Month: December 2017

Azure Functions v2 Preview Performance Issues (.NET Core / Standard)

I’ve been spending a little time building out a serverless web application as a small holiday project and as this is just a side project I’d taken the opportunity to try out the new .NET Core based v2 runtime for Azure Functions and the new tooling and support in Visual Studio 2017.

As soon as I had an end to end vertical slice I wanted to run some load tests to ensure it would scale up reliably – the short version is that it didn’t. The .NET Core v2 runtime is still in preview (and you are warned not to use this environment for production workloads due to potential breaking changes) so you would hope that this will get fixed by general release but right now there seem to be some serious shortcomings in the scalability and performance of this environment rendering it fairly unusable.

I used the VSTS load testing system to hit a single URL initially with a high volume of users for a few minutes. In isolation (i.e. if I run it from a browser with no activity) this function runs in less than 100ms and normally around the 70ms mark however as the number of users increases performance quickly takes a serious nosedive with requests taking seconds to return as can be seen below:

After things settled down a little (hitting a system like this from cold with a high concurrency is going to cause some chop while things scale out) average request time began to range in the 3 to 9 seconds and the anecdotal experience (me running it in a browser / PostMan while the test was going on) gave me highly variable performance. Some requests would take just a few hundred milliseconds while others would take over 20 seconds.

Worryingly no matter how long the test was run this never improved.

I began by looking at my code assuming I’d made a silly mistake but I couldn’t see anything and so boiled things down to a really simple test case, essentially the one that is created for you by the Visual Studio template:

[FunctionName("GetString")]
public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)]HttpRequest req, TraceWriter log)
{
    log.Info("C# HTTP trigger function processed a request.");

    var result = new OkObjectResult("hello world");

    return (IActionResult)result;
}

I expected this to scale and perform much better as it’s as simple as it gets: return a hard coded string. However to my surprise this exhibited very similar issues:

The response time, to return a string!, hovered around the 7 second mark and the system never really scaled sufficiently to deal with a small percentage of failures due to the volume.

Having run a fair few tests and racking up a lot of billable virtual user minutes on my credit card I tweaked the test slightly at this point moving to a 5 minute test length with step up concurrent user growth. Running this on the same simple test gave me, again, poor results with average response times of between 1.5 and 2 seconds for 100 concurrent users and a function that is as close to doing nothing as it gets (the response time is hidden by the page time in the performance chart below, it tracks almost exactly). The step up of users to a fairly low volume eliminates the errors, as you’d expect.

What these graphs don’t show are variance around this average response time which still ranged from a few hundred milliseconds up to around 15 seconds.

At this point I was beginning to suspect the Functions 2.0 preview runtime might be the issue and so created myself a standard Functions 1.0 runtime and deployed this simple function as a CSX script:

using System.Net;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    var response = req.CreateResponse();
    response.StatusCode = HttpStatusCode.OK;
    response.Content = new StringContent("hello world", System.Text.Encoding.UTF8, "text/plain");

    return response;
}

Running the same ramp up test as above shows that this function behaves much more as you’d expect with average response times in the 300ms to 400ms range when running at 100 concurrent users:

Intrigued I did run a short 5 minute 400 concurrent user test with no ramp up and again the csx based function behaved much more in line with what I think are reasonable expectations with it taking a short time to scale up to deal with the sudden demand but doing so without generating errors and eventually settling down to a response time similar to the test above:

Finally I deployed a .NET 4.6 based function into a new 1.0 runtime Function app. I made a slight mistake when setting up this test and ramped it up to 200 users rather than 100 but it scales much more as you’d expect and holds a fairly steady response time of around 150ms. Interestingly this gives longer response times than .NET Core for single requests run in isolation around 170ms for .NET 4.6 vs. 70ms for .NET Core.

At this point I felt fairly confident that the issue I was seeing in my application was due to the v2 Function runtime and so made a quick change to target .NET 4.6 instead and spun up a new v1 runtime and ran my initial 400 concurrent user test again:

As the system scales up, giving no errors, this test eventually settles at around the 500ms average request per second mark which is something I can move ahead with. I’d like to get it closer to 150ms and it will be interesting to see what I can tweak so I can on the consumption plan as I think I’m starting to bump up against some of the other limits with Functions (ironically resolving that involves taking advantage of what is actually going on with the Functions runtime implementation and accepting that its a somewhat flawed serverless implementation as it stands today).

