.net core, Azure, C# tip, Clean Code, Dependency Injection, Inversion of Control, MVC

Azure Cache as a session data store in C# and MVC

Using the HTTP Session is one of those things that provokes…opinions. A lot of developers think that sessions are evil. And whereas I understand some of the reasons why that’s a common viewpoint – I’ve had my share of problems with code that uses sessions in the past – I’d have to qualify any criticism by saying the problems were more about how I was using the technique, rather than any inherent problem with sessions as a concept.

For example, some instances where using an in-memory session store can cause problems are:

  • If you chuck lots of website data into an in-memory session, you’ll quickly eat up lots of RAM on your web server. This might eventually cause performance problems.
  • Sessions are often short lived – often around 20 minutes – leading to a poor user experience after a period of inactivity (like being unexpectedly logged out).
  • Also in a load balanced environment, users might experience issues – if their first request leads to a session being created on one web server, and then their next request is routed to a different (less-busy) web server, then it won’t know anything about their previous session. Apparently you can work around this with using sticky sessions…and my own experiences with the sticky sessions approach are best described as “mixed”. But YMMV.
  • If you’re not using SSL/TLS, your session might be vulnerable to the Man-in-the-Middle attack vector. But the easy answer to this is….use SSL.

Anyway – I think most people would agree with the basic need for one web page to access data entered on another web page. However, if you have high throughput, a need for a large session store, or a load balanced environment, then the out-of-the-box HTTP Session object might not be for you. But that doesn’t mean you can’t use sessions at all.

‘Azure Cache for Redis’ to the rescue

So even though my application isn’t in a load-balanced environment right now, I’d still like to make sure it’s easy to port to one in the future. So I’ve been looking for alternatives to using the Session object:

  • I could use Cookies, but I can’t store very much information in them.
  • I could use a SQL database, but this seems heavyweight for my need for shortlived session-based information.
  • Something like a NoSQL store like Redis would suit very well – it’s super fast with low-latency, high-throughput performance.

I’ve written about using Redis as a fast-access data store a long time ago, but that post is out of date now and worth updating as there’s now a built-in Azure option – Azure Cache for Redis.

Spinning up Azure Cache for Redis

Check out the official docs for how to create a cache in Azure – it’s clearly described here with lots of screenshots to guide you through.

But how can I using Azure Cache for Redis in a website?

I don’t really like the ASP.NET implementation from the official documentation. It works, but there’s a lot of code in the controller’s action, and I’d like a cleaner solution. Ideally I’d like to inject an interface into my controller as a dependency, and use ASP.NET Core’s service container to instantiate the dependency on demand.

I found this really useful post from Simon Holman, and he also has created a super helpful example on GitHub. I tested this with an MVC project in .NET Core v2.2, and the implementation is very simple (check out Simon’s source code for exactly where to put these snippets).

  • Update the Startup.cs file’s ConfigureServices method after putting the connection string into your appsettings.json file:
services.AddDistributedRedisCache(options =>
{
    options.Configuration = Configuration.GetConnectionString("RedisCache");
});
 
services.AddSession();
  • Update the Startup.cs file’s Configure method:
app.UseSession();
  • Here’s how to set data into the cache:
var sessionstartTime = DateTime.Now.ToLongTimeString();
HttpContext.Session.SetString("mysessiondata"sessionstartTime);
  • …get data from the cache:
var sessionstartTime = HttpContext.Session.GetString("mysessiondata");
  • …and remove data from the cache:
HttpContext.Session.Remove("mysessiondata");

Some things to bear in mind about Azure Cache for Redis

I wanted to dive into the details of Azure Cache a bit more, just to understand what’s actually going on beneath the hood when we’re reading from, and writing to, the session object.

You can see what session keys are saved in your Redis cache using the Azure portal

redis console arrow

Once you’re in the console, you run the command “scan 0 count 100 match *” to see up to the first 100 keys in your Redis cache.

redis console

From the screenshot above, I can see that I’ve got 16 sessions open.

The Guid in the Key is actually your Session’s *private* “_sessionKey”

In the image above, you can see a bunch of GUID objects which are the keys of the items in my Redis cache. And if you look at the 16th item in the list above, you can see that it corresponds to the private “_sessionKey” value, which is held in my HttpContext.Session object (compare with the VS2019 watch window below).

redis session

So this information is interesting…but I’m not sure how useful it is. Since that property is private, you can’t access it (well you can, but not easily, you have to use reflection). But it might be helpful to know this at debug time.

Browsers behave differently when in incognito mode

I thought I’d try the application with my browser in incognito mode. And every time I hit refresh on the browser when I was in incognito or private browsing mode, a new session key was created on the server – which meant it wasn’t able to obtain data from the session previously created in the same browser instance.

You can see the number of keys has hugely increased in the image below, corresponding to the number of times I hit refresh:

private window redis

But at least I can detect when the session isn’t available through the HttpContext.Session.IsAvailable property – when a session is available, the image below is what I can see in the session using a watch in the VS2019 debugger:

