N-Layered Web Applications with ASP.NET 3.5 Part 3: Advanced Validation Topics


NOTE: the concepts presented in this article are now considered obsolete possibly because better alternatives are available.

Update!! - I have written a new series on N-Layer design targeting ASP.NET 4.5 and Entity Framework 5. You can check out the new series here.

Update 02/03/2009: There is now a VB.NET version of the application available thanks to Sven Huijbrechts from ClearMedia bvba. Check it out at the Downloads section at the end of this article

Note: this is part three in a series of six. If you rather read this entire series off-line, you can buy the series as a convenient PDF document that comes with the full source. Besides the convenience, buying the PDF will also make you feel good as it shows your appreciation for the articles and helps me pay the bills for my server and hosting so I can keep running imar.spaanjaars.com and continue to provide you with great content. For more details, check out this post that shows you how you can buy the entire series right now.

This is part 3 of a six-part series of articles on N-Layer design. This article series builds on top of my three part series on N-Layer design that I released in early 2007. If you haven’t already done so, be sure to check out these articles first, as a lot of code and concepts used in this new series is explained in detail in the older series.

In this installment I'll dig deeper into the Validation Framework I introduced in part 2 and show you how to write your own validation behavior in your business entities and how to set up your application for localization so you can target users in multiple languages.

After you’ve read the previous series, be sure to check out the previous two parts as well as they describe the new application’s architecture and introduce you to the Validation Framework.

Quick Links to All Articles

Previous Series
Building Layered Web Applications with Microsoft ASP.NET 2.0 - Part 1
Building Layered Web Applications with Microsoft ASP.NET 2.0 - Part 2
Building Layered Web Applications with Microsoft ASP.NET 2.0 - Part 3
Custom Sorting with N-Layer Design Classes and the GridView

Current Series
N-Layered Web Applications with ASP.NET 3.5 Part 1: General Introduction
N-Layered Web Applications with ASP.NET 3.5 Part 2: Introducing the Validation Framework
N-Layered Web Applications with ASP.NET 3.5 Part 3: Advanced Validation Topics
N-Layered Web Applications with ASP.NET 3.5 Part 4: Sorting, Paging and Filtering
N-Layered Web Applications with ASP.NET 3.5 Part 5: Dealing with Concurrency
N-Layered Web Applications with ASP.NET 3.5 Part 6: Security

In the previous article I introduced you to the Validation Framework. You saw how to use the ValidationBase class, how to apply validation attributes to the properties of your business entities and how to write your own validation attributes.

In this article I’ll show you two more important concepts: writing your own business rules at the entity level (as opposed to the property level) and localization of the Validation Framework and validation rules so they can be used in multi-lingual web sites.

Implementing Custom Business Rules

Besides simple value validation, you are likely to have more validation needs. For example, it’s not uncommon that you have the need to validate two or more properties in relation to each other. Consider for example a Project class that has nullable StartDate and EndDate properties. You could use the NotNullOrEmpty attribute to enforce that both these dates contain at least a value. However, for a valid Project instance you need more, like making sure that the StartDate is not greater than or equal to the EndDate (naturally, a project should be started before it can be finished). So how would you go about validating this in the current Validation Framework? The answer is: override Validate().

Overriding Validate() to Implement Your Own Business Rules

Earlier you saw that the Validate() methods of the ValidationBase class are marked as virtual, like this:

public virtual bool Validate() {…}
public virtual bool Validate(bool clearBrokenRules) {…}

Virtual methods are methods that can be overridden in a child class (using the override keyword) and are an excellent way to implement behavior in a child class that differs from the base class. So in order to implement your own validation rules for related properties, all you need to do is override the Validate method in your business entity. If you do so, be sure to call base.Validate() as well as that executes the standard validation rules as you’ve seen so far. You’ll see how this works in a bit.

In the following examples I am using the aforementioned Project class that looks like this:

public class Project : ValidationBase
{
  // ... Other proprties here; omited for brevity. 
  [NotNullOrEmpty(Message = "Enter a start date.")] 
  public DateTime? StartDate { get; set; }

  [NotNullOrEmpty(Message = "Enter an end date.")] 
  public DateTime? EndDate { get; set; }
} 

Both the DateTime properties are nullable, so it’s sufficient to put a NotNullOrEmpty attribute on them to make sure they contain a non-null value. To compare the StartDate and EndDate properties in relation to each other, you could override Validate() like this:

