ASP.NET MVC 4 FileResult - In error
Asked Answered
G

4

13

I have a simple Action on a controller which returns a PDF.

Works fine.

public FileResult GetReport(string id)
{
    byte[] fileBytes = _manager.GetReport(id);
    string fileName = id+ ".pdf";
    return File(fileBytes, MediaTypeNames.Application.Octet, fileName);
}

When the manager fails to get the report I get back null or an empty byte[].

How can I communicate to the browser that there was a problem, when the result is set to a FileResult?

Grouping answered 2/12, 2013 at 18:53 Comment(1)
Possible duplicate of How to return error message from FileResult method in asp.net MVC 4 application?Turney
S
32

I would change the return type of your method to ActionResult.

public ActionResult GetReport(string id)
{
    byte[] fileBytes = _manager.GetReport(id);
    if (fileBytes != null && fileBytes.Any()){
        string fileName = id+ ".pdf";
        return File(fileBytes, MediaTypeNames.Application.Octet, fileName);
    }
    else {
        //do whatever you want here
        return RedirectToAction("GetReportError");
    }
}
Surplus answered 2/12, 2013 at 19:2 Comment(3)
Looks like I was too late. :DTengdin
It will redirect to Action. How we can show Error dialog?Atomic
If you want to show a dialog you need to implement some sort of AJAX communication on your page.Surplus
T
13

The FileResult class inherits from ActionResult. So, you can define your Action like this:

public ActionResult GetReport(string id)
{
    byte[] fileBytes = _manager.GetReport(id);
    string fileName = id + ".pdf";

    if(fileBytes == null || fileBytes.Length == 0)
       return View("Error");

    return File(fileBytes, MediaTypeNames.Application.Octet, fileName);
}
Tengdin answered 2/12, 2013 at 19:18 Comment(0)
C
8

If you want to "communicate to the browser" that there was an error, the standard "HTTP way" is to return status code 500, especially if your request is invoked using Ajax, so that you can gracefully handle the exception.

I would suggest to simply throw an Exception when no report found for the provided id:

public FileResult GetReport(string id)
{
    // could internally throw the Exception inside 'GetReport' method
    byte[] fileBytes = _manager.GetReport(id);

    // or...
    if (fileBytes == null || !fileBytes.Any())
          throw new Exception(String.Format("No report found with id {0}", id));

    return File(fileBytes, MediaTypeNames.Application.Octet, fileName = id+ ".pdf");
}

Explicitly redirecting to an error page or returning a ViewResult is not the best approach in ASP.NET MVC as this is usually the role of the HandleError filter (which is applied by default) that can be easily configured to either redirect or render some View with the Exception details (while still maintaining HTTP status 500).

This is all true assuming that a failure to fetch a report is indeed considered an exception. If it's not (for example, if we expect some report to not have an available file to dump), explicitly returning a Redirect/View result is totally acceptable.

Chunky answered 2/12, 2013 at 19:26 Comment(0)
K
3

Another workaround for handling prerequisites is to split download process into two stages. First is to check preconditions in server side method which is executed as ajax/post method.

Then if these preconditions are fulfilled you can start download request (e.g. in onSuccess callback where it is checked the return value indicating fulfillment) in which (on server side) you will handle potential exceptions in a way as it was described in above posts.

Kale answered 27/7, 2015 at 22:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.