MvcExtensions - PerRequestTask

In the previous post, we have seen the BootstrapperTask which executes when the application starts and ends, similarly there are times when we need to execute some custom logic when a request starts and ends. Usually, for this kind of scenario we create HttpModule and hook the begin and end request events. There is nothing wrong with this approach, except HttpModules are not at all IoC containers friendly and tight coupled with HttpContext and its tail, also defining the HttpModule execution order is bit cumbersome, you either have to modify the machine.config or clear the HttpModules and add it again in web.config. Instead, you can use the PerRequestTask which is very much container friendly as well as supports execution orders. Lets few examples where it can be used.

Remove www Subdomain

Lets say we want to remove the www subdomain, so that if anybody types http://www.mydomain.com it will automatically redirects to http://mydomain.com.

public class RemoveWwwSubdomain : PerRequestTask
{
    public RemoveWwwSubdomain()
    {
        Order = DefaultOrder - 1;
    }

    protected override TaskContinuation ExecuteCore(PerRequestExecutionContext executionContext)
    {
        const string Prefix = "http://www.";

        Check.Argument.IsNotNull(executionContext, "executionContext");

        HttpContextBase httpContext = executionContext.HttpContext;

        string url = httpContext.Request.Url.ToString();

        bool startsWith3W = url.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
        bool shouldContinue = true;

        if (startsWith3W)
        {
            string newUrl = "http://" + url.Substring(Prefix.Length);

            HttpResponseBase response = httpContext.Response;

            response.StatusCode = (int)HttpStatusCode.MovedPermanently;
            response.Status = "301 Moved Permanently";
            response.RedirectLocation = newUrl;
            response.SuppressContent = true;
            shouldContinue = false;
        }

        return shouldContinue ? TaskContinuation.Continue : TaskContinuation.Break;
    }
}

As you can see, first, we are setting the order so that we do not have to execute the remaining tasks of the chain when we are redirecting, next in the ExecuteCore, we checking the whether www is present, if present we are sending a permanently moved http status code and breaking the task execution chain otherwise we are continuing with the chain.

Blocking IP Address

Lets take another scenario, your application is hosted in a shared hosting environment where you do not have the permission to change the IIS setting and you want to block certain IP addresses from visiting your application. Lets say, you maintain a list of IP address in database/xml files which you want to block, you have a IBannedIPAddressRepository service which is used to match banned IP Address.

public class BlockRestrictedIPAddress : PerRequestTask
{
    protected override TaskContinuation ExecuteCore(PerRequestExecutionContext executionContext)
    {
        bool shouldContinue = true;
        HttpContextBase httpContext = executionContext.HttpContext;

        if (!httpContext.Request.IsLocal)
        {
            string ipAddress = httpContext.Request.UserHostAddress;

            HttpResponseBase httpResponse = httpContext.Response;

            if (executionContext.ServiceLocator.GetInstance<IBannedIPAddressRepository>().IsMatching(ipAddress))
            {
                httpResponse.StatusCode = (int)HttpStatusCode.Forbidden;
                httpResponse.StatusDescription = "IPAddress blocked.";

                shouldContinue = false;
            }
        }

        return shouldContinue ? TaskContinuation.Continue : TaskContinuation.Break;
    }
}

Managing Database Session

Now, let see how it can be used to manage NHibernate session, assuming that ISessionFactory of NHibernate is already registered in our container.

public class ManageNHibernateSession : PerRequestTask
{
    private ISession session;

    protected override TaskContinuation ExecuteCore(PerRequestExecutionContext executionContext)
    {
        ISessionFactory factory = executionContext.ServiceLocator.GetInstance<ISessionFactory>();

        session = factory.OpenSession();

        return TaskContinuation.Continue;
    }

    protected override void DisposeCore()
    {
        session.Close();
        session.Dispose();
    }
}

As you can see PerRequestTask can be used to execute small and precise tasks in the begin/end request, certainly if you want to execute other than begin/end request there is no other alternate of HttpModule.

That’s it for today, in the next post, we will discuss about the Action Filters, so stay tuned.

Shout it

2 Comments

  • I just started evaluating MvcExtensions and so far I've found it very appealing. I have a question about your use of PerRequestTask for DB session initialization though.

    I'm not using nHibernate, but am trying out the new Raven DB. It has a similar session concept but there's no way of getting the newly opened session from a PerRequestTask from within the controllers.

    What I really need is to natively use some of the container's ability to hold per request objects. Perhaps this is a place where the user of ServiceLocator isn't a great fit.

  • Yes, you're absolutely right. I began thinking down one path and ignored the simplicity of just using the container. I'm using Unity in this particular case.

    One thing you haven't blogged about yet is modules. Are they simply loaded once per application? That's what I'm using right now to register my services in my container and I think that's correct.

    What would be nice is if they also had an Unload method that would be called when the application ended.

Comments have been disabled for this content.