Monday, May 10, 2010

Using MEF and Autofac to discretely control Ioc Wireup

Autofac is currently my favorite IoC container with support for constructor depedency injection with things like factories with Func<T>, Func<T, params> and Lazy<T> among others. Autofac is very clean and concise with plenty of hooks throughout the lifecycle. Using Lazy<T> effectively declares that I want an instance of T that is not instantiated until I first use it. The Lazy<T> type is borrowed straight from MEF. I’m leaving a lot out here in my summary – in short it’s a great container. Whether or not it’s your container of choice, take a listen to Nikolaus Blumhardt discuss Autofac 2, MEF and other topics on “Talking Shop Down Under”. It’s a great discussion about Autofac in particular and DI in a broader sense.

But let’s take this MEF thing a little further. I should note that I am using MEF Preview 9 on .Net 3.51 from MvcContrib. This approach works the same on .Net 4.0 as well (without the need to download MEF of course).

Autofac has it’s own scanning capability that puts you closer to convention-based registration, while this approach gives you a different style of control.

Creating a Common Registrar Interface

Autofac uses the notion of a ContainerBuilder that takes our fluent configuration and roles it into a container. In that light, we’ll create a generic interface that allows us to register components via an instance of a ContainerBuilder like so:

public interface IIocRegistrar
{
/// <summary>
/// Accepts a container builder to configure with mappings
/// </summary>
/// <param name="builder">autofac container builder</param>
void RegisterComponents(ContainerBuilder builder);
}
Given this interface, we can write a concrete implementation that takes wires up our builder according to how we want things configured like so:
public class IocRegistrar : IIocRegistrar
{
#region IIocRegistrar Members

public void RegisterComponents(ContainerBuilder builder)
{
builder.RegisterType<FooModelCreator>().Named<IModelCreator>(“Foo”));
builder.RegisterType<BarModelCreator>().Named<IModelCreator>(“Bar”));
}

#endregion
}

So, that’s great, we can call that and get our container built, but what if we have components that span multiple namespaces or assemblies? Do we really want a single registrar tying all these things together?

Instead, let’s decorate that same class with the MEF ExportAttribute like so:

[Export(typeof(IIocRegistrar))]
public class IocRegistrar : IIocRegistrar
{
#region IIocRegistrar Members

public void RegisterComponents(ContainerBuilder builder)
{
builder.RegisterType<SalesRepModelCreator>().Named<IModelCreator>(“Foo”));
builder.RegisterType<AdminModelCreator>().Named<IModelCreator>(“Bar”));
}

#endregion
}

MEF in the Bloodstream - or - seeking out all registrars at runtime

This is MEF in its simplest form – we’re categorizing our Export as a type that we will use to discover at runtime. If we want to segment our containers, we can add a ‘contractName’ parameter to further declare groupings of registrars and pull them back by name. This opens up a lot of possibilities, but we’ll focus on the simplest case here.

When building up our container – we may do this in a central resolver if using ServiceLocation, or this can be done more generically on app startup and integrate it with something like Mvc’s resolver wireup. Here we’ll use the DirectoryCatalog to go after everything in the bin directory to get our wireups. If we wanted to go after registrars of a particular name, we can change the GetExportedValues call to take care of this.

var moduleBuilder = new ContainerBuilder();
var directoryCatalog = new DirectoryCatalog(GetAssemblyLocation());

// create a container that we use to discover and compose
var container = new CompositionContainer(directoryCatalog);

foreach (var registrar in container.GetExportedValues<IIocRegistrar>())
registrar.RegisterComponents(moduleBuilder);

We have now told the application to search out all IIocRegistrar exports and build up the container builder accordingly.

Resolving Instances with Autofac

From here on out, everything is the same. No traces of MEF, just Autofac container behavior as usual. Registered types can be resolved from the container created by the builder. Using Service Location to demonstrate the behavior looks like this:

var container = moduleBuilder.Build();

var modelCreator = container.Resolve<IModelCreator>("Foo");

That’s All Folks!

So there you have it. You can now have Ioc registration defined at whatever granularity you choose and even have it occur across assembly layers in your application. While Autofac supports the use of Xml configuration, the ability to test our wireup in small consumable pieces and avoid centralized registrars that reach across many namespaces keeps things light and simple.

Wednesday, March 3, 2010

The DerivedTypeModelBinder in MvcContrib

This content has been moved to the MvcContrib Codeplex site. Please refer to that link for the latest, most current documentation.