session available

And when a session isn’t available (such as when my browser is in incognito mode), this is what I see:

session unavailable

So at least I can programmatically distinguish between when the session can work for the user and when it can’t.

In summary, this behaviour had a couple of implications for me:

  • Session persistence didn’t work in incognito/private windows – values weren’t persistent in the same session across pages.
  • Hitting refresh a bunch of times in incognito will create lots of orphan session objects in your server, which might have security/availability implications for your application, especially if your sessions are large and fill up available memory.

Clearing down sessions was harder than I thought

HttpContext.Session.Clear() emptied my session, but didn’t delete the key from the server, as I could still see it in the Redis console.

In fact, the only way I was able to remove sessions held in Redis was to get right into the guts of the StackExchange.Redis package using the code below. Since I knew the exact session that I wanted to delete had the key “57154387-d8b7-c361-a174-9d27b6c6caae“:

var connectionMultiplexer = StackExchange.Redis.ConnectionMultiplexer.Connect(Configuration.GetConnectionString("RedisCache"));
 
connectionMultiplexer.GetDatabase(connectionMultiplexer.GetDatabase().Database).KeyDelete("57154387-d8b7-c361-a174-9d27b6c6caae");

But this is only useful if you can get the exact session key that you want to delete, and that isn’t particularly easy. You could use reflection to get that private value like in the code below, but I get why that’s not something you might want to do.

var _sessionKey = typeof(DistributedSession)
                .GetField("_sessionKey"BindingFlags.NonPublic | BindingFlags.Instance)
                .GetValue(HttpContext.Session);

Wrapping up

I’ve talked a little bit about sessions in this post – they’re not a magic hammer, but also aren’t inherently a bad tool – maybe consider an alternative to in-memory sessions if you have large session objects, or are working in a load balanced environment. Azure Cache for Redis might be one of those alternatives. I’ve found it to be interesting and useful, and relatively easy to set up as an alternative to an in-memory session, but there are a few quirks – sessions may not work the way you expect them to for users who are incognito/using private browsing, and it’s hard to completely delete a session once it has been created.

.net, C# tip, Clean Code, Dependency Injection, Inversion of Control, MVC, Solid Principles

How to use built-in dependency inversion in MVC6 and ASP.NET Core

I’ve previously posted about the new logging features in ASP.NET Core RC1 and MVC6. This time I’m going to write about how Microsoft now has dependency inversion baked into the new Core framework.

Dependency inversion is a well documented and understood principle – it’s what the D stands for in SOLID, and says that your code should only depend on abstractions, not concrete implementations. So plug your services into your application through interfaces.

ojfhi
No

In previous versions of MVC, I’ve needed to download a 3rd party library to assist with dependency inversion – these libraries are also sometimes called “containers”. Examples of containers I’ve used are NInject.MVC, Autofac, and Sprint.NET.

In MVC6, Microsoft has entered this field, by including a simple container in the new version of ASP.NET. This isn’t intended to replicate all the features of other containers – but it provides dependency inversion features which may be suitable for many projects. This allows us to avoid adding a heavyweight 3rd party dependency to our solution (at least until there’s a feature we need from it).

Getting started

For our example, first create the default MVC6 web application in Visual Studio 2015.

webapp1.png

Now let’s create a simple stubbed service and interface to get some users. We’ll save this in the “Services”folder of the project.

public interface IUserService
{
    IEnumerable<User> Get();
}

We’ll need a User object too – we’ll put this in the “Models” folder.

public class User
{
    public string Name { getset; }
}

Let’s create a concrete implementation of this interface, and save this in the “Services” folder too.

public class UserService : IUserService
{
    public IEnumerable<User> Get()
    {
        return new List<User>{ new User { Name = "Jeremy" } };
    }
}

Now modify the HomeController to allow us to display these users on the Index page – we need to change the constructor (to inject the interface as a class dependency), and to change the Index action to actually get the users.

public class HomeController : Controller
{
    private readonly IUserService _userService;
 
    public HomeController(IUserService userService)
    {
        _userService = userService;
    }
 
    public IActionResult Index()
    {
        var users = _userService.Get();
        return View(users);
    }
}

If we just run our project now, we’ll get an exception – the HomeController’s Index action is trying to get users, but the IUserService has not been instantiated yet.

error

We need to configure the services that the container knows about. This is where Microsoft’s new dependency inversion container comes in. You just need to add a single line of code in the ConfigureServices method in Startup.cs to make sure the controller is given a concrete instance of UserService when it asks the container “Can you give me something that implements IUserService?

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddTransient<IUserServiceUserService>();
}

If we run the project again now, we won’t get any exceptions – obviously we’d have to change the Index view to display the users.

Transient, Scoped, Singleton, Instance

In the example above, I used the “AddTransient” method to register the service. There’s actually 4 options to register services:

  • AddTransient
  • AddScoped
  • AddSingleton
  • AddInstance