public class Project : ValidationBase
{ 
  public override bool Validate() 
  { 
    bool baseValid = base.Validate();
    bool localValid = true; 
    if (StartDate >= EndDate) 
    { 
      BrokenRules.Add("The StartDate of this project has to 
            be smaller than the EndDate."); 
      localValid = false;
    } 
    return baseValid && localValid; 
  } 
}

Notice how this code calls base.Validate() first and stores the results in the baseValid variable. When you call base.Validate, the code that checks the individual properties is executed. The code then proceeds with some custom logic: in this case, it compares the StartDate and the EndDate. If the StartDate is greater than or equal to the EndDate, a new BrokenRule is added the project’s BrokenRules collection using a handy Add overload on the BrokenRules collection class.

At the end of the method, the combined result of the base class and child class validation is returned. This way, if either one of them fails (or both ), the method returns false and the BrokenRules collection now contains your own rules as well.

Taming the BrokenRules Collection

You may have noted that the Validate method in ValidationBase has an overload with a bool parameter that determines whether the internal BrokenRules collection is cleared or not. This is useful in scenarios where you have already added your own rules to the collection before you call base.Validate(). In the previous example you don’t need it, as the custom rules are added after the ones from the base class validation. However, if you need to reverse things, you can call the overloaded version to stop your custom rules from being cleared. Don’t forget to manually clear the BrokenRules collection first in order to remove any leftover rules from a previous call:

public override bool Validate() 
{
  BrokenRules.Clear(); 
  bool localValid = true; 
  if (StartDate >= EndDate) 
  { 
    BrokenRules.Add(@"The StartDate of this project has to 
             be smaller than the EndDate."); 
    localValid = false;
  } 
  bool baseValid = base.Validate(false);
  return baseValid && localValid; 
} 

Typically, you don’t need this, and you should use the parameterless version from the first example. However, knowing how to use this overloaded version can be useful, especially when you’re fixing up some behavior or data in the Validate method yourself before you want the base class to do its work.

Validate(): A Method or a Property?

Initially, the Validate() method was called IsValid in AzamSharp’s version. During a few pair programming sessions with my colleagues at Design IT to let them provide feedback on my implementation of the Validation Framework I noticed they initially tried to use IsValid without parentheses. It turned out that — based on the method’s name — they thought it was a property, rather than a method. I very much agreed with that reasoning and thought about a fix: renaming it to Validate() or making it a property instead? We really had some discussions about it before we came to our final conclusion.

From an API point of view, a property called IsValid would have been the easiest to read. This is the way that the Page class and various Validation Controls in ASP.NET implement it. However, in order for that IsValid property to get a value, you need to call Validate first.

Since the Validate method does so much work, and, more importantly, changes the inner state of the business entity, just a property called IsValid wouldn’t have cut it either. So, that brought me down to two choices: a void Validate method and an IsValid property that is set by Validate, or just a Validate method.

To minimize the code you need to write, I decided to implement just the single Validate method. However, if you feel it’s more natural to have an IsValid property as well, you can easily fix that in the ValidationBase class yourself.

So far the validation examples you have seen contained hard coded validation message detailing the reason why validation failed. For English only applications, this is not a real issue. However, many of today's web sites need to be multi-lingual, so you'll need a way to easily present this data in different languages, without writing many versions of the applications. You'll see how the Validation Framework implements this localization behavior in the next section.

Localization of Validation Messages

The ability to localize error and validation messages is a key concept of the Validation Framework. You certainly don’t want to hard code validation messages in English (or your own “default” language) into your properties directly. This makes it near impossible to use your business entities in multi-lingual web sites. ASP.NET already comes with great tools to localize the UI of web sites and string resources so it makes sense to hook into that existing framework.

To implement localization in the Validation Framework, you need to do the following:

  1. Set the Key property of the ValidationAttribute rather than the Message property.
  2. Override GetValidationMessage of ValidationBase in a child class to get a localized messaged based on the Key property of the ValidationAttribute.
  3. Define Localization files for the supported languages and create the required keys and translations.

I’ll discuss each of these in the following sections:

1. Set the Key property of the ValidationAttribute

Rather than setting the Message property of each validation attribute as you’ve seen so far, you now need to set the Key attribute (notice that Message and Key are mutually exclusive; you’ll get a run-time exception when you try to set both).

[NotNullOrEmpty(Key = "EmailNotEmpty")] 
[ValidEmail(Key = "EmailNotValid")] 
public string Email { get; set; }

The keys used in this example refer to localization keys in resource files defined in the project, as you’ll see later.

2. Override GetValidationMessage of ValidationBase in a child class.

The default behavior of this method is to return the key as is:

protected virtual string GetValidationMessage(string key) 
{ 
  return key; 
}

This means that by design, you’ll end up with the key as a validation message if you don’t implement your own translation services.

So, in order for the GetValidationMessage to return something useful (the localized version of the validation message associated with the key), you should override this method in a class that inherits from ValidationBase and then return the localized version - by accessing a ResourceManager for example. Because you don’t want to write this behavior in each of your business entities over and over again, it’s best to introduce an intermediate class that sits between the ValidationBase and your custom business entity. In the Contact Manager Application that comes with this article, this class is called BusinessBase. In Figure 21 you see the relation between the base classes and the ContactPerson class:

The Inheritance Hierarchy of the ContactPerson Class
Figure 21 – The Inheritance Hierarchy of the ContactPerson Class

The GetValidationMessage method in the BusinessBase class overrides its parent version from ValidationBase. This in turn means that if you call Validate in ContactPerson, GetValidationMessage is called in BusinessBase to convert a key associated with a validation attribute in a localized version of the validation message. By using the standard localization features of .NET to get a localized description for a key, all you need is the following code:

public abstract class BusinessBase : ValidationBase
{ 
  protected override string GetValidationMessage(string key)
  { 
    return General.ResourceManager.GetString(key);
  } 
}

In this code snippet, the General class is a standard Resource file and is used to get the language and culture neutral translations (English in my case) and the localized versions of the validation messages. The ASP.NET Framework will figure out from what resource file it should get the messages, based on the current language. You’ll see how the language is set later in this article.

3. Define Localization Files

The final part of the localization equation deals with the resource files. For the Contact Manager Application I added two files to the Localization folder of the Business Entities project, called General.resx and General.nl-NL.resx, visible in Figure 22

Resx Files that Contain Localized Text Stored in the Localization Folder
Figure 22 – Resx Files that Contain Localized Text Stored in the Localization Folder

These files contain the fall back validation messages (General.resx) and language and culture specific versions of them (General.nl-NL.resx with all validation messages translated in Dutch).

The resource files contain simple key-value pairs that relate validation keys to validation messages. Figure 23 shows the English version:

The Language and Culture Neutral Resources
Figure 23 – The Language and Culture Neutral Resources

You can see the same keys but with Dutch validation messages in Figure 24:

The Dutch Translations of the Resources
Figure 24 – The Dutch Translations of the Resources

As soon as you add these Resource files to your project (using Project | Add New Item | Resources File), you get a strongly typed class named after the resource file that provides access to the keys. You can then access this class in the GetValidationMessage method and retrieve the necessary validation messages.

With the localized versions of the validation messages in the Business Entities project, you’re pretty much done. When a message needs to be displayed in a supported language, it’s retrieved from its associated resx file automatically. To let the web application automatically pick up the browser’s language preference to get the validation messages in the correct language, set the following element under <system.web> in web.config:

<globalization uiCulture="auto" />      

However, if the user requests a language that’s not supported, the system will fall back to the culture and language neutral texts defined in the General.resx file.

References

For more information on localization, take a look at the following articles:

  1. How to: Set the Culture and UI Culture for ASP.NET Web Page Globalization
  2. Creating a Data Driven ASP.NET Localization Resource Provider and Editor
  3. Introduction to Localization in ASP.NET 2.0
  4. dasBlonde – Globalization
  5. Localization practices for .NET 2.0: It's still about the architecture

You may not like it from an OO, design and maintenance point of view that the BusinessEntities project is responsible for maintaining the translated messages. In my sample application, I don’t really mind. The business entities are quite simple and closely related to the UI and other layers. Therefore, it isn’t that bad that translation keys are kept in the same project as the business entities. However, in more extensive applications, this may not always be the case. Fortunately, it’s easy to group all translation messages in resource files in the UI and then pass a ResourceManager into the BusinessBase class so it knows where to get the messages from. The following list gives you an overview on how to implement this in an ASP.NET web site:

  1. Create global resources in your web application. In a Web Site Project you do this by adding Resource files (with a .resx extension) to the App_GlobalResources folder. With a Web Application Project you can put the .resx anywhere you like, although you’re advised to standardize on logical folder names and thus store them in a folder like /Resoures.
     
  2. Give the BusinessBase class in the BusinessEntities namespace a static property of type ResourceManager from the System.Resources namespace. This is the underlying type of resource managers in .NET applications. The property could look like this:
    public abstract class BusinessBase : ValidationBase
    {
      …
      public static ResourceManager ResourceManager { get; set; }
      … 
    }
  1. In your web application, assign the web scoped resource manager to the static property in the BusinessEntities namespace. A good location to do this is in Global.asax, for example in the Application_AuthenticateRequest. You could use code like this:
    protected void Application_AuthenticateRequest(object sender, EventArgs e) 
    {
      Spaanjaars.ContactManager.BusinessEntities.
         BusinessBase.ResourceManager = 
                Resources.WebResources.ResourceManager;
    } 
    
  2. Finally, in the GetValidationMessage method in the BusinessBase class, you can access the newly created resource manager. If you want, you can fall back on existing keys in the BusinessEntities project in case they’re not defined in the web application’s resource manager. The following code shows how to try and retrieve a key from the passed resource manager, and fall back to the existing resources in case the first attempt fails:
    protected override string GetValidationMessage(string key) 
    { 
      string tempValue = string.Empty;
      if (ResourceManager != null)
      {
        tempValue = ResourceManager.GetString(key);
      }
      
      if (string.IsNullOrEmpty(tempValue))
      {
        tempValue = General.ResourceManager.GetString(key);
      }
      return tempValue;
    }

    With this setup, you can centralize your resource files in the UI. For fallback scenarios, the Business Layer still provides default messages for all localizable keys.

Validation in the Contact Manager Application

I implemented pretty much all the concepts I explained in this article. To quickly find the implementation in the Contact Manager Application, here’s a quick list of what is implemented where:

  1. All business entities in the Spaanjaars.ContactManager.BusinessEntities namespace inherit from BusinessBase which in turn inherits from the ValidationBase class.
     
  2. All business entities in the Spaanjaars.ContactManager.BusinessEntities namespace have validation attributes applied to relevant properties.
     
  3. The validation attributes all use the Key property to refer to a validation text defined in a Resource file. For example, the Email property of the EmailAddress class looks like this:
    [NotNullOrEmpty(Key = "EmailNotEmpty")] 
    [ValidEmail(Key = "EmailNotValid")] 
    public string Email { get; set; } 
    
  4. The ContactPerson class overrides the Validate method of the ValidationBase class so it only returns true when the instance is valid and all of its collections are valid as well.
     
  5. The collections, like AddressCollection all inherit from BusinessCollectionBase<T>. This gives these collections validation behavior as well. The validity of a collection is currently determined by looking at each individual instance in the collection. If one is not valid, the entire collection is considered invalid. Note that you’re not limited to checking individual instances. The Validate method from the ValidationCollectionBase class is virtual, so you can override it in a class like AddressCollection to ensure, say, the AddressCollection contains at least one address, or at the most one Home address if that’s what your application requires.
     
  6. The *Manager classes in the Spaanjaars.ContactManager.Bll throw an InvalidSaveOperationException (a custom class defined in the Spaanjaars.Validation namespace) when you try to save an invalid BusinessBase instance.
     
  7. The pages in the Web Application call Validate on a business entity before an attempt is made to save them in the database. In case validation fails, the list of errors (translated by the GetValidationMessage method) is displayed using the ErrorList.ascx User Control (located in the Controls folder). This user control has a BrokenRules property that you can set to the collection of broken rules for a BusinessBase instance. The following code snippet shows a simplified version of SaveContactPerson (the final version also takes concurrency, discussed in part 5, into account):
    if (myContactPerson.Validate())
    {
      ContactPersonManager.Save(myContactPerson);
      EndEditing();
    }
    else
    {
      ErrorList1.BrokenRules = myContactPerson.BrokenRules;
    }
  8. Code in the code behind of Default.aspx executes when an address is about to be inserted. Inside the Inserting event handler, an instance of the Address is retrieved and validated. When the instance is invalid, a bulleted list (using the same ErrorList control) with validation messages is shown. I have only implemented this for the Address class, but it’s easy to write the same behavior for the other contact entities as well.

Summary

As you have seen, validation is quite a broad topic, with many different factors to keep in mind.

Over the past two articles, you learned about the following important topics:

  1. How to inherit from the ValidationBase class and use its Validate method.
  2. How to use Validation attributes and how to write your own for validation purposes currently not covered by the Validation Framework.
  3. How to localize your validation messages in order to display them in a multi-lingual web site.
  4. How to centralize the display of the broken rules using a separate User Control.

Note that you’re not limited to the implementation you’ve seen here. It’s likely you’ll need to write additional validation attributes (attributes like MinimumValue, MaximumValue, RegularExpression, ZipCode and so on come to mind) to support all your business logic. Did you write your own validation attribute based on this article? Drop me a line and if the attribute looks useful and reusable, I’ll add it to the Validation Framework and these articles.

In the next part in this article series, I’ll take a look at advanced data concepts: Sorting, Paging and Filtering. Stay tuned.

Downloads


Where to Next?

Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .


Consider making a donation
Please consider making a donation using PayPal. Your donation helps me to pay the bills so I can keep running Imar.Spaanjaars.Com, providing fresh content as often as possible.



Feedback by Other Visitors of Imar.Spaanjaars.Com

On Sunday, January 04, 2009 11:15:10 PM Tom said:
Hi Imar,

Once again, nice article!

In the Validate method override above, you first call base.Validate(), then do the start and end date stuff and then return the combined result. Is it really necessary to continue doing the start and end date stuff if the base.Validate() fails?

Cheers
On Monday, January 05, 2009 3:39:57 AM Nandan said:
Hi Imar,

Good stuff here!

Some observations -- I'd like to get your comments:

(1) It would be preferable to return error codes (enums) for failed validation instead of/in addition to error messages. This way the BLL's client (Presentation Layer UI in this case) can decide the actual message to display.

(2) In your diagram of the n-layer architecture the business entities "flow" between the different layers. Yet, the  BLL validation is happening in the business entities rather than the BLL itself. Moreover, with validation such as checking that start_date is before end_date etc. in the business entity class it's no longer really a "dumb" class.

(3) Validation of *data* in business entities and the resultant error messages are only a part of an overall error reporting structure. How about "process oriented" validation and errors (e.g. payment authorization from a payment processor) which are initiated from the BLL and have nothing to do with the database?  Would the BLL classes also need a similar framework?

Thanks!
On Monday, January 05, 2009 8:08:05 AM Imar Spaanjaars said:
Hi Tom,

It depends. If all you need to know is whether validation fails, then yes, you could exit the method as soon as base.Validate() returns false.

However, if you want to present a complete list of validation errors in the UI including the custom ones, you need to complete the custom validation as well.

Cheers,

Imar
On Monday, January 05, 2009 8:19:03 AM Imar Spaanjaars said:
Hi Nandan,

1) Yeah, good idea.

2) Yep, true.

