tutorials

A Simple Caching Scheme for Web API using Dependency Injection

I use Dependency Injection (DI) quite a bit in my ASP.NET projects, particularly in Web API and MVC web applications. Recently, I had a need to implement a caching layer in one of my MVC apps, and such a layer would be best used if it could be injected into my clients layer (e.g. the layer that called an API and handled responses from the same). The solution I came up with seemed to be pretty simple, so I wanted to share it here.

In this post, we're going to set up a simple MVC project that consumes a Web API and implements a caching layer.

Requirements

For this project, I'm using two of my favorite NuGet packages:

The sample project, which is over on GitHub, is a fully-functional implementation of the strategy described in this post. Feel free to check it out, branch it, download it, whatever!

Setting Up the API

First, let's take a look at our sample API. Here's the class DateNumberObject, which represents a response returned from the API to the web project:

public class DateNumberObject  
{
    public DateTime CurrentDate { get; set; }
    public int RandomNumber { get; set; }

    public DateNumberObject()
    {
        CurrentDate = DateTime.Now;
        Random rand = new Random();
        RandomNumber = rand.Next(1, 200);
    }
}

As you can see, all this class does is return the current date and time and a random number.

We can now build our API, which is also rather simple. Here's a snippet from the API's controller:

[RoutePrefix("samples")]
public class SampleController : ApiController  
{

    [HttpGet]
    [Route("date")]
    public IHttpActionResult GetDateAndNumber()
    {
        return Ok(new DateNumberObject());
    }
}

That's all our API will do: return the current date and a random number. Since there's no caching taking place at the service layer, we will need to implement caching at the web layer.

Speaking of the web layer, in our sample solution it is an MVC5 project, and we will be using my favorite Dependency Injection tool, StructureMap.

Setting up StructureMap

If you've never set up StructureMap in your MVC projects, you'll want to read this section; otherwise, skip to the next section.

The first thing we need to do is download the StructureMap.MVC5 NuGet package, which will add a DependencyInjection folder and a StructuremapMvc file to our app:

Inside the Dependency Resolution folder will be a file called DefaultRegistry.cs, which will initially look something like this:

namespace WebApiCacheDemo.Mvc.DependencyResolution {  
    using Caching;
    using StructureMap.Configuration.DSL;
    using StructureMap.Graph;

    public class DefaultRegistry : Registry {
        #region Constructors and Destructors
        public DefaultRegistry() {
            Scan(
                scan => {
                    scan.TheCallingAssembly();
                    scan.WithDefaultConventions();
                    scan.With(new ControllerConvention());
                });
        }
        #endregion
    }
}

The way StructureMap works is that it keeps instances of classes that need to be "injected" into other classes in a Container class, and uses these instances any time a particular interface is called for in another class. You'll see exactly what this means in the next section.

The Uncached Example

Let's build the uncached example first, and we can begin by setting up the MVC client. For this project we'll be using RestSharp (which I have also written about before) to consume the API responses, so be sure to download the NuGet package.

Because we're using Dependency Injection, we need our clients to be injectable into our controllers. For this reason, we will make both an interface and a class for our client, like so:

public interface ISampleClient : IRestClient  
{
    DateNumberObject GetSampleDateAndNumberUncached();
}

public class SampleClient : RestClient, ISampleClient  
{
    public SampleClient()
    {
        BaseUrl = new Uri("http://localhost:58566/");
    }

    public DateNumberObject GetSampleDateAndNumberUncached()
    {
        RestRequest request = new RestRequest("samples/date", Method.GET);
        var response = Execute<DateNumberObject>(request);
        return response.Data;
    }
}

Note that we don't need to register this client with StructureMap because the naming follows the standard conventions (ISampleClient maps to SampleClient).

Now we need our controller...

[RoutePrefix("Home")]
public class HomeController : Controller  
{
    private ISampleClient _sampleClient;

    public HomeController(ISampleClient sampleClient)
    {
        _sampleClient = sampleClient;
    }

    [HttpGet]
    [Route("Uncached")]
    [Route("")]
    [Route("~/")]
    public ActionResult Uncached()
    {
        var model = _sampleClient.GetSampleDateAndNumberUncached();
        return View(model);
    }
}

...which returns a view:

@model WebApiCacheDemo.Contracts.Samples.DateNumberObject
@{
    ViewBag.Title = "Uncached Date Sample";
}

<h2>Uncached Results</h2>  
<div class="row">  
    <span><strong>Current Date:</strong></span>
    @Model.CurrentDate