Tuesday, January 26, 2010

ValidationAttribute Test Harness updated on Codeplex

Ahead of tomorrow’s 12:00-1:00 Central Brown Bag / Show and Tell over at C4MVC, I made a few changes for the ValidationAttribute Test Harness based on feedback. The changes focus on two areas:

  1. Discoverability: Do we really need to identify all the custom validators on startup? No – MEF handles this very well thank you.
  2. Runtime Statistics: Can we get a picture of what was done on a given run?

These changes were added to software, and the mechanism of calling the Analyze method (1) gives the ability to extend other scanning options and (2) provides for a platform where the MEF discovery results can be reused over multiple calls.

   1: var analyzer = new ValidationAnalyzer();
   2: var results = analyzer.AnalyzeAssembly(typeof (ChangePasswordModel).Assembly, true);
   3:  
   4: Console.WriteLine(results.AnalysisSummary());
   5:             
   6: Assert.That(results.Valid, Is.EqualTo(true), results.CompileErrorMessage());

This is going to be a fun call. We’ll focus on the latest tidbits about how ValidationAttributes are integrated with MVC, a set of ‘gotchas’ that the test harness keeps you clear of and more.

Tuesday, January 19, 2010

Introducing the ValidationAttribute Test Harness on Codeplex

***************************

*** Update: for the latest on how to use the ValidationAttribute Test Harness, check out my latest post in this series...

***************************


This article is an introduction to the ValidationAttribute Test Harness project on Codeplex. This project exists to fill a testing void and maintain quality on ValidationAttributes. Our of the box – the ValidationAttribute Test Harness monitors the declaration of error messages and validates their runtime state. This article briefly discusses the nature of ValidationAttributes, the testing issues around the resource approach and how this new CodePlex project addresses the shortcomings.

The standard thinking around testing ValidationAttribute derived classes is that these are not individually testable – but rather relegated to automated ui testing or exploratory testing. While a certain portion of that is true – we cannot fully recreate the framework that interacts with these properties - we can provide a contextual harness that allows us to test the declarations to ensure that the declarations map to their intended targets (and that intended targets are who they say they are).

Purpose 1: Verifying Properly Localized ValidationAttributes at their Attribution Site

When looking at the ValidationAttribute, you quickly notice three properties that give access to declaring the error message raised when the rule is violated. These three are:

  • string ErrorMessage
  • string ErrorMessageResourceName
  • Type ErrorMessageResourceType

It becomes apparent that there are quality issues, especially when it comes to localization.

  1. Setting a string on ErrorMessage means the error message is not localizable.
  2. The ErrorMessageResourceName is meant to point to a static public property on a resource class – but this is a magic string.
  3. Both the Type and Name must be set for resourced error messages to be identified.
  4. There are a number of combination-style errors that can arise.
  5. The errors that are thrown are obscure and difficult to locate – with details buried deep in the exceptions.

We need a mechanism to test for these scenarios and provide a list of readable errors that lead us directly to the source and allow us to triage them quickly.

Purpose 2: Verifying Custom Attribute Annotations

Custom-defined Attributes, aside from the standard set, are as wide open as we like them to be. They are especially useful when declaring relationships between data. The ASPNET MVC framework generates one out of the box in it’s application template called PropertiesMustMatchAttribute. The attribute is placed at the class level where it declares two properties (via strings) to declare that the two properties are equal which is useful on the model when resetting a password.

This has all the same problems we see with magic strings -

  1. What if the declaration is wrong
  2. What if one of the property names change. The stringified name won’t be changed with it automatically.
  3. What if only one or none of the property names is declared?

Waiting for runtime to discover these kinds of errors is unacceptable.

Using the ValidationAttribute Test Harness to Raise the Quality Bar

Out of the box, the ValidationAttribute Test Harness will take a look at all the ValidationAttribute attributions in your project and verify the configuration of the Error Message related attributes. It will also pull together error information into one concise list that can be easily triaged.

   1: var analyzer = new ValidationAssemblyAnalyzer(typeof(ChangePasswordModel).Assembly, true);
   2: Assert.That(analyzer.ValidationErrorInfoList.Count, Is.EqualTo(0), analyzer.CompileErrorMessage());