3) Yes, sounds like a good idea. Depends on the actual implementation though.

Cheers,

Imar
On Monday, January 05, 2009 12:56:54 PM Santosh Gautam said:
Hi.
I feel very happy after read this article thank u sir for posting such useful article.

I want one thing from you which Design pattern you  used in your given sample project.

   OR Which Project Design  Pattern is best if i used  your approach.
On Monday, January 05, 2009 5:34:32 PM Imar Spaanjaars said:
Hi Santosh,

My design does not use / is not based on a single design pattern.

Imar
On Wednesday, January 07, 2009 5:23:27 AM Santosh Gautam said:
Thank Sir for your reply.
     I learn your parte3( Validation part ) yesterday it is amazing because custom  validation support the localization .
i am waiting for next post.

I have an question how can i perform following validation

(1) Duplicate Validation

    I have CityMaster i want to validate whether the city is already exist or  not when user entered his record.
  
2) composite validation

if user is married then fetch the DOB .

how can i validate above given two validation .
On Wednesday, January 07, 2009 7:35:25 AM Imar Spaanjaars said:
Hi Santosh,

1) Yes, you can do that. Either when you save the object and then throw an exception, or when you call the Validate method. The latter solution causes a bit more overhead though.

2) Isn't that what's being done in the override of Validate?

Imar
On Wednesday, January 07, 2009 9:55:51 AM Santosh Gautam said:
Hi,
sorry for my above second point.

i am writing my actual Scenario below :

=> I have two property in my customer object first one is "ISMinor"(Boolean) and second is "DOB".

i would required following validation .

If ISMinor property is true then DOB property is mandatory .

how can i achieve this composite property validation ?
On Wednesday, January 07, 2009 10:47:36 AM Imar Spaanjaars said:
Hi Santosh,

Again, isn't that what's being done in the override of Validate?

E.g.:

if (IsMinor && Dob == DateTime.MinValue)
    {
      BrokenRules.Add("Must enter Dob.");
      localValid = false;
    }

Imar
On Wednesday, January 07, 2009 11:33:09 AM Santosh Gautam said:
Thanks !