</div>  
<div class="row">  
    <span><strong>Random Number:</strong></span>
    @Model.RandomNumber
</div>  

When we run this, we can see that the view returns the newest date and time, as shown in this gif:

That's exactly what we would expect to see, of course. Now, we can get down to implementing a cache at the web layer for this.

The Cached Example

The first thing we need is our CacheService interface and implementation, which I totally stole from this StackOverflow answer:

public class InMemoryCache : ICacheService  
{
    public T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class
    {
        T item = MemoryCache.Default.Get(cacheKey) as T;
        if (item == null)
        {
            item = getItemCallback();
            MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddMinutes(30));
        }
        return item;
    }
}

public interface ICacheService  
{
    T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class;
}

We also need our SampleClient class updated to use this cache service, like so:

public class SampleClient : RestClient, ISampleClient  
{
    private ICacheService _cache;
    public SampleClient(ICacheService cache)
    {
        _cache = cache;
        BaseUrl = new Uri("http://localhost:58566/");
    }

    public DateNumberObject GetSampleDateAndNumber()
    {
        return _cache.GetOrSet("SampleDateAndNumber", () => GetSampleDateAndNumberUncached());
    }

    public DateNumberObject GetSampleDateAndNumberUncached()
    {
        RestRequest request = new RestRequest("samples/date", Method.GET);
        var response = Execute<DateNumberObject>(request);
        return response.Data;
    }
}

NOTE: In my structure, I am intentionally implementing the cached and uncached operations as separate methods in the same client, so that either one can be used. This may or may not be the correct usage in your application.

Further, we need to update our controller:

[RoutePrefix("Home")]
public class HomeController : Controller  
{
    ...

    [HttpGet]
    [Route("Cached")]
    public ActionResult Cached()
    {
        var model = _sampleClient.GetSampleDateAndNumber();
        return View(model);
    }
}

The last step is to register the ICacheService implementing in StructureMap's DefaultRegistry.cs class:

namespace WebApiCacheDemo.Mvc.DependencyResolution {  
    ...

    public class DefaultRegistry : Registry {
        public DefaultRegistry() {
            ...
            var inMemoryCache = new InMemoryCache();
            For<ICacheService>().Use(inMemoryCache);
        }
    }
}

Now, when we run this sample, we will see the cached values for the date and number, as shown in the following gif:

Now we've successfully implemented our cache AND used Dependency Injection in the process!

Summary

With this structure, we've successfully implemented a caching layer into our MVC application, all while using StructureMap to provide Dependency Injection. This structure allows us to potentially swap cache providers (in case we, say, move to a database-located cache for server farms) without too much trouble, as well as injecting the cache service into our existing clients.

Don't forget to check out the sample project over on GitHub, and feel free to point out how you've used this implemention or where it can be improved in the comments.

Happy Coding!

Working with Environments and Launch Settings in ASP.NET Core

I'm continuing my series of deep dives into ASP.NET Core, on my never-ending quest to keep my coding career from becoming obsolete. In this part of the series, let's discuss a new feature in ASP.NET Core that will make debugging and testing much more intuitive and pain-free: Environments and Launch Settings.

ASP.NET Core includes the native ability to modify how an application behaves (and what it displays) based upon the environment it is currently executing in. This ends up being quite useful, since now we can do things as simple as not showing the error page to people using the application in a production environment. But it requires just a tiny bit of setup, and some knowledge of how environments are controlled.

ASPNETCORE_ENVIRONMENT

At the heart of all the stuff ASP.NET Core can do with environments is the ASPNETCORE_ENVIRONMENT environment variable. This variable controls what type of environment the current build will run in. You can edit this variable manually by right-clicking your project file and selecting "Properties", then navigating to the "Debug" tab.

There are three "default" values for this variable:

  • Development
  • Staging
  • Production

Each of those values corresponds to certain methods we can use in our Startup.cs file. In fact, the Startup.cs file includes several extension methods that make modifying our application based it's current environment quite simple.

Selecting an Environment

The Startup.cs file that every ASP.NET Core application needs does many things, not the least of which is setting up the environment in which the application runs. Here's a snippet of the default Startup.cs file that was generated when I created my sample project for this post:

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

Notice the IHostingEnvironment variable. That variable represents the current environment in which the application runs, and ASP.NET Core includes four extension methods that allow us to check the current value of ASPNETCORE_ENVIRONMENT:

  • IsDevelopment()
  • IsStaging()
  • IsProduction()
  • IsEnvironment()