As a more general conclusion the only real takeaway I have from the above (beyond the general point that it’s always worth doing some basic load testing even on what you assume to be simple code) is that the Azure Function 2.0 runtime has some way to go before it comes out of Preview. What’s running in Azure currently is suitable only for the most trivial of workloads – I wouldn’t feel able to run this even in a beta system today.

Something else I’d like to see from Azure Functions is a more aggressive approach to scaling up/out, for spiky workloads where low latency is important there is a significant drag factor at the moment. While you can run on an App Service Plan and handle the scaling yourself this kind of flies in the face of the core value proposition of serverless computing – I’m back to renting servers. A reserved throughput or Premium Consumption offering might make more sense.

I do plan on running these tests again once the runtime moves out of preview – I’m confident the issue will be fixed, after all to be usable as a service it basically has to be.

C# Cloud Application Architecture – Commanding via a Mediator (Part 3)

In the previous post we simplified our controllers by having them accept commands directly and configured ASP.Net Core so that consumers of our API couldn’t insert data into sensitive properties. However we’ve not yet set up any validation so, for example, it is possible for a user to add a product to a cart with a negative quantity. We’ll address that in this post and take a look at an alternative to the attribute model of validation that comes out the box with ASP.Net and ASP.Net Core.

The source code for this post can be found on GitHub:

https://github.com/JamesRandall/CommandMessagePatternTutorial/tree/master/Part3

The built in ASP.Net Core approach to validation, like previous versions, relies on a model being annotated with attributes but there are some significant drawbacks with this approach:

  1. You need access to the source code to add the attributes – sometimes this isn’t possible and so you end up maintaining multiple sets of models just to express validation rules.
  2. It requires you to tightly couple your model to a specific validation system and set of validation rules and include additional dependencies that may not be appropriate everywhere you want to use the model.
  3. It’s extensible but not particularly elegantly and complicated rules are hard to implement.

Depending on your application architecture maintaining multiple sets of model can be a good solution to some of these issues, and might be the right thing to do for your architecture in any case (for example you certainly don’t want Entity Framework models bleeding out through an API for example) but in our scenario there’s little to be gained by maintaining multiple representations of commands, at least in the general sense.

An excellent alternative framework for validation is Jeremy Skinner’s Fluent Validation package set. This allows validation rules to be expressed separately from models, hooks into the ASP.Net Core pipeline to support the standard ModelState approach, and allows validations to be run easily from anywhere.

We’re going to continue to follow our application encapsulation model for adding validations and so we will add a validator package to each domain, for example ShoppingCart.Validation. Each of these assemblies will consist of private classes for the validators that are registered in the IoC container using an installer. Below is an example of the validator for our AddToCartCommand command:

internal class AddToCartCommandValidator : AbstractValidator<AddToCartCommand>
{
    public AddToCartCommandValidator()
    {
        RuleFor(c => c.ProductId).NotEqual(Guid.Empty);
        RuleFor(c => c.Quantity).GreaterThan(0);
    }
}

This validator makes sure that we have a none-empty product ID and specify a quantity of 1 or more. We register this in our installer as follows:

public static class IServiceCollectionExtensions
{
    public static IServiceCollection RegisterValidators(this IServiceCollection serviceCollection)
    {
        serviceCollection.AddTransient<IValidator<AddToCartCommand>, AddToCartCommandValidator>();
        return serviceCollection;
    }
}

The ShoppingCart.Validation assembly is referenced only from the ShoppingCart.Application installer as shown below:

public static class IServiceCollectionExtensions
{
    public static IServiceCollection UseShoppingCart(this IServiceCollection serviceCollection,
        ICommandRegistry commandRegistry)
    {
        serviceCollection.AddSingleton<IShoppingCartRepository, ShoppingCartRepository>();

        commandRegistry.Register<GetCartQueryHandler>();
        commandRegistry.Register<AddToCartCommandHandler>();

        serviceCollection.RegisterValidators();

        return serviceCollection;
    }
}