---Santosh Gautam
On Wednesday, January 07, 2009 10:00:23 PM Shuaib said:
Imar,
Thanks for the amazing articles. Looking forward to next ones.
Would be making any changes to the design based on Nandan points? Just wonding.

Thanks
On Wednesday, January 07, 2009 10:07:52 PM Imar Spaanjaars said:
Hi Shuaib,

No, no plans to change anything in the current articles and source. However, he/she brought up some valid points, so be sure to consider them if you build anything based on this design.

Cheers,

Imar
On Thursday, January 08, 2009 12:52:25 AM Shuaib said:
Thanks Imar... I have alredy started building an application based on your desing.
Do you have any post for exception handling or know a good post which you can recommand for exception handling?

Thanks
Shuaib
On Thursday, January 08, 2009 7:59:49 AM Imar Spaanjaars said:
Hi Shuaib,

Sorry, no direct links. However, searching the web for

.NET excepton handling best practices

brings up many useful results.

Cheers,

Imar
On Tuesday, January 13, 2009 8:25:30 PM Murat said:
Hi,

I am the big fan of these articles. I builded a real time e-commerce based on your design and it works great.

I have a question about the validation framework. Checking properties with attribute is the right thing to do(at least just talk about IsNullOrEmpty validation)? I mean if you want to insert a new object, of course the email property cannot be null or empty. But what if you need to update the table(may be last login column) and you don't have the email address, You need to get that emaill adres from the database first i think. And this is a unnecessary round trip to database. This can be happen, assume that you need to update  the last login time of the user. The only necessary sections are The customerID and the Datetime.Now. Why do i need to give the emailladdress(or some properties that can not be null or empty).

I modified your first design (Articles about .NET 2.0) and put a decision mechanisim whether the the column will be update or not(pass the null value if the property default, and on the database side it checks will it be update with the IsNull function) But with your new validation mechanism it is kind a problem. What do you say?

I really appriciate your articles and they rock. Keep it coming...
On Tuesday, January 13, 2009 9:50:24 PM Imar Spaanjaars said:
Hi Murat,

I see a few ways:

1. Simply do get the data from the database and do a full update. I often prefer that, as I can enfocre my logic (e.g. update other relevant data, like LastModified for example).

2. Create a separate table and object, called UserLog. This way, the data is stored separately from the user.

3. Create a log method on the User class that accepts a user name and a datetime and updates the data.

4. Lower restrictions on Update. If you can tell for sure the data in the database is OK, you can be more relaxed on updating the data. However, then you'll need to call separate SQL statements or stored procedures to do a partial update.

5. Execute the update statement from a SqlDataSource in the markup or code behind of the page.

Cheers,

Imar

P.S. Just kidding with item 5.....
On Wednesday, January 14, 2009 2:17:42 AM Jeff said:
You're doing string comparisons in the public int Compare(ContactPerson x, ContactPerson y) function in the ContactPersonManager.cs file. I was wanting to add a contact person photo to my contact person object and I was wondering how I would compare the two photos in the compare function?
On Wednesday, January 14, 2009 7:17:34 AM Imar Spaanjaars said:
Hi Jeff,

Pictures are difficult to compare. You either need to use complex image recognition software for "looks like comparisons" or you can simply get an image hash of the picture and compare the hash. In the latter case, changing a single pixel marks the image as changed.

You can do it like this:

public static string GetImageHash(string fileNameIn)
{
  Bitmap myBitmap = null;
  try
  {
    myBitmap = new Bitmap(fileNameIn);
    MemoryStream stream = new MemoryStream();
    myBitmap.Save(stream, ImageFormat.Bmp);
    byte[] bytes = stream.ToArray();
    byte[] HashVal = (new MD5CryptoServiceProvider()).ComputeHash(bytes);
    return Convert.ToBase64String(HashVal);
  }
  catch (OutOfMemoryException)
  {
    throw new ArgumentException("Path does not contain a valid image");
  }
  catch (ArgumentException)
  {
    throw new ArgumentException("This is not a valid path");
  }
  catch (FileNotFoundException)
  {
    throw new ArgumentException("File not found");
  }
  catch (Exception)
  {
    throw;
  }
  finally
  {
    if (myBitmap != null)
    {
      myBitmap.Dispose();
    }
  }
}

This gets the hash of an image based on its path, but it's easy to change it to get it based on an Image instance.

Hope this helps,

Imar
On Friday, January 16, 2009 2:40:47 PM Wouter Neuteboom said:
He Imar,

Is it possible, when im on Default.aspx, and i have an try and catch, that i do BrokenRules.Add(ex.Message);

Groetjes
On Friday, January 16, 2009 9:48:01 PM Imar Spaanjaars said:
Hi Wouter,

Yes, it is. Make sure your object inheriting ValidationBase is in scope (you may need to get a reference to it first) and then you can add messages in a catch clause.

Afterwards, you need to bind the BrokenRules collection to a UI control like a Repeater.

Cheers,

Imar
On Monday, January 19, 2009 1:28:25 PM Santosh Gautam said:

Hi Sir,
  
I am big fan of your articles. i am waiting to next article.
now i am going to used your approach in my  project but i am in afix how to handle the concurrency . after a lot of search on internet
i decided to use to the following approach please sir just go through that

Kindly check the following written code and  suggest me if you have any other better approach to handle the concurreny and also nay drawback of below code.

I am using the Timestamp column in my table to handle the concurrency in SQLSERVER.



ALTER PROCEDURE CustomerUpdate
    
    @CustId nvarchar(32),
    @FirstName  (64),
    @timestamp  Timestamp

AS
  BEGIN

       UPDATE Customer
         SET    FirstName   =@FirstName
        WHERE CustomerID=@CustId and timestamp =@timestamp

         IF @@ROWCOUNT=0
            BEGIN
                   RAISERROR(' Concurrent Error Occured ')
            END

END

On Monday, January 19, 2009 1:36:23 PM Imar Spaanjaars said:
Hi Santosh,

Concurrency is dealt with in part 5. You can wait for it to appear in the beginning of February, or buy the entire article series now:
http://imar.spaanjaars.com/QuickDocId.aspx?quickdoc=482

Cheers,

Imar
On Tuesday, January 20, 2009 9:52:15 AM John Mathew said:
Hi Imar ,


I saw this article last week and i found quite useful. But  one thing came in my mind how can i handle the following situation.

I have Contact table with createUserId column, createUserId column contain foreign key of  UserMaster Table
Now I want to the show contact record in gridview but instead of showing foreign key of createUserId column I want show actual person name (name from UserMaster table) who created this record.


For the above problem should I use Dataset or it can be implemented using object.
  
OR any other way to avoid the above problem.


    
On Tuesday, January 20, 2009 11:53:08 AM Jeff said:
Imar,
I'm also wanting to capture the username of the logged in user who makes the change to a contact person. Is there an easy way to retrieve the user name?
On Tuesday, January 20, 2009 8:18:19 PM Imar Spaanjaars said:
Hi John,

This is easy to do. A couple of ways I can think of:

