Dive Deep Into MVC - IValueProvider

In these series of posts, I'll talk about some ASP.NET MVC aspects. You can find the previous post here. Btw, make sure you have a basic knowledge about ASP.NET MVC at least before reading. If so continue.

What I want to achive at last?

I want to implement a custom value provider that retrieves its value from cookie.

What's a value provider?

Frankly, a value provider provides values from associated source for an action method. All of value providers implement IValueProvider interface directly or indirectly. The following table demonstrates a list of available value providers in the ASP.NET MVC.

  • FormValueProvider: Provides value from posted form parameters.
  • QueryStringValueProvider: Provides value from querystring.
  • HttpFileCollectionValueProvider: Provides value from posted files.
  • RouteDataValueProvider: Provides value from route parameters.

Implementing

I had to find an approach to inform the value provider that should retrieve which key from which cookie. Thus, I decided to define a permanent format for parameters as follows.

 

public class HomeController : Controller
{
    //
    // GET: /Home/
    public ActionResult Index(string cookie_hcvp_id, string cookie_hcvp_lastVisit) { }
}

As illustrated in the above code snippet, I used special format to name parameters(cookie_{name}_{*key}). Afterwards, I created my custom value provider by implementing IValueProvider interface that structure is as follows.

namespace System.Web.Mvc
{
    // Summary:
    //     Defines the methods that are required for a value provider in ASP.NET MVC.
    public interface IValueProvider
    {
        bool ContainsPrefix(string prefix);
        ValueProviderResult GetValue(string key);
    }
}

There are two methods to implement. First method checks which the supplied parameter name exists or not. Second one gets called while ContainsPrefix returns true. It returns the associated value of the specified key. The completed source is as follows.

using System;
using System.Globalization;
using System.Web;
using System.Web.Mvc;

namespace HCVP.ValueProviders
{

    public class HttpCookieValueProvider : IValueProvider
    {

        private ControllerContext _context;

        // Ctor

        public HttpCookieValueProvider(ControllerContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");

            this._context = context;
        }

        // methods

        protected virtual bool ContainsPrefix(string prefix)
        {
            return prefix.StartsWith("cookie_", true, CultureInfo.CurrentCulture);
        }

        protected virtual ValueProviderResult GetValue(string key)
        {
            string[] segments = key.Remove(0, 7).Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries);

            if (segments.Length == 0)
                return null;

            HttpCookie cookie = this._context.HttpContext.Request.Cookies[segments[0]];

            if (cookie == null)
                return null;

            if (segments.Length < 2)
                return new ValueProviderResult(cookie.Value, cookie.Value, CultureInfo.CurrentCulture);

            return new ValueProviderResult(cookie.Values.GetValues(segments[1]), cookie.Values[segments[1]], CultureInfo.CurrentCulture);
        }

        // IValueProvider members

        bool IValueProvider.ContainsPrefix(string prefix)
        {
            return this.ContainsPrefix(prefix);
        }

        ValueProviderResult IValueProvider.GetValue(string key)
        {
            return this.GetValue(key);
        }

    }

}

As far as I said here, the value provider class structure has been changed after ASP.NET MVC 2 RC. The ValueProviders class removed. And added an abstract factory design pattern instead. Thus, I have to implement a factory class as follows.

using System.Web.Mvc;

namespace HCVP.ValueProviders
{

    public class HttpCookieValueProviderFactory : ValueProviderFactory
    {

        public override IValueProvider GetValueProvider(ControllerContext controllerContext)
        {
            return new HttpCookieValueProvider(controllerContext);
        }

    }

}

Usage

Lastly, I have to add my own value provider factory to the factories listed in the Global.asax.

protected void Application_Start()
{
    ValueProviderFactories.Factories.Add(new HttpCookieValueProviderFactory());
}

Download Source

Download full source code with a simple example from here...

blog comments powered by Disqus