我有一个返回void的控制器方法,因为它正在构建一个Excel报告供用户下载。我们正在使用的Excel第三方库正在写入响应本身。该方法如下所示:
[HttpGet]
public void GetExcel(int id)
{
try
{
var report = _reportService.GetReport(id);
var table = _reportService.GetReportTable(id);
var excelReport = new ExcelReport(table, report.Name);
excelReport.DownloadReport(System.Web.HttpContext.Current.Response);
}
catch (Exception ex)
{
// This is wrong, of course, because I'm not returning an ActionResult
Response.RedirectToRoute("/Report/Error/", new { exceptionType = ex.GetType().Name });
}
}
如果用户未获得用于获取报告的特定凭据,则会进行多项安全检查以引发异常。我想重定向到另一个页面并传递有关异常的一些信息,但我无法弄清楚如何在MVC3中执行此操作....
有什么想法吗?
答案 0 :(得分:8)
你可以做一个
Response.Redirect(Url.Action("Error", "Report", new { exceptionType = ex.GetType().Name });
但是你看过FilePathResult或FileStreamResult了吗?
答案 1 :(得分:2)
不是让第三方库直接写入响应,而是让内容使用常规ActionResult
并返回File(...)
作为实际文件或RedirectToAction(...)
(或RedirectToRoute(...)
)出错了。如果您的第三方库只能写入Response,您可能需要使用一些技巧来捕获它的输出。
[HttpGet]
public ActionResult GetExcel(int id)
{
try
{
var report = _reportService.GetReport(id);
var table = _reportService.GetReportTable(id);
var excelReport = new ExcelReport(table, report.Name);
var content = excelReport.MakeReport(System.Web.HttpContext.Current.Response);
return File(content, "application/xls", "something.xls");
}
catch (Exception ex)
{
RedirectToRoute("/Report/Error/", new { exceptionType = ex.GetType().Name });
}
}
答案 2 :(得分:2)
您可以返回EmptyActionResult:
[HttpGet]
public ActionResult GetExcel(int id)
{
try
{
var report = _reportService.GetReport(id);
var table = _reportService.GetReportTable(id);
var excelReport = new ExcelReport(table, report.Name);
excelReport.DownloadReport(System.Web.HttpContext.Current.Response);
return new EmptyResult();
}
catch (Exception ex)
{
return RedirectToAction("Error", "Report", rnew { exceptionType = ex.GetType().Name });
}
}
不确定它是否有效,尚未测试过。
答案 3 :(得分:0)
另一种方法是使用异常过滤器:
public class MyExceptionFilter : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
var routeValues = new RouteValueDictionary()
{
{ "controller", "Error" },
{ "action", "Report" }
};
filterContext.Result = new RedirectToRouteResult(routeValues);
filterContext.ExceptionHandled = true;
// Or I can skip the redirection and render a whole new view
//filterContext.Result = new ViewResult()
//{
// ViewName = "Error"
// //..
//};
}
}