How to return an embedded static html file from an Asp.Net Core Controller?

Viewed 4278

I have the following configuration:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseDefaultFiles();

        app.UseFileServer(new FileServerOptions
        {
            FileProvider = new EmbeddedFileProvider(typeof(Startup).Assembly, typeof(Startup).Namespace + ".WebApp"),
            RequestPath = string.Empty
        });

        app.UseCors("CorsPolicy");

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "angular",
                defaults: new {controller = "Angular", action = "Index"},
                template: "{*url}");
        });
    }

My Angular project files are in the namespace MyNamespace.WebApp.

My AngularController and Startup classes are in the namespace MyNamespace

When I don't use MVC and access http://localhost:8000 it loads the index.html file in the WebApp folder. Now for all other requests (for example /action) I have mapped it to the AngularController, which looks as follows:

public class AngularController : Controller
{
    public IActionResult Index() {
        return View("/index.html");
    }
}

I have debugged and verified that the request does come to AngularController.Index() and returns View("/index.html"). But after that I get a 500 Error. I'm guessing because it cannot find the view file.

How do I let MVC know to fetch the index.html file from the embedded files?

I've tried the following:

return View("~/index.html");
return View("index.html");
return View("~/../index.html");
return View("../index.html");
return View("~/WebApp/index.html");
return View("WebApp/index.html");

None of these work. Probably I've missed a step?

2 Answers

In this example, I've tried to create an HTML file with the name htmlpage.html in the path Views/Home/htmlpage.html.

In the file Index.cshtml (path: Views/Home/Index.cshtml):

@using Microsoft.AspNetCore.Hosting
@using System.IO
@inject IHostingEnvironment environment
@{ 
    string htmlPath = "Views/Home/htmlpage.html";
}

@Html.Raw(File.ReadAllText(System.IO.Path.Combine(environment.ContentRootPath, htmlPath)))

In the file htmlpage.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>bar</title>
</head>
<body>
    <h3>foo</h3>
</body>
</html>

Test:

1


This way doesn't require: app.UseDefaultFiles(); and app.UseFileServer(...);

My solution was to configure a controller that would use an EmbeddedFileProvider and fetch the contents of the embedded file as follows:

public AngularController: Controller
{
    private IAppSettings appSettings;

    public AngularController(IAppSettings appSettings)
    {
        this.appSettings = appSettings;
    }

    public IActionResult Index()
    {
        var fileProvider = new EmbeddedFileProvider(this.appSettings.WebAssembly, this.appSettings.WebNamespace);
        var contents = this.fileProvider.GetDirectoryContents(string.Empty);

        IFileInfo index = null;
        foreach (var file in contents)
        {
            if (file.Name.Equals("index.html"))
            {
                index = file;
                break;
            }
        }

        if (index == null)
        {
            throw new Exception("'index.html' not found");
        }

        var reader = new StreamReader(index.CreateReadStream());
        var text = reader.ReadToEnd();
        return this.Content(text, "text/html");
    }
}

The Assembly and Namespace of the embedded files are provided using dependency injection to make it more generic. You could also hard code it into the controller.

Related