The Code Slinger

January 31, 2011

Client Specific Metadata in your MVC Application

Filed under: MVC — Pete @ 12:21 pm

Recently I was working on a new requirement for one of our systems in which each different client may refer to the same data types differently.  For example, ClientA might refer to roadways as a “Parkways” whereas ClientB and ClientC might refer to them as “Highways”.   Changes like these obviously aren’t big enough to warrant separate Views for each screen in which data types like these are referenced or mentioned, however sometimes small things like that make a big difference to the client and makes the application feel more in line with their existing business processes.

So, in order to make it so that my application is still a single code-base that will work for all the various clients that might come along and their varying terminologies, here is what I came up with that I think integrates nicely into an existing MVC application and requires only slight modifications.

First off, here is my interface and concrete implementation of a dictionary wrapper that I will use to not only store the key/value pairs which represent the data types but which will be what my Views utilize as an appendage to their ViewModel instances.

    public interface IMeta

    {

        MetaDictionary Meta { get; set; }

    }

 

    public class MetaDictionary

    {

        private Dictionary<string, KeyValuePair<string,string>> dict;

        public MetaDictionary()

        {

            dict = new Dictionary<string, KeyValuePair<string, string>>();

        }

 

        public void Add(string key, KeyValuePair<string,string> value)

        {

            if (!dict.ContainsKey(key))

                dict.Add(key, value);

            else

                dict[key] = value;

        }

        public void Remove(string key)

        {

            if (dict.ContainsKey(key))

                dict.Remove(key);

        }

 

        public string GetValue(string key)

        {

            if(dict.ContainsKey(key))

                return dict[key].Key;

            else

                return "";

        }

        public string GetValueAbbrev(string key)

        {

            if(dict.ContainsKey(key))

                return dict[key].Value;

            else

                return "";

        }

    }

Next, I need to write an action filter that will fetch the appropriate key/value pairs relevant to the currently logged in user and which client they belong to.  Please note that this is where your logic goes to determine A) where to retrieve your key/value pairs to begin with (DB, XML, config file, etc) and B) what differentiating factor(s) you might have which would determine how your application knows each client.  In my situation, I currently have a variable which would store the ClientID in a pre-existing injected Session wrapper.  Also note, I’m using StructureMap as my DI container.

    public class ClientMetaAttribute : ActionFilterAttribute, IActionFilter

    {

        private readonly IControllerDependency Services;

        public ClientMetaAttribute():this(ObjectFactory.GetInstance<IControllerDependency>())

        {

        }

        public ClientMetaAttribute(IControllerDependency service)

        {

            Services = service;

        }

        public override void OnResultExecuting(ResultExecutingContext filterContext)

        {

            //Lookup all appropriate attributes.

            int? clientid = Services.SessionHandler.ClientID;

            var metadict = new MetaDictionary();

            //FILL YOUR META dictionary here!!

 
           ((IMeta)((ViewResultBase)filterContext.Result).ViewData.Model).Meta = metadict;

            base.OnResultExecuting(filterContext);

        }

 

        public override void OnResultExecuted(ResultExecutedContext filterContext)

        {

            base.OnResultExecuted(filterContext);

        }

Now, once I’ve implemented IMeta in the ViewModel used for my action method:

    public class ClientViewModel: IMeta

    {

        public MetaDictionary Meta { get; set; }

        //Rest of model class definition…

    }

Then I simply need to update any hardcoded references within View(s) which use this ViewModel such as:

<h4><%: Model.Meta.GetValue("roadname") %> (<%: Model.Meta.GetValueAbbrev("roadname") %>)</h4>

Which for ClientA will give me

Parkway (PKWY)

and for for ClientB & ClientC will give

Highway (HWY)

Obviously this could be expanded in terms of the dictionary value storage to include a host of other information that may be specific to your needs, however this example shows the intent.  Additionally, another enhancement would be to extend this for use in a localization scenario where multiple languages may be necessary as well. 

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: