What I have is the following extension method:
public MyCustomAttribute[] GetActionAttributes(
this Controller @this,
string action,
string contr
I have looked inside MVC 3 source code, and tested with MVC 4, and discovered how to do it. I have tagged the question wrong... it is not for MVC 3, I am using MVC 4. Though, as I could find a solution looking at MVC 3 code, then it may work with MVC 3 too.
At the end... I hope this is worth 5 hours of exploration, with a lot trials and errors.
Works with
Unfortunately, this solution is quite complex, and dependent on things that I don't like very much:
ControllerBuilder.Current
(very bad for unit testing)RouteData
object is not used to find the controller type, so I simply use stub RouteData objects)HttpContextWrapper
and HttpRequestWrapper
in order to set the http method
to be POST
or GET
... these pretty simple values comes from complex objects (oh god! =\ ))public static Attribute[] GetAttributes(
this Controller @this,
string action = null,
string controller = null,
string method = "GET")
{
var actionName = action
?? @this.RouteData.GetRequiredString("action");
var controllerName = controller
?? @this.RouteData.GetRequiredString("controller");
var controllerFactory = ControllerBuilder.Current
.GetControllerFactory();
var controllerContext = @this.ControllerContext;
var otherController = (ControllerBase)controllerFactory
.CreateController(
new RequestContext(controllerContext.HttpContext, new RouteData()),
controllerName);
var controllerDescriptor = new ReflectedControllerDescriptor(
otherController.GetType());
var controllerContext2 = new ControllerContext(
new MockHttpContextWrapper(
controllerContext.HttpContext.ApplicationInstance.Context,
method),
new RouteData(),
otherController);
var actionDescriptor = controllerDescriptor
.FindAction(controllerContext2, actionName);
var attributes = actionDescriptor.GetCustomAttributes(true)
.Cast()
.ToArray();
return attributes;
}
EDIT
Forgot the mocked classes
class MockHttpContextWrapper : HttpContextWrapper
{
public MockHttpContextWrapper(HttpContext httpContext, string method)
: base(httpContext)
{
this.request = new MockHttpRequestWrapper(httpContext.Request, method);
}
private readonly HttpRequestBase request;
public override HttpRequestBase Request
{
get { return request; }
}
class MockHttpRequestWrapper : HttpRequestWrapper
{
public MockHttpRequestWrapper(HttpRequest httpRequest, string httpMethod)
: base(httpRequest)
{
this.httpMethod = httpMethod;
}
private readonly string httpMethod;
public override string HttpMethod
{
get { return httpMethod; }
}
}
}
Hope all of this helps someone...
Happy coding for everybody!