系统位于Asp.Net MVC 4,C#。
在执行控制器方法之前抛出异常。我不知道如何处理它 - 我想将用户重定向到错误页面,但我不能。
我有一个基本ViewModel类,其中包含要在下拉列表中使用的SelectList。在其构造函数中,ViewModel从数据库中获取其SelectListItems。这是例外的来源。
索引方法将viewmodel作为参数。
这是代码草图:
class MyViewModel{
public SelectList SelectListModel { get; set; }
public MyViewModel()
{
List<X> xs = GetItemsFromDB(); // <= Exception thrown here
List<SelectListItem> SelectListContent = new List<SelectListItem>();
foreach(X x in xs)
{
SelectListContent.Add(new SelectListItem( Value = x.value,Text=x.text);
}
SelectListModel = new SelectList(SelectListContent , "Value", "Text");
}
}
public class MyController : Controller
{
public ActionResult Index(MyViewModel model) //<< Exception thrown before entering method
{
//do something
}
}
我试图在catch中使用try-catch包含以下代码:
var context = new HttpContextWrapper(HttpContext.Current);
var rc = new RequestContext(context, new RouteData());
var urlHelper = new UrlHelper(rc);
context.Response.Redirect(urlHelper.Action("Index", "Error", new { messagem = x.Message }), false);
HttpContext.Current.ApplicationInstance.CompleteRequest();
我从其他SO答案中得到了这个,但它不起作用。执行此块时,用户不会重定向到错误页面。相反,MyControllers Index方法继续执行。
答案 0 :(得分:4)
捕获此信息的最佳方法是创建ExceptionFilter
public class CustomExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (filterContext.ExceptionHandled)
return;
//Do yout logic here
}
}
并在FilterConfig.cs的RegisterGlobalFilters中将其注册为全局
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomExceptionFilter());
}
答案 1 :(得分:1)
虽然您可以使用ExceptionFilter
,但这是不必要的。这里真正的问题是你错误地使用了视图模型。视图模型应仅包含您在视图中显示/编辑所需的属性,并且不应访问数据库。有两个原因是
DefaultModelBinder
将初始化模型并调用它
构造函数,它反过来调用数据库来填充你的
SelectList
。您应该需要SelectList
的唯一原因
POST方法是因为ModelState
无效而你需要
返回视图。如果启用了客户端验证,则可以
很少见,所以你不必通过建立数据库来降低性能
要求提供不会使用的数据。建议您阅读What is ViewModel in MVC?
中的答案接下来,您的GET方法不应包含模型的参数。有两个原因是
DefaultModelBinder
正在初始化您的模型及其
将模型属性的值添加到ModelState
,如果您的
属性包含任何验证属性,然后ModelState
将
无效。副作用将是任何验证错误
显示在初始视图中,以及任何设置值的尝试
HtmlHelper
将忽略GET方法中的属性
方法,因为它们优先使用ModelState
中的值
到模型属性。为了克服这个问题,你需要使用
ModelState.Clear()
黑客,有效地撤消了什么
ModelBinder
刚刚完成。它再次毫无意义
开销。BeginForm()
,指定操作方法名称。相反,您应该在GET方法中初始化视图模型的实例。
最后,模型构造函数中用于生成SelectList
的代码生成一个IEnumerable<SelectListItem>
,然后从第一个创建第二个相同的IEnumerable<SelectListItem>
(再次只是不必要的额外开销)。
根据您的评论,您已指出这将是一个基本视图模型,因此我建议您使用以下方法BaseController
protected void ConfigureBaseViewModel(BaseVM model)
{
List<X> xs = GetItemsFromDB();
model.SelectListModel = new SelectList(xs, "value", "text");
// or model.SelectListModel = xs.Select(x => new SelectListItem{ Value = x.value, Text=x.text });
}
其中BaseVM
是
public abstract class BaseVM
{
[Required(ErrorMessage = "Please select an item")] // add other display and validation attributes as necessary
public int SelectedItem { get; set; } // or string?
public IEnumerable<SelectListItem> SelectListModel { get; set; }
.... // other common properties
}
然后在具体控制器中
public ActionResult Index()
{
var model = new yourConcreteModel();
ConfigureBaseViewModel(model);
return View(model);
}
[HttpPost]
public ActionResult Index(yourConcreteModel model)
{
if (!ModelState.IsValid)
{
ConfigureBaseViewModel(model);
return View(model);
}
// save and redirect
}
类似地,您可能在每个具体控制器中都有一个private void ConfigureConcreteViewModel(yourConcreteModel model)
方法,用于分配GET方法和POST方法中需要的公共值,如果需要返回视图,则需要{/ 1}。