How to serve html file from another directory as ActionResult

52.1k views Asked by At

I have a specialised case where I wish to serve a straight html file from a Controller Action.

I want to serve it from a different folder other than the Views folder. The file is located in

Solution\Html\index.htm

And I want to serve it from a standard controller action. Could i use return File? And how do I do this?

6

There are 6 answers

4
lucask On BEST ANSWER

If you want to render this index.htm file in the browser then you could create controller action like this:

public void GetHtml()
{
    var encoding = new System.Text.UTF8Encoding();
    var htm = System.IO.File.ReadAllText(Server.MapPath("/Solution/Html/") + "index.htm", encoding);
    byte[] data = encoding.GetBytes(htm);
    Response.OutputStream.Write(data, 0, data.Length);
    Response.OutputStream.Flush();
}

or just by:

public ActionResult GetHtml()
{
    return File(Server.MapPath("/Solution/Html/") + "index.htm", "text/html"); 
}

So lets say this action is in Home controller and some user hits http://yoursite.com/Home/GetHtml then index.htm will be rendered.

EDIT: 2 other methods

If you want to see raw html of index.htm in the browser:

public ActionResult GetHtml()
{
    Response.AddHeader("Content-Disposition", new System.Net.Mime.ContentDisposition { Inline = true, FileName = "index.htm"}.ToString());
    return File(Server.MapPath("/Solution/Html/") + "index.htm", "text/plain"); 
}

If you just want to download file:

public FilePathResult GetHtml()
{
    return File(Server.MapPath("/Solution/Html/") + "index.htm", "text/html", "index.htm"); 
}
2
Wahid Bitar On

Check this out :

    public ActionResult Index()
    {
        return new FilePathResult("~/Html/index.htm", "text/html");
    }
0
Abhijit-K On

Can you read the html file in a string and return it in action? It is rendered as Html page as shown below:

public string GetHtmlFile(string file)
{
    file = Server.MapPath("~/" + file);
    StreamReader streamReader = new StreamReader(file);
    string text = streamReader.ReadToEnd();
    streamReader.Close();
    return text;
}

Home/GetHtmlFile?file=Solution\Html\index.htm

If the destination or storage mechanism of HTML files is complicated then you can you Virtual path provider

Virtual path provider MVC sample

0
Ognyan Dimitrov On

I want put my two cents in. I have found this most terse and it is there already :

public ActionResult Index()
{
     var encoding = new System.Text.UTF8Encoding();
     var html = ""; //get it from file, from blob or whatever
     return this.Content(html, "text/html; charset=utf-8");
}
0
om471987 On

I extended wahid's answer to create HtmlResult

Create Html Result which extends FilePathResult

public class HtmlResult : FilePathResult
{
    public HtmlResult(string path)
        : base(path, "text/html")
    {
    }
}

Created static method on controller

public static HtmlResult Html(this Controller controller, string path)
{
    return new HtmlResult(path);
}

used like we return view

public HtmlResult Index()
{
    return this.Html("~/Index.html");
}

Hope it helps

0
Jason On

Alternative approach if using .net core is to use a FileProvider. The files could be in a folder or embedded at compile time.

In this example we will use embedded files.

Add a folder in your project let's say assets, in it create a file myfile.html, add some basic html to the file say

<html>
<head>
  <title>Test</title>
</head>
<body>
   Hello World
</body>
</html>

Right click on the new file (assuming you are in visual studio) select properties, in the properties screen / build action, select embedded resource. It will add the file to the csproj file.

Right click on your project, edit your csproj file. Check that your property group contains the following:

<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>

If not please add it. The csproj should also contain the newly created html file as:

  <ItemGroup>
    <EmbeddedResource Include="assets\myfile.html" />
  </ItemGroup>

To read the file in your controller and pass it to the client requires a file provider which is added to the startup.cs

Edit your startup.cs make sure it includes the HostingEnvironment:

private readonly IHostingEnvironment HostingEnvironment;
public Startup(IHostingEnvironment hostingEnvironment)
{
     HostingEnvironment = hostingEnvironment;
}

Then create a file provider and make it a service that can be injected at runtime. Create it as follows:

 var physicalProvider = HostingEnvironment.ContentRootFileProvider;
 var manifestEmbeddedProvider =
      new ManifestEmbeddedFileProvider(Assembly.GetEntryAssembly());
 var compositeProvider =
      new CompositeFileProvider(physicalProvider, manifestEmbeddedProvider);

 services.AddSingleton<IFileProvider>(compositeProvider);

To serve the file go to your controller, use dependency injection to get the FileProvider, create a new service and serve the file. To do this, start with dependency injection by adding the provider to your constructor.

IFileProvider _fileProvider;
public MyController(IFileProvider fileProvider)
{
    this._fileProvider = fileProvider;
}

Then use the file provider in your service

[HttpGet("/myfile")]
[Produces("text/html")]
public Stream GetMyFile()
{
   // Use GetFileInfo to get details on the file passing in the path added to the csproj
   // Using the fileInfo returned create a stream and return it.
   IFileInfo fileinfo = _fileProvider.GetFileInfo("assets/myfile.html");
   return fileinfo.CreateReadStream();
}

For more info see ASP .Net Core file provider sample and the Microsoft documentation here.