Notice what we're setting up in the Startup.cs file: if the current environment is Development, we use the Developer Exception Page (which was formerly the Yellow Screen of Death) as well as enabling Browser Link in Visual Studio, which helps us test our application in several browsers at once.

But we don't want those features enabled in a Production environment, so instead our configuration establishes an error handling route "/Home/Error".

This is the coolest thing about this feature: you can decide what services are enabled for your application in each environment without ever touching a configuration file!

However, what if you need more environments? For example, at my day job we have up to four environments: Development, Staging, Production, and Testing, and very often I'll need to change application behaviors or display based on which environment it's currently running in. How do I do that in ASP.NET Core?

The launchSettings.json File

ASP.NET Core 1.0 includes a new file called launchSettings.json; in any given project, you'll find that file under the Properties submenu:

This file sets up the different launch environments that Visual Studio can launch automatically. Here's a snippet of the default launchSettings.json file that was generated with my demo project:

{
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "CoreEnvironmentBehaviorDemo": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

At the moment we have two profiles: one which runs the app using IIS Express and one which runs the app using a command-line handler. The interesting thing about these two profiles is that they correspond directly to the Visual Studio play button:

In other words: the launchSettings.json file controls what environments you can run your app in using Visual Studio. In fact, if we add a new profile, it automatically adds that profile to the button, as seen on this GIF I made:

All this together means that we can run the app in multiple different environment settings from Visual Studio, simply by setting up the appropriate launch profiles.

The Environment Tag Helper

Quite a while ago I wrote a post about Tag Helpers and how awesome they are, and I want to call out a particular helper in this post: the <environment> tag helper.

With this helper, we can modify how our MVC views are constructed based upon which environment the application is currently running in. In fact, the default _Layout.cshtml file in Visual Studio 2015 comes with an example of this:

<environment names="Development">  
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
</environment>  
<environment names="Staging,Production">  
    <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
            asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
            asp-fallback-test="window.jQuery">
    </script>
    <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/bootstrap.min.js"
            asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
            asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
    </script>
    <script src="~/js/site.min.js" asp-append-version="true"></script>
</environment>  

In this sample, when we run the app in Development mode we use the local files for jQuery, Bootstrap, and our custom Javascript; but if we're running in the Staging or Production environments, we use copies of those libraries files found on the ASP.NET content delivery network (CDN). In this way, we improve performance, because a CDN can deliver these static files from one of many centers around the globe, rather than needing to round-trip all the way to the source server to get those files.

But, remember, in our sample we have the custom environment Testing. The environment tag helper also supports custom environments:

<div class="row">  
    <environment names="Development">
        <span>This is the Development environment.</span>
    </environment>
    <environment names="Testing">
        <span>This is the Testing environment.</span>
    </environment>
    <environment names="Production">
        <span>This is the Production environment.</span>
    </environment>
</div>  

Summary

Working with environments (both default and custom) gets a whole lot easier in ASP.NET Core, and with the new Launch Settings feature, getting the app started in different environment modes is a breeze! Using these features, we can:

  • Create and use custom environments.
  • Enable or disable application services based on the environment the app is running in.
  • Use the environment tag helper (<environment>) to modify our MVC views based on the current execution environment.

You can check out my sample project over on GitHub to see this code in action. Feel free to mention any cool tips and tricks you've found when dealing with environments and launch settings in the comments!

Happy Coding!

Real-World CQRS/ES with ASP.NET and Redis Part 5 - Running the APIs

NOTE: This is the final part of a five-part series in which I detail how a real-world ASP.NET Web API app using the Command-Query Responsibility Segregation and Event Sourcing (CQRS/ES) patterns and the Redis database might look. Here's Part 1 of this series. The corresponding repository is over on GitHub.

All our work in the previous parts of this series (learning what Command-Query Responsibility Segregation and Event Sourcing are, building the Write Model to modify our aggregate roots, building the Read Model to query data, and building both our Write and Read APIs) has lead to this. We can now test these two APIs using [Postman] and see how they operate.

In this post, the final part of our Real-World CQRS/ES with ASP.NET and Redis series, we will:

  • Run the Commands API with both valid and invalid commands.
  • Run the Queries API with existent and non-existent data.
  • Discuss some shortcomings of this design.

You're on the last lap, so don't stop now!

Command - Creating Locations

The first thing we should do is run a few commands to load our Write and Read models with data. To do that, we're going to use my favorite tool Postman to create some requests.

First, let's run a command to create a new location. Here's a screenshot of the Postman request:

Running this request returns 200 OK, which is what we expect. But what happens if we try to run the exact same request again?

Hey, lookie there! Our validation layer is working!

Let's create another location:

Well, seems our create location process is working fine. Or, at least, it looks like it is.

Query - Locations (All and By ID)

To be sure that our system is properly updating the read model, let's submit a query to our Queries API that returns all locations:

Which looks good. Let's also query for a single location by its ID. First, let's get Location #2:

Now we can query for Location #3:

Oh, wait, that's right, there is no Location #3. So we get back HTTP 400 Bad Request, which is also what we expect. (You could also make this return HTTP 404 Not Found, which is more semantically correct).

OK, great, adding and querying Locations works. But what about Employees?

Command - Creating Employees

Let's first create a new employee and assign him to Location #1:

Let's also create a couple more employees:

So now we should have two employees at Location #1 and a third employee at Location #2. Let's query for employees by location to confirm this.

Query - Employees by Location

Here's our Postman screenshot for the Employees by Location query for each location.

Just as we thought, there are two employees at Location #1 and a third at Location #2.

We're doing pretty darn good so far! But what happens if Reggie Martinez (Employee #3) needs to transfer to Location #2? We can do that with the proper commands.

Command - Assign Employee to Location

Here's a command to move Mr. Martinez to Location #2:

And now, if we query for all employees at Location #2:

I'd say we've done pretty darn good! All our commands do what we expect them to do, and all our queries return the appropriate data. We've now got ourselves a working CQRS/ES project with ASP.NET and Redis!

Shortcomings of This Design

Even though we've done a lot of work on this project and I think we've mostly gotten it right, there's still a few places that I think could be improved:

  • All Redis access through repositories. I don't like having the Event Handlers access the Redis database directly, I'd rather have them do that through the repositories. This would be easy to do, I just didn't have time before my publish date.
  • Better splitting of requests/commands and commands/events. I don't like how commands always seem to result in exactly one event.

That said, I'm really proud of the way this project turned out. If you see any additional areas for improvement, please let me know in the comments!

Summary

In this final part of our Real-World CQRS/ES with ASP.NET and Redis series:

  • Ran several queries and commands.
  • Confirmed that those queries and commands worked as expected.
  • Discussed a couple of shortcomings of this design.

As always, I welcome (civil) comments and discussion on my blog, and feel free to fork or patch or do whatever to the GitHub repository that goes along with this series. Thanks for reading!

Happy Coding!

Post image is Toddler running and falling from Wikimedia, used under license

Real-World CQRS/ES with ASP.NET and Redis Part 4 - Creating the APIs

NOTE: This is Part 4 of a five-part series in which I detail how a real-world ASP.NET Web API app using the Command-Query Responsibility Segregation and Event Sourcing (CQRS/ES) patterns and the Redis database might look. Here's Part 1 of this series. The corresponding repository is over on GitHub.

We've done quite a lot of work to get to this point! We've discussed why we might want to use Command-Query Responsibility Segregation (CQRS) and Event Sourcing (ES) in our app, we've built a Write Model to handle the processing of our commands, and we've built a Read Model to query our data.

Now we can show why this is a "real-world" app. Here's what we're going to do in Part 4 of Real World CQRS/ES with ASP.NET:

  • Build a Queries API so we can query the system for data.
  • Build a Commands API so that we can issue commands to the system.
  • Implement a validation layer using FluentValidation to ensure that commands being issued are valid to execute.
  • Implement dependency injection using StructureMap in both the commands and queries APIs.

Don't stop now! Let's get starting building our APIs!

The Queries API

We're going to switch it up a bit and build the Queries API first, as that turns out to be easier than building the Commands API right off the bat. After all, the Queries API doesn't have to worry about things like validation. So, let's create a new ASP.NET Web API app.

Dependency Injection with StructureMap

After creating the new ASP.NET Web API project, the first thing we need to do is download the StructureMap.WebApi2 NuGet package and install it. Doing so gives us a folder structure that looks something like this (notice the new DependencyResolution folder):

I've blogged about how to use StructureMap with Web API in a previous post, so if you're not familiar with the StructureMap.WebApi2 package, you might want to read that post first, then come back here. It's OK, I'll wait.

Once we've downloaded and installed the StructureMap.WebApi2 package, we'll need to change just a couple of things. In our Global.asax file, we need to start the StructureMap container:

public class WebApiApplication : System.Web.HttpApplication  
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        GlobalConfiguration.Configure(WebApiConfig.Register);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        StructuremapWebApi.Start(); //Start! Your! Containers! VROOOOOOOOM
    }
}

