The setting - Steve's post in brief

I recommend you read Steve's post first, but the key points to this discussion are described below.

Steve wanted to ensure that HTML POSTed inside a JSON string property was automatically HTML encoded, so that potentially malicious script couldn't be stored in the database. This wouldn't necessarily be something you'd always want to do, but it worked for his use case. It ensured that a string such as

by the time it was received in an Action method. He describes creating a custom ContractResolver and ValueProvider to override the CreateProperties method and automatically encode any string properties.

The section I am interested in is where he wires up his new resolver and provider using a small extension method UseHtmlEncodeJsonInputFormatter. This requires providing a number of services in order to correctly create the JsonInputFormatter. I have reproduced his extension method below:

For the full details of this method, check out his post. For our discussion, all that's necessary is to appreciate that we are modifying the MvcOptions by adding a new JsonInputFormatter, and that to do so we need instances of an ILogger<T> and ObjectPoolProvider.

The need for these services is a little problematic - we will be calling this extension method when we are first configuring MVC, within the ConfigureServices method, but at that point, we don't have an easy method of accessing other configured services.

The approach Steve used was to build a service provider, and then create the required services using it, as shown below:

This approach works, but it's not the cleanest, and luckily there's a handy alternative!

What does AddMvc actually do?

Before I get into the cleaned up approach, I just want to take a quick diversion into what the AddMvc method does. In particular, I'm interested in the overload that takes an Action<MvcOption> setup action.

Taking a look at the source code, you can see that it is actually pretty simple:

This overload calls AddMvc() without an action, which returns an IMvcBuilder. We then call Configure with the Action<> to configure an instance of MvcOptions.

ConfigureOptions to the rescue!

When I saw the Configure call, I immediately thought of a post I wrote previously, about using ConfigureOptions to inject services when configuring IOptions implementations.

Using this technique, we can avoid having to call BuildServiceProvider inside the ConfigureServices method, and can leverage dependency injection instead by creating an instance of IConfigureOptions<MvcOptions>.

Implementing the interface is simply a case of calling our already defined extension method, from within the required Configure method:

With this configuration in place, we have the same behaviour as before, just with some nicer wiring in the Setup class! For a more detailed explanation of why this works, check out my previous post.

Summary

This post was a short follow-up to a post by Steve Gordon in which he showed how to create a custom JsonInputFormatter. I showed how you can use IConfigureOptions<> to use dependency injection when adding MvcOptions as part of your MVC configuration.