1. Create a UserName property in the ContactPerson and load it with a JOIN query in the GetItem and GetList methods. On insert / update, update the relvant item in the related table (if it's not read-only)

2. Create a UserName class and add that as a property. From here, things could be more or less the same as in the first scenario.

Hope this helps,

Imar
On Tuesday, January 20, 2009 8:21:37 PM Imar Spaanjaars said:
Hi Jeff,

Try this:

string userName = User.Identity.Name;

You can check whether someone is logged in by checking:

bool isLoggedIn = User.Identity.IsAuthenticated;

Alternatively, when using the ASP.NET membership services, this should work as well:

bool isLoggedIn = Membership.GetUser() != null;

The MembershipUser also exposes a UserName property that you can read.

Hope this helps,

Imar
On Tuesday, January 20, 2009 8:31:29 PM Jeff said:
Imar,
Thanks a million! This helps alot.

Do I have to include anything special in the using section if I use either of these methods?
On Tuesday, January 20, 2009 8:37:36 PM Imar Spaanjaars said:
Why don't you try it out? Type the code, and if it doesn't work, open the Smart Task for the error (or press Shift+Alt+F10 when you see the small underline appear) and choose the correct using item.... ;-)

Then you'll find out you need System.Web.Security......

Cheers,

Imar
On Wednesday, January 21, 2009 5:57:09 AM John Mathew said:
Thanks Imar for you quick response.

It means we have to create additional property for each attribute that we fetch from reference table. These properties would be an overhead during insert because CreateUserID field would be inserted in ContactPerson table.

If we are to expose our get methods in web services then both CreateUserId and CreateUserName properties would be returned but we want to return only the CreateUser Name property.

Can we design a seperate DataTransferObject class that would have each foreign table column as a property and would not have Id columns.

These dataTransferObject collection can be used to bind grids and to respond web methods.

What is your opinion about handling reference columns for an object by introducing DTO objects.

Thanks & Regards,

John Mathew



On Thursday, January 22, 2009 12:10:38 PM Imar Spaanjaars said:
Hi John,

If you want to expose read-only data, you can use LINQ and Anonymous Types to select and return only the required data.

If that doesn't help, I am not sure I understand what you're saying / asking.

Imar
On Thursday, January 22, 2009 12:48:23 PM John Mathew said:
Hi Imaar .

TO understand the what i am trying to say please go through this link:

i have posted my problem with code in following link.

http://forums.microsoft.com/msdn/ShowPost.aspx?postid=4313422&isthread=true&siteid=1
On Friday, January 23, 2009 11:24:47 PM Imar Spaanjaars said:
Hi John,

Imaar? Who is Imaar? My name is Imar.

Anyway, looks like you've gotten an answer on this question in the mean time. That would have been my recommendation as well: Don't store just the CountryId, but create a Country property, that in turn exposes an Id and a Name property for example.

Cheers,

Imar
On Sunday, February 22, 2009 6:14:30 PM Francois Ward said:
By the way, +10 brownie points for using the correct terminology... N-Layered instead of N-Tier (which is often used incorrectly).

Nice read, too.
On Monday, February 23, 2009 1:42:07 PM mark said:
Hi Imar,

I've really enjoyed this series of articles. As an alternative to creating custom collection classes for validation and for my business entities, I am using extension methods, which helps me cut down on the number of classes that I need to maintain. For example, here is how I am implementing validation on my collections (note: I had to alter the generic syntax so that I could post this comment):

public static class ValidationCollectionExtensions
{
        public static bool Validate[T](this Collection[T] collection) where T : ValidationBase
        {
            foreach (T item in collection)
            {
                if (!item.Validate())
                {
                    return false;
                }
            }
            return true;
        }
}

I thought I'd share this approach with your readers and perhaps get your opinion.

Thanks again!


On Monday, February 23, 2009 2:05:34 PM Imar Spaanjaars said:
Hi mark,

Sounds like a good plan to me. Do you use similar extension methods to support sorting? Sorting is one of my main reasons to have a separate collection class....

Cheers,

Imar
On Monday, February 23, 2009 3:06:14 PM Nisar Khan said:
Imar:

is there a way i can get rid of resource file? my application only use English. so i tried using like this

[NotNullOrEmpty("Enter your street name.")]
public string Street { get; set; }

i get error :

Error 1 'Spaanjaars.Validation.NotNullOrEmptyAttribute' does not contain a constructor that takes '1' arguments

i think that's because of BusinessBase ?

would you please show me how to change and i will change rest of the properties.

thanks.
On Monday, February 23, 2009 3:07:34 PM Nisar Khan said:
Mark: would you mind uploading your solution? i'm curious to know more about your implementation - thanks.
On Monday, February 23, 2009 3:25:04 PM Imar Spaanjaars said:
Hi Nisar,

Take another look at part 2. It contains the following:

"
The Key property of the attribute is used as the localization key for multi-lingual web sites. If you don’t have a localized site, you can add the validation message to the Message property instead:

[NotNullOrEmpty(Message = "Enter your first name.")]
public string FirstName { get; set; }

"

If you don't want to use a named parameter, you can create a constructor that just accepts the Message in each of the Validation attributes.

Cheers,

Imar
On Monday, February 23, 2009 3:53:46 PM Nisar Khan said:
Imar:

thanks for reply, i have another question :)

i don't know if you have already covered this question and if you do please point me and i'm sorry for that:

my question is:

i want to make sure user have entered text in:
Street
ZipCode
City
Country

how can i make optional for:
HouseNumber ?

thanks.
On Monday, February 23, 2009 3:56:47 PM Imar Spaanjaars said:
Hi Nisar,

Simply don't use an attribute.

Please take another look at part 2; most of this is all in there.

Imar
On Monday, February 23, 2009 4:41:07 PM Mark said:
Yes, I was also planning to use extension methods for sorting/paging of Business Entity collections.
On Monday, February 23, 2009 5:11:05 PM Mark said:
Nisar,

The code that was in my original post was my implementation. I'm using extension methods to add the Validate function to any Collection of objects that subclass ValidationBase objects. I also plan on using the same technique to implement sorting/paging in my business entity collections.

Mark
On Monday, February 23, 2009 6:59:19 PM Nisar Khan said:
Imar: thanks for quick response appreciate your help.
and i did read your part 2.

is there a way i can display errors in pop-up window?

thanks again.

On Monday, February 23, 2009 7:41:18 PM Imar Spaanjaars said:
Hi Nisar,

You can have the ValidationSummary trigger a client side alert box. Alternatively, look into client frameworks like jQuery to build a pop up.

Cheers,

Imar
On Monday, February 23, 2009 8:24:23 PM Nisar Khan said:
Imar:

I apologize for asking too many questions  but i'm striving for the best and this is first time dealing with attributes, so please bare with me :)

okay my question is: i have added a new class (Visit.cs) just to feel of it and in that class i have four prop Name,Purpose,Startdate,Enddate

problem is:  even thou i have filled all four textbox but still get four errors

here is my code

Add a new BusinessEntity Class called "Visit"

//business entity class (Visit.cs)


    public class Visit   BusinessBase
    {
       public Visit()
        {
           // Type = ContactType.None;
        }
      
        [DataObjectFieldAttribute(true, true, false)]
        public int VisitInfoId { get; set; }

        [NotNullOrEmpty(Message = "Enter visit name.")]
        public string Name { get; set; }

        [NotNullOrEmpty(Message = "Enter visit purpose")]
        public string Purpose { get; set; }

        [NotNullOrEmpty(Message = "Enter visit start date")]
        public string StartDate { get; set; }

        [NotNullOrEmpty(Message = "Enter visit end date")]
        public string EndDate { get; set; }
    }

//on Visit.aspx

i have four textbox

//Visit.aspx.cs