And finally in our ASP.Net Core project, OnlineStore.Api, in the Startup class we register the Fluent Validation framework – however it doesn’t need to know anything about the specific validators:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(c =>
    {
        c.Filters.Add<AssignAuthenticatedUserIdActionFilter>();
        c.AddAuthenticatedUserIdAwareBodyModelBinderProvider();
    }).AddFluentValidation();

    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new Info { Title = "Online Store API", Version = "v1" });
        c.SchemaFilter<SwaggerAuthenticatedUserIdFilter>();
        c.OperationFilter<SwaggerAuthenticatedUserIdOperationFilter>();
    });

    CommandingDependencyResolver = new MicrosoftDependencyInjectionCommandingResolver(services);
    ICommandRegistry registry = CommandingDependencyResolver.UseCommanding();

    services
        .UseShoppingCart(registry)
        .UseStore(registry)
        .UseCheckout(registry);
    services.Replace(new ServiceDescriptor(typeof(ICommandDispatcher), typeof(LoggingCommandDispatcher),
        ServiceLifetime.Transient));
}

We can roll that approach out over the rest of our commands and with the validator configured in ASP.Net can add model state checks into our AbstractCommandController, for example:

public abstract class AbstractCommandController : Controller
{
    protected AbstractCommandController(ICommandDispatcher dispatcher)
    {
        Dispatcher = dispatcher;
    }

    protected ICommandDispatcher Dispatcher { get; }

    protected async Task<IActionResult> ExecuteCommand<TResult>(ICommand<TResult> command)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        TResult response = await Dispatcher.DispatchAsync(command);
        return Ok(response);
    }
        
    // ...
}

At this point we can enforce simple entry point validation but what if we need to make validation decisions based on state we only know about in a handler? For example in our AddToCartCommand example we want to make sure the product really does exist before we add it and perhaps return an error if it does not (or, for example, if its not in stock).

To achieve this we’ll make some small changes to our CommandResponse class so that instead of simply returning a string it returns a collection of keys (property names) and values (error messages). This might sound like it should be a dictionary but the ModelState design of ASP.Net supports multiple error messages per key and so a dictionary won’t work, instead we’ll use an IReadOnlyCollection backed by an array. Here’s the changes made to the result-free implementation (the changes are the same for the typed variant):

public class CommandResponse
{
    protected CommandResponse()
    {
        Errors = new CommandError[0];
    }

    public bool IsSuccess => Errors.Count==0;

    public IReadOnlyCollection<CommandError> Errors { get; set; }

    public static CommandResponse Ok() {  return new CommandResponse();}

    public static CommandResponse WithError(string error)
    {
        return new CommandResponse
        {
            Errors = new []{new CommandError(error)}
        };
    }

    public static CommandResponse WithError(string key, string error)
    {
        return new CommandResponse
        {
            Errors = new[] { new CommandError(key, error) }
        };
    }

    public static CommandResponse WithErrors(IReadOnlyCollection<CommandError> errors)
    {
        return new CommandResponse
        {
            Errors = errors
        };
    }
}

We’ll add the errors from our command response into model state through an extension method in the API assembly – that way the syntax will stay clean but we won’t need to add a reference to ASP.Net in our shared assembly. We want to keep that as dependency free as possible. The extension method is pretty simple and looks like this:

public static class CommandResponseExtensions
{
    public static void AddToModelState(
        this CommandResponse commandResponse,
        ModelStateDictionary modelStateDictionary)
    {
        foreach (CommandError error in commandResponse.Errors)
        {
            modelStateDictionary.AddModelError(error.Key ?? "", error.Message);
        }
    }
}

And finally another update to the methods within our AbstractCommandController to wire up the response to the model state:

protected async Task<IActionResult> ExecuteCommand<TCommand, TResult>() where TCommand : class, ICommand<CommandResponse<TResult>>, new()
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    TCommand command = CreateCommand<TCommand>();
    CommandResponse<TResult> response = await Dispatcher.DispatchAsync(command);
    if (response.IsSuccess)
    {
        return Ok(response.Result);
    }
    response.AddToModelState(ModelState);
    return BadRequest(ModelState);
}

With that we can now return simple model level validation errors to clients and more complex validations from our business domains. An example from our AddToCartHandler that makes use of this looks as follows:

public async Task<CommandResponse> ExecuteAsync(AddToCartCommand command, CommandResponse previousResult)
{
    Model.ShoppingCart cart = await _repository.GetActualOrDefaultAsync(command.AuthenticatedUserId);

    StoreProduct product = (await _dispatcher.DispatchAsync(new GetStoreProductQuery{ProductId = command.ProductId})).Result;

    if (product == null)
    {
        _logger.LogWarning("Product {0} can not be added to cart for user {1} as it does not exist", command.ProductId, command.AuthenticatedUserId);
        return CommandResponse.WithError($"Product {command.ProductId} does not exist");
    }
    List<ShoppingCartItem> cartItems = new List<ShoppingCartItem>(cart.Items);
    cartItems.Add(new ShoppingCartItem
    {
        Product = product,
        Quantity = command.Quantity
    });
    cart.Items = cartItems;
    await _repository.UpdateAsync(cart);
    _logger.LogInformation("Updated basket for user {0}", command.AuthenticatedUserId);
    return CommandResponse.Ok();
}

Hopefully that’s a good concrete example of how this loosely coupled state and convention based approach to an architecture can reap benefits. We’ve added validation to all of our controllers and actions without having to revisit each one to add boilerplate and we don’t have to worry about unit testing each and every one to ensure validation is enforced and to be sure this worked we simply updated the unit tests for our AbstractCommandController, and our validations are clearly separated from our models and testable. And we’ve done all this through simple POCO (plain old C# object) type models that are easily serializable – something we’ll make good use of later.

In the next part we’ll move on to our handlers and clean them up so that they become purely focused on business domain concerns and at the same time improve the consistency of the logging we’ve got scattered around the handlers at the moment. We’ll also add some basic telemetry to the system using Application Insights so that we can measure how often and for how long each of our handlers take to run.

Other Parts in the Series

Part 5
Part 4
Part 2
Part 1

Azure Functions – Expect Significant Clock Skew

While running the experiment I posted about on Sunday I annotated the message I sent on to the event hub with the Azure Functions view of the current time (basically I set a property to DateTime.UtcNow) and, out of curiosity, grouped my results by second long tumbling windows based on that date. This gave me results that were observably different than when doing the same with the enqueue date and time logged by the Event Hub (as an aside there is some interesting information about Event Hubs and clock skew here). My experiments didn’t need massively accurate time tracking as I was really just looking for trends over a long, relative to the clock skew, period of time however I looked at some of the underlying numbers and became suspicious that there was a significant degree of clock skew across my functions.

I reached out to the @AzureFunctions team on Twitter asking how they handled clock sync on the platform and one of the engineers, Chris Anderson, replied confirming what I suspected: there are no guarantees about clock sync on the Azure Functions platform and, further, you should expect the time skew to be large.

That means you can’t really obtain a consistent view of “now” from within an Azure Function. You could go and get it from an external source but that in and of itself is going to introduce other inaccuracies. Essentially you can’t handle dynamic time reliably inside a function with any precision and you’re limited to working with reference points obtained upstream and passed in.

Definitely something to be aware of when designing systems that make use of Azure Functions as it would be easy to use them in scenarios applying timestamps expecting some sense of temporal sequence.

This isn’t, of course, a new problem – dealing with precise and accurate time in a distributed system is always a challenge and requires careful consideration but it does underline the importance of understanding your cloud vendors various runtime environments.

Azure Functions – Queue Trigger Scaling (Part 1)

I’m a big fan of the serverless compute model (known as Azure Functions on the Azure platform), but in some ways its greatest strength is also its weakness: the serverless model essentially asks you to run small units of code inside a fully managed environment on a pay for what you need basis that in theory will scale infinitely in response to demand. With the increased granularity this is the next evolution in cloud elasticity with no more need to buy and reserve CPUs which sit partially idle until the next scaling point is reached. However as a result you lose control over the levers you might be used to pulling in a more traditional cloud compute environment – it’s very much a black box. Using typical queue processing patterns as an example this includes the number of “threads” or actors looking at a queue and the length of the back off timings.

Most of the systems I’ve transitioned onto Azure Functions to date have been more focused on cost than scale and have had no particular latency requirements and so I’ve just been happy to reduce my costs without a particularly close examination. However I’m starting to look at moving spikier higher volume queue systems onto Azure Functions and so I’ve been looking to understand the opaque aspects more fully through running a series of experiments.

Before continuing it’s worth noting that Microsoft continue to evolve the runtime host for Azure Functions and so the results are only really valid at the time they are run – run them again in 6 months and you’re likely to see, hopefully subtle and improved, changes in behaviour.

Most of my higher volume requirements are light in terms of compute power but heavy on volume and so I’ve created a simple function that pulls a message from a Service Bus queue and writes it, along with a timestamp, onto an event hub:

[FunctionName("DequeAndForwardOn")]
[return: EventHub("results", Connection = "EhConnectionString")]
public static string Run([ServiceBusTrigger("testqueue", Connection = "SbConnectionString")]string myQueueItem, TraceWriter log)
{
    log.Info($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
    EventHubOutput message = JsonConvert.DeserializeObject<EventHubOutput>(myQueueItem);
    message.ProcessedAtUtc = DateTime.UtcNow;
    string json = JsonConvert.SerializeObject(message);
    return json;
}

Once the items are on the Event Hub I’m using a Streaming Analytics job to count the number of dequeues per second with a tumbling window and output them to table storage:

SELECT
    System.TimeStamp AS TbPartitionKey,
    '' as TbRowKey,
    SUBSTRING(CAST(System.TimeStamp as nvarchar(max)), 12, 8) as Time,
    COUNT(1) AS totalProcessed
INTO
    resultsbysecond
FROM
    [results]
TIMESTAMP BY EventEnqueuedUtcTime
GROUP BY TUMBLINGWINDOW(second,1)

For this initial experiment I’m simply going to pre-load the Service Bus queue with 1,000,000 messages and analyse the dequeue rate. Taking all the above gives us a workflow that looks like this:

Executing all this gave some interesting results as can be seen from the graph below:

From a cold start it took just under 13 minutes to dequeue all 1,000,000 messages with a fairly linear, if spiky, approach to scaling up the dequeue rate from a low at the beginning of 23 dequeues per second to a peak of over 3000 increasing at a very rough rate of 3.2 messages per second. It seems entirely likely that this will go on until we start to hit IO limits around the Service Bus. We’d need to do more experiments to be certain but it looks like the runtime is allocating more queue consumers while all existing consumers continue to find their are items on the queue to process.

In the next part we’re going to run a few more experiments to help us understand the scaling rate better and how it is impacted by quiet periods.

C# Cloud Application Architecture – Commanding via a Mediator (Part 2)

In the last post we’d converted our traditional layered architecture into one that instead organised itself around business domains and made use of command and mediator patterns to promote a more loosely coupled approach. However things were definitely still very much a work in progress with our controllers still fairly scruffy and our command handlers largely just a copy and paste of our services from the layered system.

In this post I’m going to concentrate on simplifying the controllers and undertake some minor rework on our commands to help with this. This part is going to be a bit more code heavy than the last and will involve diving into parts of ASP.Net Core. The code for the result of all these changes can be found on GitHub here:

https://github.com/JamesRandall/CommandMessagePatternTutorial/tree/master/Part2

As a reminder our aim is to move from controller with actions that look like this:

[HttpPut("{productId}/{quantity}")]
public async Task<IActionResult> Put(Guid productId, int quantity)
{
    CommandResponse response = await _dispatcher.DispatchAsync(new AddToCartCommand
    {
        UserId = this.GetUserId(),
        ProductId = productId,
        Quantity = quantity
    });
    if (response.IsSuccess)
    {
        return Ok();
    }
    return BadRequest(response.ErrorMessage);
}

To controllers with actions that look like this:

[HttpPut("{productId}/{quantity}")]
public async Task<IActionResult> Put([FromRoute] AddToCartCommand command) => await ExecuteCommand(command);

And we want to do this in a way that makes adding future controllers and commands super simple and reliable.

We can do this fairly straightforwardly as we now only have a single “service”, our dispatcher, and our commands are simple state – this being the case we can use some ASP.Net Cores model binding to take care of populating our commands along with some conventions and a base class to do the heavy lifting for each of our controllers. This focuses the complexity in a single, testable, place and means that our controllers all become simple and thin.

If we’re going to use model binding to construct our commands the first thing we need to be wary of is security: many of our commands have a UserId property that, as can be seen in the code snippet above, is set within the action from a claim. Covering claims based security and the options available in ASP.Net Core is a topic in and of itself and not massively important to the application architecture and code structure we’re focusing on for the sake of simplicty I’m going to use a hard coded GUID, however hopefully its clear from the code below where this ID would come from in a fully fledged solution:

public static class ControllerExtensions
{
    public static Guid GetUserId(this Controller controller)
    {
        // in reality this would pull the user ID from the claims e.g.
        //     return Guid.Parse(controller.User.FindFirst("userId").Value);
        return Guid.Parse("A9F7EE3A-CB0D-4056-9DB5-AD1CB07D3093");
    }
}

If we’re going to use model binding we need to be extremely careful that this ID cannot be set by a consumer as this would almost certainly lead to a security incident. In fact if we make an interim change to our controller action we can see immediately that we’ve got a problem:

[HttpPut("{productId}/{quantity}")]
public async Task<IActionResult> Put([FromRoute]AddToCartCommand command)
{
    CommandResponse response = await _dispatcher.DispatchAsync(command);
    if (response.IsSuccess)
    {
        return Ok();
    }
    return BadRequest(response.ErrorMessage);
}

The user ID has bled through into the Swagger definition but, because of how we’ve configured the routing with no userId parameter on the route definition, the binder will ignore any value we try and supply: there is nowhere to specify it as a route parameter and a query parameter or request body will be ignored. Still – it’s not pleasant: it’s misleading to the consumer of the API and if, for example, we were reading the command from the request body the model binder would pick it up.

We’re going to take a three pronged approach to this so that we can robustly prevent this happening in all scenarios. Firstly, to support some of these changes, we’re going to rename the UserId property on our commands to AuthenticatedUserId and introduce an interface called IUserContextCommand as shown below that all our commands that require this information will implement:

public interface IUserContextCommand
{
    Guid AuthenticatedUserId { get; set; }
}

With that change made our AddToCartCommand now looks like this:

public class AddToCartCommand : ICommand<CommandResponse>, IUserContextCommand
{
    public Guid AuthenticatedUserId { get; set; }

    public Guid ProductId { get; set; }

    public int Quantity { get; set; }
}

I’m using the Swashbuckle.AspNetCore package to provide a Swagger definition and user interface and fortunately it’s quite a configurable package that will allow us to customise how it interprets actions (operations in it’s parlance) and schema through a filter system. We’re going to create and register both an operation and schema filter that ensures any reference to AuthenticatedUserId either inbound or outbound is removed. The first code snippet below will remove the property from any schema (request or response bodies) and the second snippet will remove it from any operation parameters – if you use models with the [FromRoute] attribute as we have done then Web API will correctly only bind to any parameters specified in the route but Swashbuckle will still include all the properties in the model in it’s definition.

public class SwaggerAuthenticatedUserIdFilter : ISchemaFilter
{
    private const string AuthenticatedUserIdProperty = "authenticatedUserId";
    private static readonly Type UserContextCommandType = typeof(IUserContextCommand);

    public void Apply(Schema model, SchemaFilterContext context)
    {
        if (UserContextCommandType.IsAssignableFrom(context.SystemType))
        {
            if (model.Properties.ContainsKey(AuthenticatedUserIdProperty))
            {
                model.Properties.Remove(AuthenticatedUserIdProperty);
            }
        }
    }
}
public class SwaggerAuthenticatedUserIdOperationFilter : IOperationFilter
{
    private const string AuthenticatedUserIdProperty = "authenticateduserid";

    public void Apply(Operation operation, OperationFilterContext context)
    {
        IParameter authenticatedUserIdParameter = operation.Parameters?.SingleOrDefault(x => x.Name.ToLower() == AuthenticatedUserIdProperty);
        if (authenticatedUserIdParameter != null)
        {
            operation.Parameters.Remove(authenticatedUserIdParameter);
        }
    }
}

These are registered in our Startup.cs file alongside Swagger itself:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new Info { Title = "Online Store API", Version = "v1" });
        c.SchemaFilter<SwaggerAuthenticatedUserIdFilter>();
        c.OperationFilter<SwaggerAuthenticatedUserIdOperationFilter>();
    });

    CommandingDependencyResolver = new MicrosoftDependencyInjectionCommandingResolver(services);
    ICommandRegistry registry = CommandingDependencyResolver.UseCommanding();

    services
        .UseShoppingCart(registry)
        .UseStore(registry)
        .UseCheckout(registry);
}

