I'm trying to make the move from PHP to ASP.NET and in doing so I'm trying to learn how the MVC works, however I'm stuck with the ControllerActionInvoker.InvokeActionMethodWithFilters as I don't understand what is happening.
The snippet I'm struggling with is the following:
protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
{
ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
Func<ActionExecutedContext> continuation = () =>
new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */)
{
Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
};
// need to reverse the filter list because the continuations are built up backward
Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation,
(next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));
return thunk();
}
The full source code can be found at the following URL: https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/ControllerActionInvoker.cs#L371
In particular, I'm unsure on what the following is doing:
Func<ActionExecutedContext> continuation = () =>
new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */)
{
Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
};
As I've never seen a line containing the following before: continuation = () =>
Nor can I seem to find an answer on Google because it doesn't recognise = () => as a search term.
I'm just as confused with the following snippet of code which has a similar syntax:
// need to reverse the filter list because the continuations are built up backward
Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation,
(next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));
Coming from a PHP background, I've not seen this syntax before, and the resources I've read online don't really clear things up for me either.
On the basis of the following SO question: delegate keyword vs. lambda notation
If I was to rewrite the following...
Func<ActionExecutedContext> continuation = () =>
new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */)
{
Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
};
Would it look like so...
Func<ActionExecutedContext> continuation = delegate(new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */))
{
Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
};
And same for the second snippet...
// need to reverse the filter list because the continuations are built up backward
Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation,
(next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));
Which if I'm not mistaken would be...
// need to reverse the filter list because the continuations are built up backward
Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation, delegate(next, filter) {InvokeActionMethodFilter(filter, preContext, next)});
Or am I still not getting it?
It's a lambda expressions, and in this particular case it is nothing more then anonymous functions.
Wrong. It is delegate to function with two parameters
next
andfilter
, that returns delegate to another function, that callsInvokeActionMethodFilter
method:This code chains IActionFilters invocation until some of them produce result. And at the end of chain is your action method. Variable
next
is either filter executing function() => InvokeActionMethodFilter(filter, preContext, next)
, orcontinuation
at the end of chain. SeeInvokeActionMethodFilter
implementation for details.