We also need to register the appropriate items with the container so that they can be injected. Among those items are the Repositories we created in the previous part of this series; we must register them so our API controller have them injected.

In Part 3, we also established that we are using Redis as our Read Data Store, and that we are utilizing StackExchange.Redis to interface with said Redis instance. StackExchange.Redis conveniently comes prepared for dependency injection, so we will need to register the IConnectionMultiplexer interface with our container.

In all, our DefaultRegistry class for the Queries API looks like this:

public class DefaultRegistry : Registry {  
    public DefaultRegistry() 
    {
        //Repositories
        For<IEmployeeRepository>().Use<EmployeeRepository>();
        For<ILocationRepository>().Use<LocationRepository>();

        //StackExchange.Redis
        ConnectionMultiplexer multiplexer = ConnectionMultiplexer.Connect("localhost");
        For<IConnectionMultiplexer>().Use(multiplexer);
    }
}

See, that wasn't too bad! Just wait until you see the Commands API's registry.

Building the Queries

Anyway, with StructureMap now in place, we can start building the queries we need to support. Here's the queries list we talked about in Part 3:

  • Get Employee by ID
  • Get Location by ID
  • Get All Locations
  • Get All Employees (with their assigned Location ID)
  • Get All Employees at a Location

Let's start with the easy one: getting an Employee by their ID.

