开发者

How do I Redirect to another Action/Controller in MVC3 from a VOID method?

I have a controller method that returns a void because it is b开发者_高级运维uilding an Excel report for the user to download. The Excel 3rd party library we're using is writing to the response itself. The method looks something like this:

[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 });
  }
}

There are several security checks in place that throw exceptions if the user doesn't meet certain credentials for fetching the report. I want to redirect to a different page and pass along some information about the exception, but I can't figure out how to do this in MVC3....

Any ideas?


You could use the following code

Response.Redirect(Url.Action("Error", "Report", new { exceptionType = ex.GetType().Name }));

But have you taken a look at the FilePathResult or FileStreamResult ?


Instead of letting the 3rd part library write to the response directly get the content use regular ActionResult and return File(...) for the actual file or RedirectToAction(...) (or RedirectToRoute(...)) on error. If your 3rd party library can only write to Response you may need to use some tricks to capture it's output.

[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  });
  }
}


You can return an 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 });    
      }

}

Not sure if it works, haven't tested it.


Another approach would be using an exception filter:

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"
        //    //..
        //};
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