The analyzer can also take lists of custom validators so we can provide customized tests based on the attribute type like so:


   1: var analyzer = new ValidationAssemblyAnalyzer(typeof (ResourcedValidationAssemblyAnalyzerTests).Assembly, true, 
   2:                           null,
   3:                           new[] {new PropertiesMustMatchValidator()});
   4:  
   5: Assert.That(analyzer.ValidationErrorInfoList.Count, Is.EqualTo(0), analyzer.CompileErrorMessage());

… this is a great place for MEF, but I’ve held off to avoid dependencies on this initial release. If people just copy the code into their projects, great. If they tend to grab the assembly as a dependency in their unit test project, then it makes more sense. For net4.0, MEF is a no-brainer but we’ll cross that bridge when we get to it. …

Note that the Analyzer takes two enumerable lists – one for member-specific attribute validators and one for class-specific attribute validators. These are denoted by the interface they are derived from: ICustomValidationByTypeAnalyzer or ICustomValidationByMemberAnalyzer.

Understanding How To Write Custom Validators

Writing the custom validators is straightforward and simple. Just implement the ICustomValidator interface on your validator according to the attribute site target. From there, you declare:

  1. The type of the attribute that you are testing.
  2. The actual test using the contextual information about the attribution site.
And there you have it. Check out the code below to see the custom validator in detail. It’s not fully fleshed out, but provides a good boilerplate as such. Now each time you run your unit tests, your models will be validated and you won’t have to


   1: // since the matching attribute only applies at the class level, we'll use the ByTypeAnalyzer variant
   2: public class PropertiesMustMatchValidator : ICustomValidationByTypeAnalyzer 
   3: {
   4:     #region ICustomValidationByTypeAnalyzer Members
   5:  
   6:     /// <summary>
   7:     /// Here we'll test that the property exists on the object according to our criteria
   8:     /// </summary>
   9:     /// <param name="candidateType">attributed class</param>
  10:     /// <param name="propertyName">property name to look for</param>
  11:     /// <returns></returns>
  12:     private bool PublicPropertyExists(Type candidateType, string propertyName)
  13:     {
  14:         return candidateType.GetProperty(propertyName, BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance) != null;
  15:     }
  16:  
  17:     /// <summary>
  18:     /// Responsible for raising errors according to the tests being performed on
  19:     /// the PropertiesMustMatch validator
  20:     /// </summary>
  21:     /// <param name="candidateType">candidate class type information</param>
  22:     /// <param name="validationAttribute">the validation attribute instance that is being tested</param>
  23:     /// <param name="enforceResourceMode">whether to enforce valid resourcing</param>
  24:     /// <returns>list of error error information</returns>
  25:     public IEnumerable<CustomValidationInfo> Validate(Type candidateType, ValidationAttribute validationAttribute, bool enforceResourceMode)
  26:     {
  27:         var list = new List<CustomValidationInfo>();
  28:         var matchAttribute = validationAttribute as PropertiesMustMatchAttribute;
  29:  
  30:         if (!String.IsNullOrEmpty(matchAttribute.OriginalProperty) &&
  31:             !String.IsNullOrEmpty(matchAttribute.ConfirmProperty))
  32:         {
  33:             if( ! PublicPropertyExists(candidateType, matchAttribute.OriginalProperty))
  34:                 list.Add(new CustomValidationInfo(ValidationStatus.DeclarationError, string.Format(CultureInfo.InvariantCulture, "OriginalProperty named '{0}' does not exist on the object", matchAttribute.OriginalProperty)));
  35:  
  36:             if( ! PublicPropertyExists(candidateType, matchAttribute.ConfirmProperty))
  37:                 list.Add(new CustomValidationInfo(ValidationStatus.DeclarationError, string.Format(CultureInfo.InvariantCulture, "ConfirmProperty named '{0}' does not exist on the object", matchAttribute.ConfirmProperty)));
  38:  
  39:             // more tests could be added here - validating type, other required attribute declarations, etc
  40:         }
  41:         else
  42:             list.Add(new CustomValidationInfo(ValidationStatus.DeclarationError,
  43:                                               "Original Property and/or ConfirmPropert is not set"));
  44:  
  45:         return list;
  46:  
  47:     }
  48:  
  49:     /// <summary>
  50:     /// the attribute type that this validator is testing
  51:     /// </summary>
  52:     /// <returns>Type info on the targeted attribute</returns>
  53:     public Type TargetType()
  54:     {
  55:         return typeof (PropertiesMustMatchAttribute);
  56:     }
  57:  
  58:     #endregion
  59: }