If we try this now we can see that our action now looks as we expect:

With our Swagger work we’ve at least obfuscated our AuthenticatedUserId property and now we want to make sure ASP.Net ignores it during binding operations. A common means of doing this is to use the [BindNever] attribute on models however we want our commands to remain free of the concerns of the host environment, we don’t want to have to remember to stamp [BindNever] on all of our models, and we definetly don’t want the assemblies that contain them to need to reference ASP.Net packages – after all one of the aims of taking this approach is to promote a very loosely coupled design.

This being the case we need to find another way and other than the binding attributes possibly the easiest way to prevent user IDs being set from a request body is to decorate the default body binder with some additional functionality that forces an empty GUID. Binders consist of two parts, the binder itself and a binder provider so to add our binder we need two new classes (and we also include a helper class with an extension method). Firstly our custom binder:

public class AuthenticatedUserIdAwareBodyModelBinder : IModelBinder
{
    private readonly IModelBinder _decoratedBinder;

    public AuthenticatedUserIdAwareBodyModelBinder(IModelBinder decoratedBinder)
    {
        _decoratedBinder = decoratedBinder;
    }

    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        await _decoratedBinder.BindModelAsync(bindingContext);
        if (bindingContext.Result.Model is IUserContextCommand command)
        {
            command.AuthenticatedUserId = Guid.Empty;
        }
    }
}

