Embedded Static Pages Library CSharp DotNetCore

Dec 20th, 2019 - written by Kimserey with .

In today post we will explore one of the technique used in ASP NET Core libraries to share static content (like html pages) in the form of a library.

Embedded Resource

Embedded Resource are specified via the property menu which will change the .csproj.

We start first by creating a library and a Hello World html page that we place under /static.

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>
<body>
    Hello World
</body>
</html>

Then we set the file as embedded resource:

1
2
3
4
<ItemGroup>
    <None Remove="HelloWorld\static\index.html" />
    <EmbeddedResource Include="HelloWorld\static\index.html" />
</ItemGroup>

From now on when we build the solution, the html file will be contained in the dll.

To access it, we use the EmbeddedFileProvider from Microsoft.Extensions.FileProviders.Embedded.

1
2
3
4
5
6
7
public static class HelloWorldExtensions
{
    public static readonly IFileProvider Provider = new EmbeddedFileProvider(
        typeof(HelloWorldExtensions).GetTypeInfo().Assembly,
        "HelloWorld"
    );
}

The file provider will allow us to lookup for embedded resources within the assembly provided and using the base namespace.

1
2
3
4
public static IFileInfo GetFile()
{
    return Provider.GetFileInfo("static.index.html");
}

Now that we know how to embed files and how to extract them, we can look into how to provide a reusable ASP NET Core middleware which will allow us to register our Hello World page easily.

Static Middleware

A middleware in ASP NET Core is a piece of logic handling requests. Middlewares are meant to be composable where they either wrap other middlewares or get plugged in between middlewares or short circuit the response flow.

For our example we want to provide a middleware which when registered will add a Hello World page route.

We start by adding the library necessary to build the extensions:

1
Microsoft.AspNetCore.Http.Abstractions

which gives us the ability to extend IApplicationBuilder, and

1
Microsoft.AspNetCore.Routing

which gives us access to the extensions to register the router.

1
2
3
4
5
6
7
8
9
10
public static IApplicationBuilder UseHelloWorldPage(this IApplicationBuilder app)
{
    return app.UseRouter(router => {
        router.MapGet("helloworld", async context =>
        {
            context.Response.ContentType = "text/html";
            await context.Response.SendFileAsync(HelloWorldExtensions.GetFile());
        });
    });
}

We extend the application builder by adding a UseHelloWorldPage which will route GET /helloworld to the middleware function sending the static file with a content type header of text/html.

Usage

We can now simply reference the library and use the extension in our Startup.cs of our ASP NET Core application:

1
2
3
4
5
6
7
8
9
10
11
    public class Startup
    {
        // ... rest of startup

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            // ... rest of configure

            app.UseHelloWorldPage();
        }
    }

app.UseHelloWorldPage() will register the middleware from the Hello World library and we will then be able to access the index.html from /helloworld.

From this simple example, we can imagine how this technique can be used to share static assets via Nuget packages for different projects. Sharing UI middlewares is very common, one of the biggest library of dotnet Swashbuckle.AspNetCore uses this technique to share their Swagger UI implementation. By adding .UseSwaggerUI(...) we register the /swagger UI endpoint.

And that concludes today’s post!

Conclusion

Today we saw what embedded resources where in dotnet, we started by looking at how we could embed a html page and how we could retrieve it from the assembly. We then moved on to create an extensions middleware for ASP NET Core and lastly we completed the post by looking at how our extension could be used. I hope you like this post and I see you on the next one!

External Sources

Designed, built and maintained by Kimserey Lam.