.Net MVC returning a File - asp.net-mvc

I'm working a Controller that will generate/retrieve files. These will optionally set headers.
public IActionResult SampleFileReport()
{
I see the return type is IActionResult (a data contract). I see inside the function I can still set
response.ContentType
Is there a preferred pattern for how to set ContentType in a controller?
I'm thinking it should be part of the DataContract and setting response.contentype is an anti-pattern, however I see examples such as this that utilize it. Returning a file to View/Download in ASP.NET MVC

All you need to do is return File:
public IActionResult SampleFileReport()
{
// do stuff
return File(bytes, mimetype, filename);
}
File also has overloads that accept Stream and string (path and filename to a file on the filesystem) in addition to byte[]. The mimetype is your content type, e.g. application/pdf, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet (Excel), etc. The final filename param is optional. If it's provided, a Content-Disposition: attachment header is sent with the response, which prompts the browser to pop a download dialog. Otherwise, the default Content-Disposition: inline is used, and the browser will try to load the returned file directly the browser tab/window, assuming the mime-type is supported for native rendering the browser. If not, then you'll get a download dialog, regardless.

If we are talking about MVC (not .NET Core) then you can change IActionResult to FileContentResult
public FileContentResult SampleFileReport()
{
byte[] fileBytes = GetFileBytes();
return File(fileBytes, MediaTypeNames.Application.Octet, "fileName");
}
Just checked this class still exists. FileContentResult .NET Core

Related

Asp.Net MVC ActionResult with File

In Asp.Net MVC, we need to show a Html page, but also when that page shows, download a file too as the result of a form post.
Is there a kind of ActionResult that both renders HTML, but also cause the browser to download a file? Think of a page that shows "Here's your requested file" and the file starts to download.
Basically a combination of ActionResult and FileResult in one.
Here's a controller example that returns a file. I added an Iframe to the view that targets the controller method. I set the hidden attribute so the iframe doesn't show anywhere in the page. Hope you can use the solution. It seems to work very smoothly.
[HttpGet]
public FileResult GetPDF()
{
string fileName = "test.pdf";
string filePath = HttpContext.Server.MapPath(string.Format("~/Content/{0}", fileName));
byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
Add the following code to your view.
<iframe hidden="hidden" src="#Url.Content("~/Home/Home/GetPDF")"></iframe>

MVC Post Form, but optionally return download or content

So I have a form action, that uploads a document and process it...
[HttpPost]
public ActionResult Upload(FormCollection col)
{}
But I want to either return and download (NOT A LINK) but rather the download just starts, OR some html content to show the user on the page.
What should I return, and do I need to change the attribute ( HttpPost ) ?
This is the code that you can put in your Action-Method.
bool shouldDownload = true;
if (shouldDownload)
{
Response.AddHeader("Content-disposition", "attachment; filename=guitars_11.jpg");
return File(#"c:\Temp\guitars_11.jpg", "image/jpeg");
}
else
{
return View();
}
The [HttpPost] attribute can stay - it only has an affect on routing (if the request is a POST request, the action will be invoked). It has no influence on what is returned.
Ultimately whether you deliver an HTML page or file back to the browser it's all just HTTP.
You need only set the content-type http response header to the proper mime type for the file, and optionally set the content-disposition header to set the filename ( http download file name).

Allow direct access to some file/content in Asp.Net MVC

In my Asp.Net MVC application, I am using a customized template of twitter bootstrap.
I have placed this template folder named "b3-detail-admin" on root of my mvc application.
Using Browser's address bar, when I am trying to access one file directly from this folder like so:
http://my-pc/MyWebAppMvc/b3-detail-admin/font/fontawesome-webfont.woff
I am getting following error:
HTTP Error 404.3 - Not Found
The page you are requesting cannot be served because of the extension configuration. If the page is a script, add a handler. If the file should be downloaded, add a MIME map.
What should I do to have direct access to all files/folders under "b3-detail-admin" folder?
In mvc you can only get access to the routes defined in RouteConfig.
You can add a ActionResult which returns the document like so:
public ActionResult GetPdf()
{
string file = Server.MapPath("~/folder/file.pdf");
return File(file, "application/pdf", "file.pdf");
}
You then can make it dynamic to get all sorts of files:
public ActionResult GetFile(string url, string mime)
{
string file = Server.MapPath(url);
string filename = url.Split(new char[]{'/'})[url.Split(new char[]{'/'}).Count()];
return File(file, "mime", filename);
}

Consuming a click-once application from an MVC controller/action

I am using an MVC controller/action located in /myServer/myArea/MyClickOnce/Open that returns a FileResult
public class MyClickOnceController : Controller
{
public FileResult Open()
{
FilePathResult file = new FilePathResult("/Provisioning/4843EA3F-9138-4A0D-9D33-BF4CDDEB7C7E/MyClickOnce.application", "application/x-ms-application");
return file;
}
}
this works fine for the initial loading, but then click-once makes a subsequent request to:
/myServer/myArea/MyClickOnce/9.0.0.132/MyClickOnce.exe.manifest
This path doesn't actually exist because the physical path for the click once is in:
/Provisioning/4843EA3F-9138-4A0D-9D33-BF4CDDEB7C7E/*
so it exists here:
/Provisioning/4843EA3F-9138-4A0D-9D33-BF4CDDEB7C7E/9.0.0.132/MyClickOnce.exe.manifest
Should I be using routing to redirect all these subsequent requests? Is there a better approach to consume a click-once application from and MVC controller/action?
If you use a RedirectResult, the subsequent requests to the ClickOnce manifest and other files get routed to the correct directory.
public ActionResult Open()
{
string path = "/Provisioning/4843EA3F-9138-4A0D-9D33-BF4CDDEB7C7E/MyClickOnce.application";
return new RedirectResult(path);
}

ASP.NET MVC - How to obtain file from FileResult?

Short version:
I have a third-party MVC Extension that returns the FileResult. I would like to be able to process the file before returning it to the client. How can I do that?
If you're interested in boring details, read below:
I'm using Devexpress XtraReports for reporting purposes. The problem is that it's PDF Export is terrible, but RTF one works great. I would like to create action&result filter that would trick DevExpress into generating rtf instead of pdf (done) and convert the rtf to pdf using some other third-party library. The only problem is that I need to obtain rtf file from FileResult and return my own FileResult with the converted content.
//EDIT:
The code right now looks as follows:
public virtual ActionResult ReportExport(TParameters parameters)
{
return DevExpress.Web.Mvc.ReportViewerExtension.ExportTo(this.GetReport(parameters));
}
You said you are using a third-party MVC extension that returns a FileResult and you want to access the file details that are wrapped inside the result.
If you see the FileResult, it is an abstract class and I just know there are three built-in implementations are available in MVC (I don't aware about others): FileContentResult, FileStreamResult and FilePathResult.
All these classes provide public properties to access the details of the file. For ex. the FileContentResult contains a public property called FileContents that returns the content of a file as a byte array.
The third-party extension can return any FileResult implementation of the built-in types or badly(if you can't access those type) their own types as well. You can check the returned FileResult instance's type and cast it accordingly to access the file details.
var fileResult = ... returned by the MVC extension
if(fileResult is FileContentResult)
{
var fileContentResult = fileResult as FileContentResult;
var fileContent = fileContentResult.FileContents;
// process the file
}
else if(fileResult is FileStreamResult)
{
var fileStreamResult = fileResult as FileStreamResult;
var fileStream = fileStreamResult .Stream;
//...
}
else if(fileResult is FilePathResult) // this result only contains the path
// of the file name
{
//...
}
If you want make the things reusable you can implement a custom file result that takes the FileResult returned by the extension in the constructor and override the WriteFile method.
The FileResult probably writes the file contents to the response stream. You can use a standard ASP.NET response stream using a filter. See this ancient article for details:
https://web.archive.org/web/20211029043851/https://www.4guysfromrolla.com/articles/120308-1.aspx
Alternatively you could create your own ActionResult that invokes the DevExpress FileResult using a custom HttpContext with a fake response stream, which is where you would do your conversion.

Resources