Showing posts with label .netcore. Show all posts
Showing posts with label .netcore. Show all posts

Wednesday, February 08, 2017

Reloading configuration in .NET core

Being able to reload configuration on change is typically a key requirement. ASP.NET core configuration infrastructure provides a reloadOnChange property that you can set:

var builder = new ConfigurationBuilder()
    .SetBasePath(env.ContentRootPath)
    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
    .AddEnvironmentVariables();
Configuration = builder.Build();

However, your application still has to handle the change. In asp.net core, this is via a IChangeToken and the Configuration class provides a GetReloadToken().RegisterChangeCallback - the only trouble is that this is fired only once since the change token can change.

The easy way around this is to use the ChangeToken utility - like so:


var valuesConfig = new ValuesConfig();
Configuration.GetSection("ValuesConfig").Bind(valuesConfig);
services.AddSingleton(valuesConfig);
Action onChange = () =>
{
    Configuration.GetSection("ValuesConfig").Bind(valuesConfig);
    Console.WriteLine("onChange fired!");
};

ChangeToken.OnChange(() => Configuration.GetReloadToken(), onChange);

What's interesting though that while this works, the on change handler ends up getting called twice for each change!

Monday, February 06, 2017

Building slim .NET core docker images

As I play with .NET core, I was getting a little frustrated with waiting for docker build and docker push to complete - the docker images for .net core are pretty large - weighing in at a gig as shown below. My trivial web service is hardly 80mb with dependencies - so this did not feel good at all.
rraghur/webapi-app                                    v3                  9ff77929c379        25 hours ago        976.5 MB
The .net project template sets up a Dockerfile - and while this is great, it's geared more towards development rather than production. It goes something like this:
FROM microsoft/dotnet:latest

COPY . /app
WORKDIR /app
RUN ["dotnet", "restore"]
RUN ["dotnet", "build"]
EXPOSE 5000/tcp
CMD ["dotnet", "run", "--server.urls", "http://*:5000"]
Here's the trouble - it basically needs the sdk and builds and runs the app inside the container. Also problematic is that the source is pushed inside the container. What if we just push binaries and use only the runtime?
First, make the app self-contained (SCD). In project.json, you need to remove the platform dependency type (since the platform's going to be packaged with the app). Then also add ubuntu.14.04-x64 under runtimes -
 "runtimes": {
    "win81-x64": {},
    "ubuntu.14.04-x64": {},
    "debian.8-x64": {}
  },
Second, let's publish - dotnet publish -r ubuntu.14.04-x64. This will generate the app with all dependencies in bin/debug/netcoreapp1.1/ubuntu-14.04-x64/publish
Finally, let's update the docker file to package this in:
FROM microsoft/dotnet:1.1-runtime-deps

COPY ./bin/Debug/netcoreapp1.1/ubuntu.14.04-x64/publish /app

WORKDIR /app

EXPOSE 5000/tcp

CMD ["./WebAPIApplication", "--server.urls", "http://*:5000"]
With the above, a docker build results in a much more svelte 230MB image - that's a 76% reduction in fat :)!
rraghur/webapi-app                                    v5                  815cbcecaea9        19 seconds ago      230.8 MB
Let's take it out for a spin:
D:\WebAPIApplication>docker run -it --rm rraghur/webapi-app:v5
Hosting environment: Production
Content root path: /app
Now listening on: http://*:5000
Application started. Press Ctrl+C to shut down.
Keep shipping!