public partial class Visit : System.Web.UI.Page
{
    protected void Button1_Click(object sender, EventArgs e)
    {
        if (Page.IsValid)
        {
            BusinessEntities.Visit vv = new BusinessEntities.Visit();
            if (vv.Validate())
            {
                try
                {
                    //
                }
                catch (DBConcurrencyException)
                {
                   // plcConcurrency.Visible = true;
                }
            }
            else
            {
                ErrorList1.BrokenRules = vv.BrokenRules;
            }
        }
    }
}
On Monday, February 23, 2009 10:13:13 PM Imar Spaanjaars said:
Hi Nisar,

First of all: please read things carefully. There's no need to create the same error 5 times if it tells you not to use HTML or generics syntax.

Secondly, please don't use my site as a public forum. This is not the best location to post loads of code so if you do that again I'll remove it and ask you to repost it on a public forum like http://p2p.wrox.com.

Finally, why should it be valid? Look at this:

BusinessEntities.Visit vv = new BusinessEntities.Visit();
if (vv.Validate())
{}

See what I am seeing? If not, maybe you're missing important .NET / ASP.NET basics that you need to work on first?

Imar
On Tuesday, February 24, 2009 2:00:07 AM Nisar Khan said:
dude the reason i post the code so that you can understand what i'm trying to do and if you dont feel like answering my question no problem...

and feel free to remove my posts.



On Tuesday, February 24, 2009 7:31:13 AM Imar Spaanjaars said:
Hi Nisar,

I understand why you're posting your code, and as you have found out, I typically do try to help people answer their own questions. But, as I also said, this isn't a good place to post a lot of code. As you found out, you can't post angle brackets as used in HTML and C# generics and VB attributes. You also have no color coding or formatting available. So, all I am asking you is to not post huge amounts of code here, but instead to post that on a forum like http://p2p.wrox.com. That isn't too much to ask is it?

Did you find your mistake? It's staring you in the face isn't?

Imar
On Wednesday, February 25, 2009 3:23:56 AM Shuaib said:
Hi Imar,
Thanks fore the great article again.
Question:
How can I display the BrokenRules if I am using an ObjectDataSource with a GridView?
The ObjectDataSource1_Updating event only returns  InputParameters (e.InputParameters). I can creat an instance of the Entity object and assing the values for the properties and then call the Validate() method. But I was wondering if there is an easier way?

On Wednesday, February 25, 2009 8:08:25 AM Imar Spaanjaars said:
Hi Shuaib,

You can handle the Updating event of the ODS, which does offer you the whole BO:

protected void odsAddresses_Updating(object sender,
                            ObjectDataSourceMethodEventArgs e)
{
  BusinessBase myBusinessBase = e.InputParameters[0] as BusinessBase;
  if (!myBusinessBase.Validate())
  {
    // Your code here
  }
}

Cheers,

Imar
On Wednesday, February 25, 2009 11:58:41 AM Bliek said:
In the overridden Validate method you're using BrokenRules.Add("bla bla bla etc...").
How would you localize this message?
On Wednesday, February 25, 2009 12:14:57 PM Imar Spaanjaars said:
Hi Bliek,

You can simply use the resources that are embedded in the project. The BusinessEntities project has a resource file called General. The resources inside that class can be accessed like this:

BrokenRules.Add(General.CityNotEmpty);

In this case, the resource CityNotEmpty is added....

Hope this helps,

Imar
On Thursday, February 26, 2009 1:06:29 AM Shuaib said:
You are awesome Imar!
It worked like a charm!!!
On Thursday, February 26, 2009 1:07:39 PM Richard B said:
This is fine.  Your code does look very similar to CSLA.Net framework mind.
On Wednesday, March 04, 2009 2:13:01 PM dgmassimiliano said:
Hi Imar,
I've really enjoyed this series of articles. I have a question: How is it possible validate a property of an entity with a property of another entity, Thanks
On Wednesday, March 04, 2009 5:40:12 PM Imar Spaanjaars said:
Hi dgmassimiliano,

That's not so easy if the two objects are not related to each other.

However, if one object is a property or otherwise a member of the other it's pretty easy to do as you can treat it as any other property or field.

Cheers,

Imar
On Monday, March 09, 2009 3:32:12 AM Chelonian said:
Hi Imar,

I've just stumbled into your articles today. They are going great so far :)

I built something very similar to your validation framework a couple of years ago and I remember I had to deal with a couple of things that I don't see solved in your framework.

One is already asked by dgmassimiliano. How do you handle domain validations with your framework? Did you built a separate mechanism to do this or you didn't take it into consideration for this series of articles?

And second, How do you handle validation on collection properties of an entity? For instance, suppose you have a Person Entity which has many Addresses, when you call .Validate for Person, will your framework validate all the addresses as well, you have to do that separatelly?

Bear in mind that I read only 'till this article so far and didn't have a chance to take a look at the source code yet, so if my questions sound too stupid or are already answered in any other article, my apologies :)

Chelonian
On Monday, March 09, 2009 7:35:21 AM Imar Spaanjaars said:
Hi Chelonian,

You may indeed want to keep reading and look at the source, as some of this is answered by the articles and code ;-)

Re 1): The *Manager classes can handle this. A top level class like a ContactPersonManager can easily look over multiple objects and apply any kind of validation rules. It's currently not implemented in the demo application.

Re 2): Each collection inherits ValidationCollectionBase which has a Validate method that validates all the internal ValidationBase instances. The Validate method is virtual so you can override it if you need to.

With regards to your solution, how did you solve these things? Are your ideas available on-line somewhere, as an article or source maybe?

Imar
On Saturday, March 28, 2009 5:59:24 PM kurt schroeder said:
I presented this material to a dot.net user group Thursday evening. I was a bit too much to present in one sitting, but i think all were impressed with the possibilities. I have a code generator based on the first artical series and will make it available when i get a login set up for it just to track users and prevent abuse.

On Sunday, March 29, 2009 11:19:32 PM luisa said:
hy imar, wow this lesson was a little difficult for me, i need you help again!
i 've create a custom attribute for validating numeric field dispayorder:
AttributeUsage(AttributeTargets.[Property]) _
    Public NotInheritable Class IsNumericAttribute
        Inherits ValidationAttribute
Public Overloads Overrides Function IsValid(ByVal item As Object) As Boolean
            Dim isanumber As Boolean = False
            If TypeOf item Is Integer Then
                Dim numeric As Integer
                isanumber = Integer.TryParse(item, numeric)
            End If
            Return isanumber
        End Function
i've added this line in my chapter (businessEntity) class to the propriety:
..IsNumeric(Message:="DisplayOrder must be numeric") _
        Public Property DisplayOrder() As Integer ...
This validation doesn't work: is it wrong or i have to do something else???
exuse me but i didn' understand this lesson very well ...
thank you in advance
luisa
On Monday, March 30, 2009 5:12:03 PM Imar Spaanjaars said:
Hi luisa,

You don't need an integer check; the property is already an integer, so you'll never be able to assign something else....

In this case, all you need is front end validation (e.g. a CompareValidator for example) to enforce integers....

Cheers,

Imar
On Tuesday, April 07, 2009 6:00:29 PM Eric said:
Sweet articles...

My question goes along with Shuaib's. When I create an Updating event on my ObjectDataSource, I don't get an InputParameter of my business object. My InputParameter collection has 20 items in it (one for each field).

Could this be because I'm using TemplateFields?

Any suggestions? Thanks!
On Tuesday, April 07, 2009 7:29:04 PM luisa said:
Hi Imar, thank you for your feedback

