我查看了 MVC 3 源代码,并使用 MVC 4 进行了测试,并发现了如何做到这一点。我错误地标记了这个问题......它不适用于 MVC 3,我使用的是 MVC 4。虽然,我可以找到一个查看 MVC 3 代码的解决方案,那么它也可能适用于 MVC 3。
最后......我希望这值得 5 个小时的探索,有很多试验和错误。
适用于
我的解决方案的缺点
不幸的是,这个解决方案非常复杂,并且依赖于我不太喜欢的东西:
- 静态对象
ControllerBuilder.Current
(对单元测试非常不利)
- 来自 MVC 的很多类(高耦合总是不好的)
- 不通用(它适用于 MVC 3 默认对象,但可能不适用于从 MVC 派生的其他实现......例如派生的 MvcHandler、自定义 IControllerFactory 等等......)
- 内部依赖(取决于 MVC 3 的特定方面,(MVC 4 的行为也是如此)可能是 MVC 5 不同...例如,我知道
RouteData
对象不用于查找控制器类型,所以我只是使用存根 RouteData 对象)
- 模拟复杂对象以传递数据(我需要模拟
HttpContextWrapper
并HttpRequestWrapper
设置http method
为POST
或GET
......这些非常简单的值来自复杂对象(哦上帝!=\))
编码
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<Attribute>()
.ToArray();
return attributes;
}
编辑
忘记了模拟类
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; }
}
}
}
希望所有这些对某人有帮助...
祝大家编码愉快!