Get Employee by ID

We need an EmployeeController, with a private IEmployeeRepository, to execute this query. The complete controller is as follows:

[RoutePrefix("employees")]
public class EmployeeController : ApiController  
{
    private readonly IEmployeeRepository _employeeRepo;

    public EmployeeController(IEmployeeRepository employeeRepo)
    {
        _employeeRepo = employeeRepo;
    }

    [HttpGet]
    [Route("{id}")]
    public IHttpActionResult GetByID(int id)
    {
        var employee = _employeeRepo.GetByID(id);

        //It is possible for GetByID() to return null.
        //If it does, we return HTTP 400 Bad Request
        if(employee == null)
        {
            return BadRequest("No Employee with ID " + id.ToString() + " was found.");
        }

        //Otherwise, we return the employee
        return Ok(employee);
    }
}

Well, that looks pretty simple. How about the GetAll() query?

Get All Employees

[RoutePrefix("employees")]
public class EmployeeController : ApiController  
{
    ...

    [HttpGet]
    [Route("all")]
    public IHttpActionResult GetAll()
    {
        var employees = _employeeRepo.GetAll();
        return Ok(employees);
    }
}

I think I'm sensing a theme here.

The Location Queries Controller

Let's see what the Location queries are:

[RoutePrefix("location")]
public class LocationController : ApiController  
{
    private ILocationRepository _locationRepo;

    public LocationController(ILocationRepository locationRepo)
    {
        _locationRepo = locationRepo;
    }

    [HttpGet]
    [Route("{id}")]
    public IHttpActionResult GetByID(int id)
    {
        var location = _locationRepo.GetByID(id);
        if(location == null)
        {
            return BadRequest("No location with ID " + id.ToString() + " was found.");
        }
        return Ok(location);
    }

    [HttpGet]
    [Route("all")]
    public IHttpActionResult GetAll()
    {
        var locations = _locationRepo.GetAll();
        return Ok(locations);
    }

    [HttpGet]
    [Route("{id}/employees")]
    public IHttpActionResult GetEmployees(int id)
    {
        var employees = _locationRepo.GetEmployees(id);
        return Ok(employees);
    }
}

Yep, definitely a theme going on. All this setup has made implementing our controllers very simple, and simplicity is definitely better when dealing with complex patterns like CQRS and ES.

We'll run queries against this API in Part 5, but for now let's turn our attention to the Commands API, which may prove to be a bit more difficult to write.

The Commands API

As I mentioned early on in this post, the Commands API is considerably more complex than the Queries API; this is largely due to the number of things we need to inject into our container, as well as the Commands API being responsible for validating the requests that come in to the system. We're going to tackle each of these problems.

Dependency Injection

First, let's deal with Dependency Injection. We'll use the same package as before, with the same Global.asax change. However, our DefaultRegistry looks much different.

In the Commands API, we need the following services available for injection:

  • CQRSLite's Commands and Events bus
  • Our Commands and Events (from Part 2)
  • Our Event Store (from Part 2)
  • AutoMapper
  • Our own Repositories (from Part 3)
  • StackExchange.Redis