Which option you choose depends on the lifetime of your service:

  • Transient services are created each time they are called. This would be useful for a light service, or when you need to guarantee that every call to this service comes from a fresh instantiation (like a random number generator).
  • Scoped services are created once per request. Entity Framework contexts are a good example of this kind of service.
  • Singleton services are created once and then every request after that uses the service that was created the first time. A static calculation engine might be a good candidate for this kind of service.
  • Instance services are similar to Singleton services, but they’re created at application startup from the ConfigureServices method (whereas the Singleton service is only created when the first request is made). Instantiating the service at startup would be useful if the service is slow to start up, so this would save the site’s first user from experiencing poor performance.

Conclusion

Microsoft have added their own dependency inversion container to the new ASP.NET Core framework in MVC6. This should be good enough for the needs of many ASP.NET projects, and potentially allows us to avoid adding a heavyweight third party IoC container.

.net, C# tip, Clean Code, Dependency Injection, Inversion of Control, MVC

How to use NLog or Serilog with C# in ASP.NET Core

ASP.NET core is still pretty new – at the time of writing, it’s still only at Release Candidate 1. I downloaded it for the first time a few days ago to play with the sample projects, and was surprised (in a good way) by how much has changed in the default project for MVC6. Of course the standard way of using Models, Views and Controllers is still similar to how it was in recent versions of MVC – but, the project infrastructure and configuration options are unrecognisably different (at least to me).

One of the first things I do when I set up a new project is configure the instrumentation – namely logging. I’d read a new feature of ASP.NET Core is that it provides built-in interfaces for logging – ILogger and ILoggerFactory.

This is a nice feature and provides me with an opportunity to write cleaner code. In previous versions of MVC, if I’d injected a logger interface into my controller classes, I still needed to introduce a dependency on a 3rd party library to every class that used this interface. So even though I’m injecting a dependency using an interface, if I changed logging library, I’d have to modify each of these classes anyway. Of course I could write a wrapper library for my 3rd party logging library, but I’d prefer not to have to write (and test) even more code.

Having the logging interface built into the framework gives me the opportunity to clean this up. So if I now want to add logging to my controller, I can write something like the code below. You can see this doesn’t have a dependency on a 3rd party library’s namespace – just a namespace provided by Microsoft.

using Microsoft.AspNet.Mvc;
using Microsoft.Extensions.Logging;
 
namespace WebApplication.Controllers
{
    public class HomeController : Controller
    {
        private ILogger<HomeController> _logger;
 
        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }
 
        public IActionResult Index()
        {
            _logger.LogInformation("Home controller and Index action - logged");
            return View();
        }

For this post, I created a default MVC6 project, and modified the HomeController to match the code above – I just added the bold text.

So how can we integrate third party libraries into an MVC6 project?

Configure the default ASP.NET MVC6 project to use NLog

Let’s configure NLog first.

Install-package NLog.Extensions.Logging -pre
  • Then we need to add a configuration file – nlog.config – to the root of our project. You can get a perfect example from github here – just remember to change the file locations in this config file to directories that exist in your environment.
  • Finally, modify the Startup.cs file’s Configure method by adding a couple of lines of code.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddNLog();
    env.ConfigureNLog("nlog.config");

Now just run the project – notice I didn’t need to make any changes to my HomeController class. My project created a log file named “nlog-all-2016-03-27.log” which has the text:

2016-03-27 00:27:29.3796|WebApplication.Controllers.HomeController|INFO|Home controller and Index action - logged

Configure the default ASP.NET MVC6 project to use Serilog

Let’s say for whatever reason – maybe you want to use message templates to structure your logging data – you decide that you’d prefer to use the Serilog library instead of NLog. What changes do I need to make to my project to accommodate this?

Previously, if I’d wanted to change logging library, I’d have had to change every class that logged something – probably remove a namespace inclusion of “using NLog” and add a new one of “using Serilog”, and maybe even change the methods used to log information.

But with Asp.NET Core, I don’t need to worry about that.

  • First I need to install a pre-release nuget package for Serilog;
     Install-package Serilog.Sinks.File -pre
  • Next, I need to modify the Startup.cs file in a couple of places – the first change goes into the Startup method:
public Startup(IHostingEnvironment env)
{
    // For Serilog
    Log.Logger = new LoggerConfiguration()
        .WriteTo.File(@"C:\users\jeremy\Desktop\log.txt")
        .CreateLogger();

The next change goes into the Configure method:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddSerilog();

That’s it – after running the project again, I had logs written to the file at C:\users\jeremy\Desktop\log.txt, showing the entry:

2016-03-27 00:01:46.923 +00:00 [Information] Home controller and Index action - logged

Obviously I can also safely remove the NLog packages and configuration that this point.

Conclusion

So you can see the new ASP.NET Core framework has made it super easy to swap out logging library dependencies. A big advantage for me is that the logging interface used by each file is now part of the framework that Microsoft provide, which means my classes aren’t tightly coupled to an implementation.