我的一些控制器操作具有一组标准的故障处理行为。一般来说,我想:
这些步骤非常标准化,我希望有可重用的代码来实现这种行为。
我目前的攻击计划是使用辅助方法来执行以下操作:
public static ActionResult HandleMyObject(this Controller controller,
Func<MyObject,ActionResult> onSuccess) {
var myObject = MyObject.LoadFrom(controller.RouteData).
if ( myObject == null ) return NotFound(controller);
if ( myObject.IsNotAllowed(controller.User)) return NotAllowed(controller);
return onSuccess(myObject);
}
# NotAllowed() is pretty much the same as this
public static NotFound(Controller controller){
controller.HttpContext.Response.StatusCode = 404
# NotFound.aspx is a shared view.
ViewResult result = controller.View("NotFound");
return result;
}
这里的问题是Controller.View()是受保护的方法,因此无法从帮助程序访问。我已经看过明确地创建一个新的ViewResult实例,但是有足够的属性来设置我在不知道陷阱的情况下这么做是很谨慎。
从特定控制器外部创建ViewResult的最佳方法是什么?
答案 0 :(得分:6)
刚看完这篇文章,因为我从动作过滤器中遇到了同样的问题。我的解决方案是明确地创建视图操作。这基于受MVC源的受保护View()方法,因此它应填充所需的属性。无论如何,似乎没有问题。
public static NotFound(Controller controller){
controller.HttpContext.Response.StatusCode = 404;
ViewResult result = new ViewResult {
ViewName = "NotFound",
ViewData = controller.ViewData,
TempData = controller.TempData
};
return result;
}
当天晚些时候,但这对我有用。
答案 1 :(得分:4)
当我写这篇文章时,我想到了一种方式。
我可以把它放在Controller的子类中,然后将这个类子类化为我的实际控制器,而不是将上面的代码放在帮助器中。这将允许我调用受保护的View()方法。
我不喜欢这个,因为它requires inheritance to work,但它仍然是一个选项。
答案 2 :(得分:2)
我有同样的问题并以不同的方式回答。我真的不想为此使用继承,所以我改用了lambda。
首先,我有一个对象,我从控制器传递给我想要返回视图的方法:
public struct MyControllerContext
{
public HttpRequestBase Request { get; set; }
public HttpResponseBase Response { get; set; }
public DocsController Controller { get; set; }
public Func<string, object, ViewResult> ViewResult;
public ViewResult View(string viewName, object model)
{
return this.ViewResult(viewName, model);
}
}
我创建了一个这样的实例,并将其作为参数传递给将返回结果的方法:
// In the controller
var context = new DocsControllerContext()
{
Request = Request,
Response = Response,
Controller = this,
ViewResult = (viewName, model) =>
{
return View(viewName, model);
}
};
var returnValue = methodInfo.Invoke(toInvoke, new object[] { context });
return returnValue;
然后在我调用的方法中,我可以调用context.View("ViewName", model);
。这可能有很多变化,基本思路是使用回调。
答案 3 :(得分:0)
另一种方法是使用装饰器:
public class StatusCodeViewResultDecorator : ViewResult {
ViewResult wrapped;
int code;
string description;
public StatusCodeViewResultDecorator( ViewResult wrapped, int code, string description ) {
this.wrapped = wrapped;
this.code = code;
this.description = description;
}
public override void ExecuteResult(ControllerContext context) {
wrapped.ExecuteResult(context);
context.RequestContext.HttpContext.Response.StatusCode = code;
context.RequestContext.HttpContext.Response.StatusDescription = description;
}
}
也许是一种使其更清洁的扩展方法:
public static class ViewResultExtensions {
public static ViewResult WithStatus( this ViewResult viewResult, int code, string description ) {
return new StatusCodeViewResultDecorator(viewResult,code,description);
}
}
然后你可以简单地说:
return View("MyView").WithStatus(404,"Not found");
在您的控制器中。