You can see from the code above that we delegate all the actual binding down to the decorated binder and then simply check to see if we are dealing with a command that implements our IUserContextCommand interface and blanks out the GUID if neecssary.

We then need a corresponding provider to supply this model binder:

internal static class AuthenticatedUserIdAwareBodyModelBinderProviderInstaller
{
    public static void AddAuthenticatedUserIdAwareBodyModelBinderProvider(this MvcOptions options)
    {
        IModelBinderProvider bodyModelBinderProvider = options.ModelBinderProviders.Single(x => x is BodyModelBinderProvider);
        int index = options.ModelBinderProviders.IndexOf(bodyModelBinderProvider);
        options.ModelBinderProviders.Remove(bodyModelBinderProvider);
        options.ModelBinderProviders.Insert(index, new AuthenticatedUserIdAwareBodyModelBinderProvider(bodyModelBinderProvider));
    }
}

internal class AuthenticatedUserIdAwareBodyModelBinderProvider : IModelBinderProvider
{
    private readonly IModelBinderProvider _decoratedProvider;

    public AuthenticatedUserIdAwareBodyModelBinderProvider(IModelBinderProvider decoratedProvider)
    {
        _decoratedProvider = decoratedProvider;
    }

    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        IModelBinder modelBinder = _decoratedProvider.GetBinder(context);
        return modelBinder == null ? null : new AuthenticatedUserIdAwareBodyModelBinder(_decoratedProvider.GetBinder(context));
    }
}