That results in this monstrosity of a registry:

public class DefaultRegistry : Registry {  
    #region Constructors and Destructors

    public DefaultRegistry() {
        //Commands, Events, Handlers
        Scan(
            scan => {
                scan.TheCallingAssembly();
                scan.AssemblyContainingType<BaseEvent>();
                scan.Convention<FirstInterfaceConvention>();
            });

        //CQRSLite
        For<InProcessBus>().Singleton().Use<InProcessBus>();
        For<ICommandSender>().Use(y => y.GetInstance<InProcessBus>());
        For<IEventPublisher>().Use(y => y.GetInstance<InProcessBus>());
        For<IHandlerRegistrar>().Use(y => y.GetInstance<InProcessBus>());
        For<ISession>().HybridHttpOrThreadLocalScoped().Use<Session>();
        For<IEventStore>().Singleton().Use<InMemoryEventStore>();
        For<IRepository>().HybridHttpOrThreadLocalScoped().Use(y =>
                new CacheRepository(new Repository(y.GetInstance<IEventStore>()), y.GetInstance<IEventStore>()));

        //AutoMapper
        var profiles = from t in typeof(DefaultRegistry).Assembly.GetTypes()
                        where typeof(Profile).IsAssignableFrom(t)
                        select (Profile)Activator.CreateInstance(t);

        var config = new MapperConfiguration(cfg =>
        {
            foreach (var profile in profiles)
            {
                cfg.AddProfile(profile);
            }
        });

        var mapper = config.CreateMapper();

        For<IMapper>().Use(mapper);

        //StackExchange.Redis
        ConnectionMultiplexer multiplexer = ConnectionMultiplexer.Connect("localhost");
        For<IConnectionMultiplexer>().Use(multiplexer);
    }

    #endregion
}

Holy crap that's a lot of things that need to be injected. But, as we will see, each of these things is actually necessary and provides a lot of value to our application.

(Hold on a second while I smack myself. I sounded way too much like a marketer just now.)

SMACK

Okay, I'm better now.

Requests

I've been using the term "request" liberally throughout this series, and now it's time to truly define what a request is.

In this system, a request is a potential command. That's all. Consuming applications which would like commands issued must submit a request first; that request will be validated and, if found to be valid, mapped to the corresponding command.

A request is, therefore, a C# class which contains the data needed to issue a particular command.

Request 1 - Create Employee

Let's begin to define our requests by first creating a request for creating a new employee.

public class CreateEmployeeRequest  
{
    public int EmployeeID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public string JobTitle { get; set; }
    public int LocationID { get; set; }
}

WTF Matthew, you say, that looks almost EXACTLY like the CreateEmployeeCommand! Why can't we just use that?! And after I'm done looking around for my parents (nobody calls me Matthew), I can tell you that there are two reasons why we don't reuse the command objects as requests.

First, requests must be validated against the Read Model, whereas commands are assumed to be valid. Second a single request may kick off more than one command, as is the case with this request.

But how do we accomplish that validation, you say? By using one of my favorite NuGet packages of all time: FluentValidation.

The Validation Layer

FluentValidation is a NuGet package which allows us to validate objects and places any validation errors found into the Controller's ModelState. But (unlike StackExchange.Redis) it doesn't come ready for use in a Dependency Injection environment, so we must do some setup.

First, we need a factory which will create the validator objects:

public class StructureMapValidatorFactory : ValidatorFactoryBase  
{
    private readonly HttpConfiguration _configuration;

    public StructureMapValidatorFactory(HttpConfiguration configuration)
    {
        _configuration = configuration;
    }

    public override IValidator CreateInstance(Type validatorType)
    {
        return _configuration.DependencyResolver.GetService(validatorType) as IValidator;
    }
}

Next, in our WebApiConfig.cs file, we need to enable FluentValidation's validator provider using our factory:

public static void Register(HttpConfiguration config)  
{
    ...

    FluentValidationModelValidatorProvider.Configure(config, x => x.ValidatorFactory = new StructureMapValidatorFactory(config));

    ...
}

Finally, we need to register the validator provider in our StructureMap container, which is done in the DefaultRegistry class.