Summary

And there you have it. Check out the code above to see the custom validator in detail. It’s not fully fleshed out, but provides a good boilerplate as such. Now each time you run your unit tests, your models will be validated and you won’t have to ‘wait until runtime’ to discover the quality of your model attributions.

Sunday, January 10, 2010

Localizing LabelFor in ASP.NET MVC 2

I started the weekend spelunking ModelBinder with Reflector and started toying with the front-end html helpers. The ASP.NET MVC 2 builds on the MVCContrib FluentHtml implementation and includes some fantastic features for eliminating magic strings in your html. If you are not familiar with the implementation, this piece of code summarizes the Html.LabelFor implementation. For a broader view of these modifications, check out Scott Gu's blog series on the broader functionality.

   1: <div class="editor-label">
   2:    <%=Html.LabelFor(m => m.LastName)%
   3: </div>

If you refactor your model implementation, the front-end html gets refactored along with it. The default implementation relies on marking up the model using DisplayNameAttribute to resolve a user-readable name.


   1: [Required]
   2: [DisplayName("Last Name")]
   3: [StringLength(64)]
   4: public string LastName { get; set; }

The problem with Attributes is that there is no reasonable way I’ve seen to create a DisplayName attribute style variant that is resource-aware. This is primarily due to constraints on Attributes in the form of generic and runtime type constraints. In short, there is no way to create a flexible approach with (1) no magic strings involved and (2) a format convention that can vary across different MVC Areas.

After looking over the first approach, I looked at creating a new LabelFor extension method. I had two driving criteria in creating the solution - (1) avoid any magic strings in the views and (2) allow for easy and flexible variation of naming rules associated with resource classes.

I like the result as the core workings are very testable and the flexibility is straight-forward.

The first part of the solution includes the LabelFor extension. You’ll notice it mirrors the LabelFor(Expression<…>) implementation by adding the ResourcePropertyResolver<T> implementation. In order to grab the associated metadata, I am relying on the same ModelMetadata calls that the existing LabelFor implementation uses. It then relies on the existing Label(string) implementation to generate the output.


   1: /// <summary>
   2: /// Our own set of custom label extensions
   3: /// </summary>
   4: public static class CustomLabelExtensions
   5: {
   6:     /// <summary>
   7:     /// Returns an HMTL label element with the content resolved for the given propety according to
   8:     /// the format specified in the parameters
   9:     /// </summary>
  10:     /// <typeparam name="TModel">The model typically inferred from the prage</typeparam>
  11:     /// <typeparam name="TValue">Value type inferred from expression</typeparam>
  12:     /// <typeparam name="TResourceType">Resource type used as the string resolution target</typeparam>
  13:     /// <param name="html">extension method parameter</param>
  14:     /// <param name="resourcePropertyResolver">resource resolver that indicates the resolution target 
  15:     /// and format strings</param>
  16:     /// <param name="expression">expression tree intended to point at the property being named</param>
  17:     /// <returns>localized, resolved label for the property</returns>
  18:     public static MvcHtmlString LabelFor<TModel, TValue, TResourceType>(this HtmlHelper<TModel> html, ResourcePropertyResolver<TResourceType> resourcePropertyResolver, Expression<Func<TModel, TValue>> expression)
  19:     {
  20:         var metaData = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
  21:  
  22:         var resourcePropertyName = string.Format(CultureInfo.InvariantCulture, resourcePropertyResolver.ResourcePropertyFormatPolicy,
  23:                                                  metaData.ContainerType.Name, metaData.PropertyName);
  24:  
  25:         return html.Label(resourcePropertyResolver.GetResourceValue(resourcePropertyName));
  26:     }
  27: }

The next part is a default implementation of ResourcePropertyResolver. Starting at the top, this is a generic class requires the type of your resource class. A resource class is effectively any class that has static properties – the code-gen component of Visual Studio takes the resource table and implements it as a plain old class. Remember that the code generator property defaults to internal types – called out on the Custom Tool property. You can make these all public types by changing the Custom Tool property to PublicResXFileCodeGenerator.

First off, a static readonly type is resolved once for the class to avoid multipel typeof(…) resolutions – an efficiency move here. Next, a couple of string formatting properties. The first calls out the naming policy for properties on the resource class. The default value is ‘[class name]_[property name]’. The second format calls out the value that should be returned when a matching value is not found. Note that both of these are overridable which I will demonstrate in a moment.