On Thursday, April 09, 2009 7:05:05 AM Imar Spaanjaars said:
Hi Eric,

It shouldn't be like that. As you can see in the examples above using odsAddresses_Updating, I do get access to the entity. Inside a data control, like the GridView, you do have single values for all your entity's values, but once it hits the ODS it should be an entity, not separate values. Also, in my example I am using template fields as well, so that shouldn't matter.

Do you have a different setup? Using different controls maybe?

Imar
On Wednesday, April 22, 2009 4:20:42 PM Eric said:
Figured it out. I didn't have the DataObjectTypeName property set on the ObjectDataSource. Again, excellent articles.

From MSDN: DataObjectTypeName gets or sets the name of a class that the ObjectDataSource control uses for a parameter in an update, insert, or delete data operation, instead of passing individual values from the data-bound control.
On Friday, May 01, 2009 7:18:11 PM AlwaysLearning said:
Wow, dude you rock!! Thanks so much for sharing your knowledge.

I have always implemented this, as someone previously mentioned, using virtual validation classes that must be overridden. Never, occurred to me to use your attribute method. I like the idea that if you wanted client side validation I could use reflection to read the validation attributes and autogen javascript to do client side validation.
On Friday, May 01, 2009 7:44:12 PM Imar Spaanjaars said:
Hi AlwaysLearning,

You're welcome; glad you like it so much. And yes, reflection can be put to good use here, although you should be careful with performance. You could reflect on some types and store the JavaScript on disk or in the cache to avoid doing it over and over again...

Imar
On Tuesday, November 03, 2009 11:18:34 PM krainov said:
Hi Imar!
Is it possible to use the:

BusinessBase myBusinessBase = e.InputParameters[0] as BusinessBase;
            if (!myBusinessBase.Validate())
            {
                e.Cancel = true;
                ErrorList1.BrokenRules = myBusinessBase.BrokenRules;
            }

without the DataObjectTypeName in DataObject properties??? It won't work (myBusinessBase ) if I not specified it.
On Wednesday, November 04, 2009 8:11:27 AM Imar Spaanjaars said:
Hi krainov,

I am not sure what you're asking, or what the problem is.

The DataObjectTypeName atribute is just a design time helper helping the ObjectDataSource wizard find the right objects as design time... You should be able to leave them out (although I don't understand why you would want to do that).

Imar
On Thursday, November 05, 2009 1:49:14 PM krainov said:
Hi Imar!
I'll try to explain the issue that I have faced with.
In my old business rules I had an update method looks like that: UpdateRecord(int id, string title, string description). But my record have also "addedBy" (Guid) and addedDate (DateTime) properties. Your method, where we use the Update(Record record) trying to update these addedBy & addedDate properties... but I don't need that... Also I got exception that says: addedDate cannot be converted from string to DateTime right after I click the Update Button in the DeatilsView. So I want these records not to be updated. How to set the ObjectDataSource not to update some of the properties in the class that I have exposed in the DataObjectTypeName?
On Saturday, November 07, 2009 7:59:08 AM Imar Spaanjaars said:
Hi krainov,

Please ignore parts of my previous message. I thought you were referring to the DataObjectAttribute rather than then DataObjectTypeName.

Anyway, the ODS will always give you the entire object. You could choose to not serialize some properties (as keys, or as columns) but then they'll loose their values. That's the reason why in the code behind of a details page I am getting the entire object and only update the properties I want to update.
You could so that too, or you could write code in the UpdateItem method of your business object and only update what you want.

Hope this helps,

Imar
On Wednesday, November 11, 2009 2:06:43 PM Marcel said:
Hi Imar!

Thanks for sharing your knowledge.

About the "Validate(): A Method or a Property?"-part. In my WinForm application I use an IsValid property.

I think this is handy when, for example, I want to disable my save button, if the business object is not valid. I just databind the buttons IsEnabled property to the IsValid property. And because all my business objects implements the INotifyPropertyChanged interface, the save button wil become enabled when IsValid returns true.

Also, at this moment I am trying to combine the IDataErrorInfo interface with your validation-framework :)

Thanks and Keep up the good work!
Marcel
On Wednesday, November 11, 2009 6:07:34 PM Imar Spaanjaars said:
Hi Marcel,

Would love to hear more from you when you have implemented IDataErrorInfo. I have looked into that briefly some time ago as it looks like an interesting option, but I haven't written any production-ready code yet.

Cheers,

Imar
On Tuesday, January 26, 2010 8:08:08 PM Kurt Schroeder said:
Have you integrated unit testing into the this framework? I'm doing some light experiments on it now and was just wondering if and howe you did this.

Once again, thank you! This series has started be on the road to new possibilities. Depending on the project I use this or NHibernate. Were it not for this series it would have taken me much longer to learn NH as well as many other frameworks! Thanks!

KES
On Tuesday, January 26, 2010 8:13:29 PM Imar Spaanjaars said:
Hi Kurt,

Yes, I have, but not too much. The full article comes with the Unit Tests code:

http://imar.spaanjaars.com/QuickDocId.aspx?quickdoc=482

Cheers,

Imar
On Tuesday, January 26, 2010 10:38:28 PM Kurt Schroeder said:
Ok, was not paying attention. I've been a little disappointed with MS UTF. I started to use NUnit and am finding it fairly easy to create an inheritance chain for all the base classes while using the attribute validation as you are using in your project.

Again Thanks.
KES
On Monday, May 31, 2010 2:04:39 PM Mark said:
Hi,

I am trying validate 2 objects in the UI is there anyway of appending to uxErrorList.BrokenRules.

Tried .Add but it didnt work as expected fro me.

Its probably staring me in the face but I just cant see it.

This is a really class solution.

Thanks,

M.
On Monday, May 31, 2010 2:09:05 PM Imar Spaanjaars said:
Hi Mark,

It should work. However, "didnt work as expected fro me" is way too vague for me to see what's going on.

Imar
On Monday, May 31, 2010 2:25:13 PM Mark said:
Hi,

That was a quick reply.

I am most probably being silly here but I tried  uxErrorList.BrokenRules.Add("test", "test");

The reasoning behind this is that I want to validate an address class, then a user class, I can not use validate.base & validate.address in the user class as I need to do different things depending on the results of the validation so I have to seperate the validation calls. Then I wanted to show all the errors in uxErrorList

M.
On Monday, May 31, 2010 2:29:37 PM Imar Spaanjaars said:
Hi Mark,

It's still not making any sense at all. What is uxErrorList? Where is it defined? From where are you trying to add error messages? From which layer to whcih object?

If you want my help, you have to help me help you by asking questions that can be answered, providing relevant context and information, error messages and so on. Yours doesn't qualify as one at the moment, i am afraid.

Cheers,

Imar
On Monday, May 31, 2010 3:06:53 PM Mark said:
Hi,

Yes sorry I was trying to be succinct.

uxErrorList is the user control, in your example you called it ErrorList1 (defined in ErrorList.ascx).

I am trying to add from the UI, basically I am asking if its possible to validate 2 different objects in 2 different calls then concatenate the 2 results.

e.g.,
uxErrorList.BrokenRules = Candidate.Contact.BrokenRules;
uxErrorList.BrokenRules = Candidate.ResultAddress.BrokenRules;

Now of course the 2nd call wipes out the errors from the 1st call,
Tried
uxErrorList.BrokenRules.Add(Candidate.Contact.BrokenRules.ToString());
uxErrorList.BrokenRules.Add(Candidate.ResultAddress.BrokenRules.ToString());

