Caching of field values

Apr 13, 2011 at 7:50 PM
Edited Apr 13, 2011 at 8:32 PM

I could have missed this in the documentation, but can you please provide an example of validating a customer object that has two address properties and values for some fields need to be retrieved from a DB/Web Service? The caveat here is that for performance reasons I do not want to make multiple calls to the data source. I am thinking of something like the following:

public class Customer
{
      // Other customer properties like FirstName, LastName ... etc.
      public Address BillingAddress{get;set;}
      public Address MailingAddress{get;set;}
}

public class Address
{
      public string Line1{get;set;}
      public string Line2{get;set;}
      public string City {get;set;}
      public string State {get;set;}
      public stirng Country {get;set;}
}

In the documentation, you have an example that shows how to implement validation in a custom function for, lets say, the country property. In this case it would call the database twice. Now, in ASP.NET, I could put the values in HttpContext and retrieve them in each validation specification and I could probably do something similar in WCF.

I was wondering if this library had facilities for passing context specific values to validate against into the validation specification from the class that initiates the validation call. This would provide the performance benefit of only looking up the values once.

This gets even more complicated if the list of valid countries is dependent on some other property in the object hierarchy. Or some other property in the object contains a list of available countries and we need to restrict this field to those values.

I am inventing this example based on some business rules that we have while keeping this example as simple as possible.

Also, what do you think about adding a "Tag" or "ErrorCode" field to the validation result that would be interrogated in case of special error handling. eg.:

if( validationResult.ErrorCode == "E5505")
{
    //do something
}
else
{
   //do something else
}

In this way we do not need to compare or interrogate the error message field for any custom error handling. We used the "Tag" property in the Enterprise Library Validation Block in such a manner and found it quite useful. I could use the first 5 or 6 characters of the error message to represent an error code but I am hoping that there is a better way. If SpecExpress uses other constructs to represent this concept, maybe you could provide an explanation.

Coordinator
Apr 13, 2011 at 10:04 PM

NoFear,

As for caching values of lists to enforce rules such as "IsInSet" as to avoid going back to a database:  it is my opinion that implementing this in the framework would cross a line of concerns.  SpecExpress's area of concern is validation and not caching.  Perhaps the set being used for validation isn't in a database - caching it would just duplicate the same data in memory.  Then there is the concern of when should the data in the cache be refreshed?  In the case of a country list, the data is not very volitile, but perhaps in other cases the data changes so frequently that it needs to be refreshed each time.

I think that caching should be a seperate concern from validation.  Perhaps you may consider using a ORM such as NHibernate that leverages a caching layer as to not have to query the database each and every time.  Or perhaps a singleton pattern that reads the set in from the database once and only once and then leverage the singleton for validation.

As for the Tag suggestion, the MessageStore leverages a key that is used to retrieve the message from the store.  Perhaps we should include that in the ValidationResult.  We are currently building a back log for version 2.0 and will add this to the list.

Apr 16, 2011 at 2:39 PM

Thank you for considering my suggestion and adding it to your to-do list.

You are absolutely correct about the need for keeping validation separate from caching. I apologize for using the wrong term and confusing the conversation. I shouldn't have said "caching" but I couldn't come up with a better term. Lets see if I can do better.

"I was wondering if this library had facilities for passing context specific values to validate against into the validation specification from the class that initiates the validation call."

Lets say, I need to validate against user specific list of values, so each user gets their own distinct list. Based on your examples, if i was performing this validation in ASP.NET, I could keep my list of values in SESSION and I can successfully validate against this list. 

Now, if I have a win forms application, I could have a static class or something (singleton pattern - maybe) ... it would work

I am using this library in WCF, so I don't really have session but I could probably use InstanceContext or something to simulate a SESSION and use "static" functions to access this data.

But, I feel that it may not be sufficient.

What do you think of something like:

ValidationCatalog.Validate(objectToValidate, containerObjectForListOfValuesToValidateAgainst);

containerObjectForListOfValuesToValidateAgainst is an instance of a class that looks like:

public class ContainerObjectForListOfValuesToValidateAgainst
{
      public string[] AvailableZipCodes{get;set;};
      public AnotherType[] SomethingElseStuff{get;set;};
      public Country[] CountriesList{get;set;}
}