public DefaultRegistry()  
{
    ...
    //FluentValidation 
    FluentValidation.AssemblyScanner.FindValidatorsInAssemblyContaining<CreateEmployeeRequestValidator>()
            .ForEach(result =>
            {
                For(result.InterfaceType)
                    .Use(result.ValidatorType);
            });

With all of that in place, we're ready to begin building our validators!

Create Employee - Validation

Here's the validation rules we need to implement when creating an employee:

  • The Employee ID must not already exist.
  • The First Name cannot be blank.
  • The Last Name cannot be blank.
  • The Job Title cannot be blank.
  • Employees must be 16 years of age or older.

Here's how we would implement such a validator using FluentValidation:

public class CreateEmployeeRequest  
{
    public int EmployeeID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public string JobTitle { get; set; }
}

public class CreateEmployeeRequestValidator : AbstractValidator<CreateEmployeeRequest>  
{
    public CreateEmployeeRequestValidator(IEmployeeRepository employeeRepo, ILocationRepository locationRepo)
    {
        RuleFor(x => x.EmployeeID).Must(x => !employeeRepo.Exists(x)).WithMessage("An Employee with this ID already exists.");
        RuleFor(x => x.LocationID).Must(x => locationRepo.Exists(x)).WithMessage("No Location with this ID exists.");
        RuleFor(x => x.FirstName).NotNull().NotEmpty().WithMessage("The First Name cannot be blank.");
        RuleFor(x => x.LastName).NotNull().NotEmpty().WithMessage("The Last Name cannot be blank.");
        RuleFor(x => x.JobTitle).NotNull().NotEmpty().WithMessage("The Job Title cannot be blank.");
        RuleFor(x => x.DateOfBirth).LessThan(DateTime.Today.AddYears(-16)).WithMessage("Employees must be 16 years old or older.");
    }
}

Notice that IEmployeeRepository and ILocationRepository are constructor parameters to the validator class. We don't need to do anything else to get those objects injected, as that was taken care of by registering the Repositories and the FluentValidation factory.

There's just one last thing we need to do to have our validation layer fully integrated: whenever validation fails, we need to automatically return HTTP 400 Bad Request. We accomplish this by using an ActionFilter...

public class BadRequestActionFilter : ActionFilterAttribute  
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (!actionContext.ModelState.IsValid)
        {
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, new ValidationErrorWrapper(actionContext.ModelState));
        }
        base.OnActionExecuting(actionContext);
    }
}

...and registering that action filter in WebApiConfig.

public static class WebApiConfig  
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        config.Filters.Add(new BadRequestActionFilter());
        ...
    }
}

Controller Action

The controller action for creating an employee does two things: it issues the CreateEmployeeCommand, and then issues an AssignEmployeeToLocationCommand. Since this is the only action in the EmployeeController class, the entire class looks like this:

[RoutePrefix("employee")]
public class EmployeeController : ApiController  
{
    private IMapper _mapper;
    private ICommandSender _commandSender;

    public EmployeeController(ICommandSender commandSender, IMapper mapper)
    {
        _commandSender = commandSender;
        _mapper = mapper;
    }

    [HttpPost]
    [Route("create")]
    public IHttpActionResult Create(CreateEmployeeRequest request)
    {
        var command = _mapper.Map<CreateEmployeeCommand>(request);
        _commandSender.Send(command);

        var assignCommand = new AssignEmployeeToLocationCommand(request.LocationID, request.EmployeeID);
        _commandSender.Send(assignCommand);
        return Ok();
    }
}

Since we've now got the EmployeeController written, we can move on to the next request: creating a new location.

Request 2 - Create Location

Now let's build a request and a validator to create a location. Our validation rules for creating a new location look like this:

  1. The location ID must not already exist.
  2. The street address cannot be blank.
  3. The city cannot be blank.
  4. The state cannot be blank.
  5. The postal code cannot be blank.

Implementing those rules results in the following classes:

public class CreateLocationRequest  
{
    public int LocationID { get; set; }
    public string StreetAddress { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string PostalCode { get; set; }
}

public class CreateLocationRequestValidator : AbstractValidator<CreateLocationRequest>  
{
    public CreateLocationRequestValidator(ILocationRepository locationRepo)
    {
        RuleFor(x => x.LocationID).Must(x => !locationRepo.Exists(x)).WithMessage("A Location with this ID already exists.");
        RuleFor(x => x.StreetAddress).NotNull().NotEmpty().WithMessage("The Street Address cannot be null");
        RuleFor(x => x.City).NotNull().NotEmpty().WithMessage("The City cannot be null");
        RuleFor(x => x.State).NotNull().NotEmpty().WithMessage("The State cannot be null");
        RuleFor(x => x.PostalCode).NotNull().NotEmpty().WithMessage("The Postal Code cannot be null");
    }
}

The corresponding controller (LocationController) looks pretty similar to EmployeeController.

[RoutePrefix("locations")]
public class LocationController : ApiController  
{
    private IMapper _mapper;
    private ICommandSender _commandSender;
    private ILocationRepository _locationRepo;
    private IEmployeeRepository _employeeRepo;

