MvcExtensions - PerRequestTask
- by kazimanzurrashid
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, 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 RemoveWww()
{
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.