I know I am missing something here!
On Monday, May 31, 2010 3:14:25 PM Imar Spaanjaars said:
For the record: I don't have mind reading skills.

Quote:
Tried
uxErrorList.BrokenRules.Add(Candidate.Contact.BrokenRules.ToString());
uxErrorList.BrokenRules.Add(Candidate.ResultAddress.BrokenRules.ToString());

Oh really? And what happened? Did you get an error? Did it format your hard drive? Did it kill your cat? Did it whipe out all existing rules? ;-)

Typically I can answer these kind of posts pretty fast as I don't have a lot of investigating to do.

But if you rather have me spend my time on opening Visual Studio, getting the project from source control, find the right user controls, finding the right calling location, add the code you are describing here myself, run it in the browser and then see the error you are getting: fine. I can do that but then you're not on the top of my Todo list anymore and you can easily wait weeks for an answer.

So: please be concise and detailed. The error or behavior is staring you in the face so why not post it here?

Imar
On Monday, May 31, 2010 3:20:47 PM Mark said:
There is no need to be rude.

Its ok I can work it out for myself I kinda thought that it made sense I was obvoulsy wrong I apologise and wont be bothering you again.

And too think i was going to purchase the pdf as well!

On Monday, May 31, 2010 3:24:01 PM Imar Spaanjaars said:
Hi Mark,

Rude? I don't see how I am being rude. I am trying to explain to you what you need to do to help me help you. I don't see how you think I can help you if you don't provide me the information I need to help you. I also don't see why that would be rude in any way.

So, I am more than happy to help you, but you have to provide me with information I can use.

Cheers,

Imar
On Thursday, September 23, 2010 5:51:40 PM Newbie said:
Hi, not sure if you are still tracking this.  I'm doing a simple test on validation, like this:

        ContactPerson cp = new ContactPerson();
        cp.FirstName = "first";
        cp.LastName = "last";
        cp.Type = PersonType.Colleague;
        cp.Addresses.Add(new Address());
        if (!cp.Validate())

The result is cp is not valid but the BrokenRules are empty.  Seems they got lost once out of the address validation.  Did I miss something?

Thanks
On Friday, September 24, 2010 7:36:52 AM Imar Spaanjaars said:
Hi there,

I don't think they get lost; I think they never end up in BrokenRules in the first place. The Collections don't support BrokenRules. Since properties of the ContactPerson are collections that do support validation, their Validate method is called (in Validate in the ContactPerson class) but their rules are never copied. A quick fix (which I haven't tested extensively yet) is this:

1. Create some extension method called AddRange based on the code from this article: http://www.ageektrapped.com/blog/the-missing-net-2-collectiont-addrange/
This is not required, but makes it easier to add ranges. Make sure you import the namespace where appropriate.

2. In ValidationCollectionBase, add the following BrokenRules property:

private BrokenRulesCollection _brokenRules = new BrokenRulesCollection();
public BrokenRulesCollection BrokenRules
{
  get { return _brokenRules; }
}

3. Change the Validate method in ValidationCollectionBase so it copies the broken rules when the item is not valid:

public virtual bool Validate()
{
  _brokenRules.Clear();
  foreach (T item in this)
  {
    if (!item.Validate())
    {
      _brokenRules.AddRange(item.BrokenRules);
      return false;
    }
  }
  return true;
}

This way, the broken rules of each instance (an Address for example) are now copied into the BrokenRules collection of the Collection class.

4. The final step is copying the items from the Collection classes into your ContactPerson's BrokenRules collection. Modify Validate as follows:

public override bool Validate()
{
  bool baseValid = base.Validate();
  bool localValid = Addresses.Validate() & EmailAddresses.Validate() & PhoneNumbers.Validate();
i  f (!localValid)
  {
    BrokenRules.AddRange(Addresses.BrokenRules);
    BrokenRules.AddRange(EmailAddresses.BrokenRules);
    BrokenRules.AddRange(PhoneNumbers.BrokenRules);
  }
  return baseValid && localValid;
}

Notice how I also changed && to & in the calls to the Validate methods of the collections to stop short circuiting and making sure Validate is called on all three collections, regardless of what earlier calls on that line returned.

When localValid is false, the items for all three collections are copied. You may want to optimize this a little. Then again, when one of the Collections is empty there's not much to copy so I guess there's not much overhead involved.

Hope this helps (and works ;-) )

Imar
On Tuesday, September 28, 2010 3:23:43 PM Newbie said:
Thanks.  That's very helpful.  It would be ideal to have the broken rules to handle the addrange without explicitly doing it in the override.  I'll give it a try.

But before any of those, is it correct to expect the validation cascade over a complex object structure?  Or that's the wrong approach to begin with?
On Wednesday, September 29, 2010 6:40:07 AM Imar Spaanjaars said:
Hi there,

It's certainly possible, but it requires just (a lot) of additional code. Additionally, you need think about presenting the errors to the user. That is, you need to find a way to show an error for a sub sub sub sub object that has a collection whose sub sub sub (3) object is invalid in such a way that the user understands how to fix it.... ;-)

Cheers,

Imar
On Thursday, August 25, 2011 2:38:27 PM Ajeet said:
Hi Imar,

It's really very helpful article on N-Layered Web Applications, also I have read comments of various article readers on this Validation framework, I am also concerned the comment posted by Santosh regarding Duplicate Data Validation against Database. And also read you reply to "throw an exception when objects going to save whether in BLL Save method or Dal Save method ".

I want show custom error message at UI Layer, without throwing a exception from BLL Save Method or Dal Save method or from Both.

Although I have solved this preventing Duplicate Data entry in UL Layer,
from calling a Method IsDuplicateData(cityName)  in DAL via BLL Layer Method IsDuplicateData(cityName) in presentation layer. after that I flush out a custom error message in UL layer.

However, I am not accessing DAL Method directly in UI layer, instead i am calling Dal method through BLL method as you have done  ContactPersonManager.Save().

I have implemented this in UL layer and I am thinking I have implemented Business Logic layer in UI Layer. Because of only I want to show Custom Error Message such "Duplicate city name!".

Is it ok or not? please tell me
On Thursday, August 25, 2011 4:17:08 PM Imar Spaanjaars said:
Sounds OK to me. Although you make the call from the UI, you still implemented the logic in the business kayer. Just be prepared for an additional error if a duplicate is created after your check.

Cheers,

Imar
On Thursday, October 06, 2011 2:53:15 AM Jeffreed said:
Hi Imar,

Firstly, just thank to your great article. My question is where you change your Culture and UICulture in your project? I also checking the lstSelectLanguage_SelectedIndexChanged event on your master page in project but you just create a cookie with the dropdownlist selected value then redirect page again. Actually, i just start with Localization and Globalization resource if what i'm asking you is not suitable please forgive and forgot :)

Thank You!
On Saturday, October 08, 2011 3:16:05 AM Imar Spaanjaars said:
Hi Jeffreed,

Just search the project for Culture and you'll see it's done in the BasePage class.

Cheers,

Imar
On Sunday, October 09, 2011 9:31:22 PM Jeffreed said:
Yes, I saw it. Thank You Imar.

Cheers!!!

Talk Back! Comment on Imar.Spaanjaars.Com

I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.

When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.

If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the QuickDocId of the document.

For more information about the Talk Back feature, check out this news item.