Finally, the GetResourceValue method does the heavy lifting of locating the property in the table and formatting output accordingly.


   1: /// <summary>
   2: /// Implements access of the actual resource class and the associated
   3: /// formatting rules for property names and unresolved resource values
   4: /// </summary>
   5: /// <typeparam name="TResourceType">resource class</typeparam>
   6: public class ResourcePropertyResolver<TResourceType>
   7: {
   8:     private static readonly Type _resourceType = typeof(TResourceType);
   9:  
  10:     public virtual string ResourcePropertyFormatPolicy
  11:     { get { return "{0}_{1}"; } }
  12:  
  13:     public virtual string UnresolvedValueFormatString
  14:     { get { return "{0}.{1}"; } }
  15:  
  16:     internal string GetResourceValue(string resourcePropertyName)
  17:     {
  18:         // both public and non-public are members are being searched because resource properties
  19:         // will either be generated as internal or public. Optimize this by making it specific to
  20:         // your case.
  21:         var propertyInfo =
  22:             _resourceType.GetProperty(resourcePropertyName,
  23:                                        BindingFlags.Static  BindingFlags.Public  BindingFlags.NonPublic);
  24:  
  25:         if (propertyInfo == null)
  26:             return String.Format(CultureInfo.InvariantCulture, UnresolvedValueFormatString, _resourceType.Name, resourcePropertyName);
  27:  
  28:         return (string)propertyInfo.GetValue(null, null);
  29:     }
  30: }

Next, let’s create a custom rule that outputs a patterned, more identifiable output with a little helper that simplifies the View markup. In this case, we simply override the rules we want to and then create a single live, static instance that is quickly referencable.


   1: public class WebStringResolver : ResourcePropertyResolver<WebStringTable>
   2: {
   3:     public override string UnresolvedValueFormatString
   4:     {
   5:         get
   6:         {
   7:             return "*** {0}.{1} ***";
   8:         }
   9:     }
  10:  
  11:     private static WebStringResolver _instance = new WebStringResolver();
  12:     public static WebStringResolver Instance 
  13:     {
  14:         get
  15:         {
  16:             return _instance;
  17:         }
  18:     }
  19: }

So finally, this leads us to the modified markup that is quite explicit to which resource table it is tied and no magic strings in place.


   1: <div class="editor-label">
   2:     <%=Html.LabelFor(WebStringResolver.Instance, m => m.LastName)%>
   3: </div>

So there you have it- my diversion from reflector-spellunking into the ModelBinder.

Sunday, October 18, 2009

Deconstructing Localization in ASP.NET and ASP.NET MVC

kick it on DotNetKicks.com

The localization story in ASP.NET is an interesting one. While there is a decent amount of information on how to use it, information on how it works and how you can modify it to your own needs is fairly weak. We’ll quickly review how localization works today in ASP.NET, how it is internally wired and then look at how we can tweak.

For the purpose of this post, I will refer to a fictional application called MyApp.

Review of Accessing Localized Resources in Asp.Net pages today

  • Site-wide resources are stored under a root level directory in “App_GlobalResources.”
  • Page-specific resources are stored in the local folder under a folder called “App_LocalResources”. The resources for a file named 'view.aspx' reside inside of the App_LocalResources folder under the name 'view.aspx.resx'
  • Global Resources are accessed by providing the resource path in the asp.net parsed files in the form of <%$ Resources: [class], [member] %>
  • Local Resources are accessed by providing the resource path in the asp.net parsed files in the form of <%$ Resources: [member] %>

How the Localization Scheme is implemented

  • Visual Studio munges all resource table implementations in App_GlobalResources by forcing them into the absolute namespace of ‘Resources.’.
  • Visual Studio compiles resources located under the individual App_LocalResources into their own resource assembly that gets embedded into the project as ‘[root namspace].[virtualpath].[pagename].resources
  • Handoff of values across methods in ExpressionBuilder relies on casting via System.Object.
  • The Resources: binding expression mentioned above is wired up in the system web.config with the following wireup:
<expressionBuilders>
<add expressionPrefix="Resources" type="System.Web.Compilation.ResourceExpressionBuilder"/>
</expressionBuilders>

Considerations for Change

A couple of brief thoughts that form our solution

  • When you have more than one tier in your application, having shared resources is preferred. When sending your resources out for localization, duplicate definitions across resource files gives the opportunity for translation inconsistency.
  • The solution needs to factor out the casting to/from System.Object for the purpose of clarity.
  • If you avoid code wizards, the enlistment of visual studio in this scheme probably leaves you with high blood pressure.