var containerObjectForListOfValuesToValidateAgainst = new ContainerObjectForListOfValuesToValidateAgainst();

containerObjectForListOfValuesToValidateAgainst.AvailableZipCodes = GetZipCodesForUser(userid);

... so on

Coordinator
Apr 16, 2011 at 10:35 PM

NoFear,

Basically, what you have in mind is to pass in an object/value into the Specification at runtime time to use for validating against? While this isn't something that we've needed, I could possibly see a use for it.

From my experience on the projects I've used SpecExpress on, when I needed to validate against a list, Country/State/Zip Code being the dominant examples, this is all data that was was in the database and the application architecture accessed through a Repository or LookupFactory. I realize I'm moving beyond SpecExpress and validation and into Architecture, but these usually had an Interface, IStateRepository or ILookupRepository and we would resolve the interface via an IOC Container. So, the actual specification would look like:

 

public class AddressSpecification : Validates<Address>
{
    public AddressSpecification()
    {	
     var stateRepository = ObjectFactory.GetInstance<IStateRepository>();
	Check(a => a.State)
            .If(a => a.Country == "US").Required()
		.And.IsAlpha()
		.And.LengthEqualTo(2);
		.And.IsInSet(stateRepository.GetStates());
    }
}

This allows you to decouple your Specification from it's dependencies to allow for easier testing, ie Mocking.  I realize there is some opinion here, and it's not my intention to project my architecture viewpoints (outside of validation/specifications) to the users of SpecExpress. But, what I'm interested in is why do you think this approach might not be sufficient? Is there something unique or different about your domain that I might not know?

Beside all that, I think there is a way to "bastardize" SpecExpress to do something like that, but you wouldn't be able to use the ValidationCatalog. You could inherit from Validates<T>, add your own constructor passing in your dependencies, call the Validate method. You would loose some functionality, but not have to make any changes to the framework. I still think using a container to resolve those dependencies is the way to go though.

Apr 26, 2011 at 12:27 AM

Since, I am not allowed to represent my employer in a public forum, I don't know how much detail I can provide. So, without divulging too much information, I am attempting to translate from our code structure/business model to generic terms in order to facilitate this conversation. It is possible that I haven't thought through all possible implementation or this product may not designed for our intended use.

You are correct about your code sample above about how it would work if the values are stored in a highly efficient data retreival system. I think this would work for 80-90% of the cases. And as rbell80134 mentioned earlier, if any caching/"temporary data holding" is needed we could use an ORM (personally, I am not really a big fan of ORMs, I think they are overhyped but they have their uses and benefits). Or use ASP.NET web cache or ASP.NET session. In the example above, an implementation of IStateRepository would retrieve values from web cache for an asp.net application or filter it if any filtering is required. Since, data lookups can be costly if a slow web service or database is involved, we want to cache data either in application context or in current execution context and then reuse it in the validation specification. In our case, I think static classes and IntanceContext may work but I just have a feeling that it won't be sufficient without any concrete proof to back it up, yet.

We are trying to incorporate this into our WCF service which is stateless. There are certain fields that depend on the type of consumer initiating the request. For example, we may need to validate input from one consumer request and restrict the list of countries to US and Canada, whereas for another we may need to restrict them to EU countries only.

In some cases the restriction might be dependent on other fields defined in the datamodel. Maybe, if you have two addresses in your data model, and one is already populated with a US address, the other one must be a non-US address or something like that (I realize this is going away from my initial topic - but I think it alludes to the need for sharing "contextual" information between the "specifications" in a heirarchy and is kinda related). I think this is possible in your implementation by Check()'ing it in a specification at a higher level than the address field's. But what if we need to perform a "configuration" lookup to get a list of allowed values, how many of each value we can have, how many addresses this client consumer is allowed to have, etc? We cannot retrieve the data on each validation check. We would ideally like to perform all lookups and then perform that validation.

I was hoping that there would be way to pass these values without involving an "execution context" or "session" but I can stick with it for now and maybe contruct a better argument in the future. BTW, this is all conjecture and I haven't implmented this yet. Things might get clearer once I implement it. Last week was my oncall week and I had a pretty significant bug-fix release - life was a little hectic.

Thank you for all your advice.