    public LocationController(ICommandSender commandSender, IMapper mapper, ILocationRepository locationRepo, IEmployeeRepository employeeRepo)
    {
        _commandSender = commandSender;
        _mapper = mapper;
        _locationRepo = locationRepo;
        _employeeRepo = employeeRepo;
    }

    [HttpPost]
    [Route("create")]
    public IHttpActionResult Create(CreateLocationRequest request)
    {
        var command = _mapper.Map<CreateLocationCommand>(request);
        _commandSender.Send(command);
        return Ok();
    }
}

Looking at this controller, you might be wondering why IEmployeeRepository and ILocationRepository are passed into the constructor when they aren't used by the Create() action. That's because we still have one request left to build: assigning an employee to a location.

Request 3 - Assign Employee to Location

Remember that one of our business rules (from Part 2) says the following:

  1. Employees may switch locations, but they may not be assigned to more than one location at a time.

The request we are going to build now will assign an employee to a new location, as well as remove that employee from the location s/he is currently assigned to.

But, you declare, we defined a command to remove an employee from a location! Is that not also a request? Nope, it's not, and for the same reason that creating an employee results in two commands: one request can result in multiple commands. In this case, assigning an employee to a location could result in one or two commands, depending on if the employee was just created or not.

First, let's build the request and its validator. In this case, we have three validation rules:

  1. The Location must exist.
  2. The Employee must exist.
  3. The Employee must not already be assigned to the given Location.

Implementing those rules result in the following classes:

public class AssignEmployeeToLocationRequest  
{
    public int LocationID { get; set; }
    public int EmployeeID { get; set; }
}

public class AssignEmployeeToLocationRequestValidator : AbstractValidator<AssignEmployeeToLocationRequest>  
{
    public AssignEmployeeToLocationRequestValidator(IEmployeeRepository employeeRepo, ILocationRepository locationRepo)
    {
        RuleFor(x => x.LocationID).Must(x => locationRepo.Exists(x)).WithMessage("No Location with this ID exists.");
        RuleFor(x => x.EmployeeID).Must(x => employeeRepo.Exists(x)).WithMessage("No Employee with this ID exists.");
        RuleFor(x => new { x.LocationID, x.EmployeeID }).Must(x => !locationRepo.HasEmployee(x.LocationID, x.EmployeeID)).WithMessage("This Employee is already assigned to that Location.");
    }
}

Now, all we have to do is write the controller action:

[RoutePrefix("locations")]
public class LocationController : ApiController  
{
    ...
    [HttpPost]
    [Route("assignemployee")]
    public IHttpActionResult AssignEmployee(AssignEmployeeToLocationRequest request)
    {
        var employee = _employeeRepo.GetByID(request.EmployeeID);
        if (employee.LocationID != 0)
        {
            var oldLocationAggregateID = _locationRepo.GetByID(employee.LocationID).AggregateID;

            RemoveEmployeeFromLocationCommand removeCommand = new RemoveEmployeeFromLocationCommand(oldLocationAggregateID, request.LocationID, employee.EmployeeID);
            _commandSender.Send(removeCommand);
        }

        var locationAggregateID = _locationRepo.GetByID(request.LocationID).AggregateID;
        var assignCommand = new AssignEmployeeToLocationCommand(locationAggregateID, request.LocationID, request.EmployeeID);
        _commandSender.Send(assignCommand);

        return Ok();
    }
}

Whew! With that final controller action in place, we have completed building our APIs! Give yourselves a pat on the back for coming this far!

Summary

In this part of our Real-World CQRS/ES with ASP.NET and Redis series, we:

  • Built a Queries API with a DI container and implemented our business queries.
  • Build a Commands API with a DI container and implemented our requests.
  • Used FluentValidation to implement the Commands API's validation layer.

Congratulations! We've completed the build of our real-world CQRS/ES system! All that's left to do is run a few commands and queries to show how the system works, and we will do that in the final part of this series. Keep your eyes (and feed readers) open for Part 5 of Real-World CQRS/ES with ASP.NET and Redis!

Happy Coding!