I’m not going to beleaguer the third point – I’m guessing that there is a use-case for this, but I have not personally seen it. After digging through the handlers for the global and local resources, my resolve for rewriting this grew even more.

Creating Our Custom Handlers

When creating my own custom handler for resources, I started by looking at ResourceExpressionBuilder which derives from System.Web.Compilation.ExpressionBuilder for code to reuse. What I found was nothing worth reusing, but plenty of ideas. The overloaded methods provided a view of discrete responsibilities that I isolated in the final implementation. Because the base expression builder is expected to throw System.Web.HttpException, this also called for factoring responsibilities in a manner that allows me to move the core mechanics to another assembly without requiring a reference to System.Web.

My intent is to wireup a keyword in the web application to a single resource table. In this case, I will create a MyAppResources keyword that will resolve the member residing in a separate resource assembly at MyApp.Resources.MyAppResources.resx. The solution below is can be wired up however you like, this is just my choice in this instance.

Our first step is therefore creating an interface that isolates the responsibilities independent of the implementation called IResourceValueProvider



   1: /// <summary>
   2: /// Interface responsible for breaking out the discrete responsibilities in providing
   3: /// resource strings to the application based on free text validation
   4: /// </summary>
   5: public interface IResourceValueProvider
   6: {
   7:     /// <summary>
   8:     /// Responsible for taking the expression and parsing it into a meaningful path to 
   9:     /// a resource value
  10:     /// </summary>
  11:     /// <param name="expression">string passed from the pages</param>
  12:     void ParseExpression(string expression);
  13:  
  14:     /// <summary>
  15:     /// Responsible for validating that the expression resolves to the target resource table
  16:     /// </summary>
  17:     /// <returns>true if found</returns>
  18:     bool ValidateParsedValue();
  19:  
  20:     /// <summary>
  21:     /// Responsible for returning the string value from the resource table
  22:     /// </summary>
  23:     /// <returns>resolved resource value</returns>
  24:     string GetResourceValue();
  25:  
  26:     /// <summary>
  27:     /// Responsible for describing the resource table name
  28:     /// </summary>
  29:     string TargetResourceTable { get; }
  30: }


The code comments do a fair job of explaining their responsibilities, so I’ll focus on a couple of key points here not explained. In our implementation of expecting a single value, the incoming expression in ParseExpression will not need parsing. If we decided to support [class], [member], then we would obviously require a String.Split implementation. Also, the TargetResourceTable member is responsible for describing the target resource table floated up in error conditions.

Implementing our CustomHandler

The following implementation is done as close to our Resource table as we can. There are many reasons for this and while it could be implemented in our web application due to the use of reflection, the corresponding explicit reference in Web.Config (shown later) provides a level of immediate recognition as to where these resources live.


   1: /// <summary>
   2: /// Responsible for providing access to the MyAppStringTable resources.  As this
   3: /// approach is used more, most of this functionality is likely to be
   4: /// 
   5: /// </summary>
   6: public class MyAppResourceValueProvider : IResourceValueProvider 
   7: {
   8:     protected string Expression { get; private set; }
   9:     protected PropertyInfo PropertyInfo { get; private set; }
  10:     #region IResourceValueProvider Members
  11:  
  12:     /// <summary>
  13:     /// Parse expression is where the passed in string must be interrogated according to requirements.
  14:     /// As this is a single string that maps directly to the object, there is no need to perform
  15:     /// any parsing aside from capture.
  16:     /// </summary>
  17:     /// <param name="expression"></param>
  18:     public void ParseExpression(string expression)
  19:     {
  20:         // the expression is not null checked as this is a closed system where null or empty expressions
  21:         // are explicitly handled conditions by the caller
  22:         Expression = expression;
  23:     }
  24:  
  25:     /// <summary>
  26:     /// This method is responsible to make sure that the passed along expression maps to something meaningful.
  27:     /// </summary>
  28:     /// <returns>true if the expression is valid</returns>
  29:     public bool ValidateParsedValue()
  30:     {
  31:         PropertyInfo = (typeof (MyAppStringTable)).GetProperty(Expression,
  32:                                                               BindingFlags.NonPublic | BindingFlags.Static |
  33:                                                               BindingFlags.IgnoreCase);
  34:  
  35:         return PropertyInfo != null;
  36:     }
  37:  
  38:     /// <summary>
  39:     /// Retrieves the string value from the resource table
  40:     /// </summary>
  41:     /// <returns></returns>
  42:     public string GetResourceValue()
  43:     {
  44:         return PropertyInfo.GetValue(null, null) as string;
  45:     }
  46:  
  47:     /// <summary>
  48:     /// Retreives the name of the resource table targeted by this handler
  49:     /// </summary>
  50:     public string TargetResourceTable
  51:     {
  52:         get { return "MyAppStringTable"; }
  53:     }
  54:  
  55:     #endregion
  56: }