Our installation extension method looks for the default BodyModelBinderProvider class, extracts it, constructs our decorator around it, and replaces it in the set of binders.

Again, like with our Swagger filters, we configure this in the ConfigureServices method of our Startup class:

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(c =>
    {
        c.AddAuthenticatedUserIdAwareBodyModelBinderProvider();
    });
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new Info { Title = "Online Store API", Version = "v1" });
        c.SchemaFilter<SwaggerAuthenticatedUserIdFilter>();
        c.OperationFilter<SwaggerAuthenticatedUserIdOperationFilter>();
    });

    CommandingDependencyResolver = new MicrosoftDependencyInjectionCommandingResolver(services);
    ICommandRegistry registry = CommandingDependencyResolver.UseCommanding();

    services
        .UseShoppingCart(registry)
        .UseStore(registry)
        .UseCheckout(registry);
}

At this point we’ve configured ASP.Net so that consumers of the API cannot manipulate sensitive properties on our commands and so for our next step we want to ensure that the AuthenticatedUserId property on our commands is popualted with the legitimate ID of the logged in user.

While we could set this in our model binder (where currently we ensure it is blank) I’d suggest that’s a mixing of concerns and in any case will only be triggered on an action with a request body, it won’t work for a command bound from a route or query parameters for example. All that being the case I’m going to implement this through a simple action filter as below:

public class AssignAuthenticatedUserIdActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        foreach (object parameter in context.ActionArguments.Values)
        {
            if (parameter is IUserContextCommand userContextCommand)
            {
                userContextCommand.AuthenticatedUserId = ((Controller) context.Controller).GetUserId();
            }
        }
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
            
    }
}

Action filters are run after model binding and authentication and authorization has occurred and so at this point we can be sure we can access the claims for a validated user.

Before we move on it’s worth reminding ourselves what our updated controller action now looks like:

[HttpPut("{productId}/{quantity}")]
public async Task<IActionResult> Put([FromRoute]AddToCartCommand command)
{
    CommandResponse response = await _dispatcher.DispatchAsync(command);
    if (response.IsSuccess)
    {
        return Ok();
    }
    return BadRequest(response.ErrorMessage);
}

To remove this final bit of boilerplate we’re going to introduce a base class that handles the dispatch and HTTP response interpretation:

public abstract class AbstractCommandController : Controller
{
    protected AbstractCommandController(ICommandDispatcher dispatcher)
    {
        Dispatcher = dispatcher;
    }

    protected ICommandDispatcher Dispatcher { get; }

    protected async Task<IActionResult> ExecuteCommand(ICommand<CommandResponse> command)
    {
        CommandResponse response = await Dispatcher.DispatchAsync(command);
        if (response.IsSuccess)
        {
            return Ok();
        }
        return BadRequest(response.ErrorMessage);
    }
}

With that in place we can finally get our controller to our target form:

[Route("api/[controller]")]
public class ShoppingCartController : AbstractCommandController
{
    public ShoppingCartController(ICommandDispatcher dispatcher) : base(dispatcher)
    {
            
    }

    [HttpPut("{productId}/{quantity}")]
    public async Task<IActionResult> Put([FromRoute] AddToCartCommand command) => await ExecuteCommand(command);

    // ... other verbs
}

To roll this out easily over the rest of our commands we’ll need to get them into a more consistent shape – at the moment they have a mix of response types which isn’t ideal for translating the results into HTTP responses. We’ll unify them so they all return a CommandResponse object that can optionally also contain a result object:

public class CommandResponse
{
    protected CommandResponse()
    {
            
    }

    public bool IsSuccess { get; set; }

    public string ErrorMessage { get; set; }

    public static CommandResponse Ok() {  return new CommandResponse { IsSuccess = true};}

    public static CommandResponse WithError(string error) {  return new CommandResponse { IsSuccess = false, ErrorMessage = error};}
}

public class CommandResponse<T> : CommandResponse
{
    public T Result { get; set; }

    public static CommandResponse<T> Ok(T result) { return new CommandResponse<T> { IsSuccess = true, Result = result}; }

    public new static CommandResponse<T> WithError(string error) { return new CommandResponse<T> { IsSuccess = false, ErrorMessage = error }; }

    public static implicit operator T(CommandResponse<T> from)
    {
        return from.Result;
    }
}

With all that done we can complete our AbstractCommandController class and convert all of our controllers to the simpler syntax. By making these changes we’ve removed all the repetitive boilerplate code from our controllers which means less tests to write and maintain, less scope for us to make mistakes and less scope for us to introduce inconsistencies. Instead we’ve leveraged the battle hardened model binding capabilities of ASP.Net and concentrated all of the our response handling in a single class that we can test extensively. And if we want to add new capabilities all we need to do is add commands, handlers and controllers that follow our convention and all the wiring is taken care of for us.

In the next part we’ll explore how we can add validation to our commands in a way that is loosely coupled and reusable in domains other than ASP.Net and then we’ll revisit our handlers to separate out our infrastructure code (logging for example) from our business logic.

Other Parts in the Series

Part 5
Part 4
Part 3
Part 1

Contact

  • If you're looking for help with C#, .NET, Azure, Architecture, or would simply value an independent opinion then please get in touch here or over on Twitter.

Recent Posts

Recent Tweets

Invalid or expired token.

Recent Comments

Archives

Categories

Meta

GiottoPress by Enrique Chavez