I've been trying to figure out how this works on a low-level:
[Authorize]
public ActionResult Index()
{
return View();
}
Basically, the above code snippet seems to intercept calls to the Index method, perform an authorization check, and throw and exception if not authorized. The exception prevents the code within the Index method from ever being invoked.
This seems very AOP-like, and is not something easily done in C#. If I were to implement my own class that extended System.Attribute, I would not have any interface to hook into pre or post invocation of the method my attribute decorates. So how does the MVC Authorize attribute do it, and how could I do it on my own?
PostSharp is a library that accomplishes the same thing using IL Weaving. Basically, at compile time, PostSharp scans the assembly for methods decorated with certain attributes, and then re-writes your code to wrap your method calls with other method calls.
Does the MVC framework also perform some kind of IL Weaving at compile time? Is it possible for me to perform my own IL Weaving? Or are there other techniques for applying the same AOP principles without complex IL Weaving?
I've tried to find information on IL Weaving but all I find are articles about PostSharp. I would prefer to stay away from PostSharp because of the Licensing hassles, but moreover, I just want to know how the heck they did it for my own growth as a developer. It's quite fascinating.
the easiest way to understand it is by looking at the source code.
a basic explanation is that the mvc controller is not simply called like instance.method (in which case you would need postsharp to make the attributes work the same way)
there is a ControllerActionInvoker
which has the method
public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
{
...
// get all the filters (all that inherit FilterAttribute), inlcuding the authorize attribute
FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);
first all the filters that inherit IAuthorizationFilter
are executed (Authorize, ValidateAntiForgeryToken)
, after if auth succeeded the rest
AuthorizationContext authContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor);
//authContext.Result has value if authorization didn't succeed
if (authContext.Result != null)
{
// the auth filter signaled that we should let it short-circuit the request
InvokeActionResult(controllerContext, authContext.Result);
}
else
{
if (controllerContext.Controller.ValidateRequest)
{
ValidateRequest(controllerContext);
}
IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor);
//invoke the action with filters here
ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters);
InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, postActionContext.Result);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With