Extending ExpressionBuilder to Parse and Evaluate

Our last job is to extend the ExpressionBuilder to wire this up with error handling.


   1: /// <summary>
   2: /// This generic mapping permits a resource file to be mapped in the web.config file with a clear
   3: /// declaration in the web.config expressionBuilder set.
   4: /// </summary>
   5: /// <typeparam name="TResourceValueProvider">a resource value provider that maps string names to resource properties</typeparam>
   6: internal class GenericResourceExpressionBuilder<TResourceValueProvider> : ExpressionBuilder
   7:     where TResourceValueProvider : IResourceValueProvider, new()
   8: {
   9:     /// <summary>
  10:     /// Returns a realizable CodeExpression that represents the parsed data passed in. By this time, the 
  11:     /// existance of the CodeExpression has been determined
  12:     /// </summary>
  13:     /// <param name="entry">context of the bound property</param>
  14:     /// <param name="parsedData">parsed data as defined by the ParseExpression method</param>
  15:     /// <param name="context">builder context</param>
  16:     /// <returns>CodeExpression used for evaluating the returned value</returns>
  17:     public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
  18:     {
  19:         var provider = parsedData as IResourceValueProvider;
  20:  
  21:         // the following situation should never happen as ParseExpression does not permit a null value through
  22:         if (provider == null)
  23:             throw new HttpException("Critical Error: the declared property identification process has failed");
  24:  
  25:         return new CodePrimitiveExpression(provider.GetResourceValue());
  26:     }
  27:  
  28:     /// <summary>
  29:     /// Parses the expression and tests that it maps into the resource file
  30:     /// </summary>
  31:     /// <param name="expression">text expression from the web site</param>
  32:     /// <param name="propertyType">expression type</param>
  33:     /// <param name="context">builder context inside the site</param>
  34:     /// <returns></returns>
  35:     public override object ParseExpression(string expression, Type propertyType, ExpressionBuilderContext context)
  36:     {
  37:         if (String.IsNullOrEmpty(expression) || String.IsNullOrEmpty(expression.Trim()))
  38:             throw new HttpException("The globalization field cannot be null or empty");
  39:  
  40:         var provider = new TResourceValueProvider();
  41:  
  42:         try
  43:         {
  44:             provider.ParseExpression(expression);
  45:         }
  46:         catch( Exception e)
  47:         {
  48:             throw new HttpException(e.Message, e);
  49:         }
  50:  
  51:         if (!provider.ValidateParsedValue())
  52:             throw new HttpException(string.Format(CultureInfo.InvariantCulture,
  53:                                                   "The field {0} is not declared on {1}", 
  54:                                                   expression,
  55:                                                   provider.TargetResourceTable));
  56:  
  57:         return provider;
  58:     }
  59:  
  60:     /// <summary>
  61:     /// Declares that this process does not require evaluation
  62:     /// </summary>
  63:     public override bool SupportsEvaluate
  64:     {
  65:         get
  66:         {
  67:             return false;
  68:         }
  69:     }
  70: }

Pulling it All Together in ASP.NET

Our final step is pulling this into the local web.config with the following snippet.



   1: <expressionBuilders>
   2:  <add 
   3: expressionPrefix="MyAppResources"
   4:  type="MyApp.GenericResourceExpressionBuilder<MyApp.Resources.MyAppResourcesValueProvider, 
   5:         MyApp.Resources>, MyApp"/>
   6: </expressionBuilders> 

Final Wrap

So there you have it – a view of how resources are managed in Visual Studio and the tools to change it to match differing requirements. In my server-side files, I can now point to my resources quite simply. If I want to grab the value named 'ApplicationName' in my resource file, the accompanying markup looks like this:

<%$ MyAppResources: ApplicationName %>

Twitter Updates