A388

Arex388.OpenWeatherMap 1.0.0 Released

I've started a very complicated update for the project at my work and it had a requirement to get the current weather conditions (specifically temperature and humidity) for a geocoordinate point. I settled on using the OpenWeatherMap API because it provided what I needed and the free account allows for more than enough daily usage for my needs.

I looked at what was available on NuGet, but the packages available were years out of date and I didn't like having to rely on potentially abandoned packages. So, in the spirit of all the other API clients I've made so far, I rolled my own package: Arex388.OpenWeatherMap. Since I only needed the current weather conditions for a geocoordinate point, I only implemented that functionality, but if there's demand for more I'll expand the functionality. NuGet is available here.

Arex388.Extensions.CsvHelper 1.0.1 Released

The Arex388.Extensions.CsvHelper package has been updated to 1.0.1. This is a minor update that does a simple check if the contents of a CsvDbSet<T> have changed by summing their hash codes. If the hash code hasn't changed then the call to Save() will return early.

Since this blog is now backed by this package I've noticed that the CSV files are always being updated on the server regardless if there was changes or not. This was caused by the Save() method always running because the CSV file that tracks visits to a post is always changing. With this update I'm hoping that only it will be getting updated instead of everything.

Introducing Arex388.AspNet.Mvc.Startup NuGet Package to Simulate ASP.NET Core's Startup.cs in Classic ASP.NET MVC Applications

It's been a while since I wrote anything on here because I've been busy out of my mind, but I recently made something that I want to share with everyone.

At my work, our main application is an ASP.NET MVC 5 app (5.2.7 to be exact). I use Ninject for dependency injection and it has been working well for ~6 years so far. That being said, I was having a very hard time getting AutoMapper's instance API registered with Ninject. I tried the example in AutoMapper's docs, but I couldn't get it to work. Because of this, I couldn't update to AutoMapper 9 where the static API no longer exists.

After spending a few days reading and researching how to get AutoMapper and Ninject to work I ran across a blog post from Scott Dorman about using the Microsoft.Extensions.DependencyInjection NuGet package with classic ASP.NET MVC apps. I tried implementing his example, but couldn't get it to work at all either.

After several more days of research, I stumbled onto a Gist from David Fowler where he takes a slightly different approach. I decided to give it a shot and this time it worked! Finally, I had a working code sample. From there I just messed around with it in a throw-away app to get the hang of it. Once I was satisfied I decided to extract it out into its own library so I could share it on NuGet.

Originally it was called Arex388.AspNet.Mvc.DependencyInjection, but as I progressed through it, I realized that using Owin I can make it essentially simulate ASP.NET Core's Startup.cs file, except it would all be in the Global.asax.cs. So the current version is a mix of code examples from David Fowler and Scott Dorman with some sprinkles of code from me here and there to glue it together.

How to Use

  1. Add the Arex388.AspNet.Mvc.Startup NuGet package.
  2. Change your Global.asax.cs to inherit from StartupApplication.
  3. Add [assembly: OwinStartup(typeof(YourNamespace.MvcApplication))] attribute to the namespace of your Global.asax.cs.
  4. Implement the Configure and ConfigureServices methods inherited from StartupApplication.
  5. Add ConfigureServices() to the end of Application_Start.

Here's a more complete example:

[assembly: OwinStartup(typeof(YourNamespace.MvcApplication))]
namespace YourNamespace {
    public class MvcApplication :
        StartupApplication {
        public void Application_Start() {
            //	Other setup and configuration code here...

            ConfigureServices();
        }

		public override Configure(
			IAppBuilder app) {
			//	Add IAppBuilder configurations
        }

        public override void ConfigureServices(
            IServiceCollection services) {
            var assembly = typeof(MvcApplication).Assembly;

            //	Add your controllers
            services.AddControllers(assembly);

            //	Add other services that have IServiceCollection extensions
        }
    }
}

Conclusion

As you can see it's very simple and easy, seems to "just work" and for me at least has helped me make sure my ~6 year old project is still keeping up with ASP.NET Core somehow.

And with that here's a delayed Christmas present to end off 2019! The source code is available on GitHub, and the package is available on NuGet.

Arex388.Geocodio 1.2.2 Released

This is a minor update to add the Metropolitan Divisions property for Census data.

Projection-Result Pattern: Improving on the Projection-View Pattern...

If you haven't already, I would recommend you read through my original post on the Projection-View Pattern first even though this post is technically a prequel to it. While that pattern is still fine, and I still continue to use it and I will not be changing that, I found myself wanting to use it in non-view workloads.

Specifically, in my project at work, I have quite a lot of code that needs to project data out of the database and transform it, but it never returns a view to the screen. It might be sending off an email, or generating a file, outputting JSON, or something else entirely.

I used to just adapt to what I needed at the time and inline my projections, but it felt highly disconnected considering I had been using the Projection-View Pattern with great results and success for my views. Then it kind of hit me that the view was nothing more than a result of the projection, and the result could be anything, not just a view.

So, I decided to step back a moment and after some more thought and tinkering, I settled on a base pattern that I've dubbed the Projection-Result Pattern. You're amazed at my naming skills, I know...

Also, since the original post for the Projection-View Pattern, I've changed up how I use MediatR, and I now implement IRequestHandler<TRequest, TResponse> instead of HandlerBase<TRequest, TResponse>. Here's the entire stack of base classes as I am currently using them:

  • AsyncHandlerBase<TRequest> is a simple handler that doesn't return a result.
  • AsyncHandlerBase<TRequest, TResponse> is a simple handler that does return a result.
  • AsyncProjectionHandlerBase<TRequest, TProjection, TResult> is a slightly more complex handler that does data projection and returns a result.
  • QueryHandlerBase<TQuery, TProjection, TView> is an optional handler, but it has its place when I'm returning views. As I'm writing this I'm starting to think that maybe it should be called something different like ViewHandlerBase<TQuery, TProjection, TView> to express it's intent more clearly, but I'll have to sleep on it for a bit. I slept on it and I've accepted it, so it is now called ViewHandlerBase.

Now let's look at the code for each of them. For the purpose of the example, we'll pretend there's a DbContext class called MyDbContext that's being injected. Of course, you may not need to inject anything or you just want to use the built-in handler base classes, and that's perfectly fine, I'm just showcasing how I've decided to use MediatR.

AsyncHandlerBase<TRequest>

public abstract class AsyncHandlerBase<TRequest> :
    IRequestHandler<TRequest>
    where TRequest : IRequest {
    protected MyDbContext Context { get; }
    protected IMapper Mapper { get; }

    protected AsyncHandlerBase(
        MyDbContext context,
        IMapper mapper) {
        Context = context;
        Mapper = mapper;
    }

    public abstract Task<Unit> Handle(
        TRequest request,
        CancellationToken cancellationToken = default);
}

AsyncHandlerBase<TRequest, TResponse>

The AsyncHandlerBase<TRequest, TResponse> class has an additional property called MapperConfig which I pass to the .ProjectTo<T>() AutoMapper extension methods when I need to. It's slightly less typing than the full Mapper.ConfigurationProvider everywhere. You can remove it if you don't like it or want it.

While I've debated on putting the MapperConfig property in the AsyncProjectionHandlerBase<TRequest, TProjection, TResult> class only, I decided against it because you may end up using the projection extension methods in a class inheriting from this one as well.

public abstract class AsyncHandlerBase<TRequest, TResponse> :
    IRequestHandler<TRequest, TResponse>
    where TRequest : IRequest<TResponse> {
    protected MyDbContext Context { get; }
    protected IMapper Mapper { get; }

    protected IConfigurationProvider MapperConfig => Mapper.ConfigurationProvider;

    protected AsyncHandlerBase(
        MyDbContext context,
        IMapper mapper) {
        Context = context;
        Mapper = mapper;
    }

    public abstract Task<TResponse> Handle(
        TRequest request,
        CancellationToken cancellationToken = default);
}

AsyncProjectionHandlerBase<TRequest, TProjection, TResult>

public abstract class AsyncProjectionHandlerBase<TRequest, TProjection, TResult> :
    AsyncHandlerBase<TRequest, TResult>
    where TRequest : IRequest<TResult>
    where TProjection : class, new()
    where TResult : class {
    protected AsyncProjectionHandlerBase(
        MyDbContext context,
        IMapper mapper) :
        base(context, mapper) {
    }

    public override Task<TResult> Handle(
        TRequest request,
        CancellationToken cancellationToken = default) {
        var result = GetResult(request);

        return Task.FromResult(result);
    }

    protected virtual TProjection GetProjection(
        TRequest request) => new TProjection();

    protected virtual TResult GetResult(
        TRequest request) {
        var projection = GetProjection(request);
        var result = Mapper.Map<TResult>(projection);

        NormalizeResult(request, projection, result);

        return result;
    }

    protected virtual void NormalizeResult(
        TRequest request,
        TProjection projection,
        TResult result) {
    }
}

QueryHandlerBase<TQuery, TProjection, TView>

Lastly, we have the QueryHandlerBase<TQuery, TProjection, TView> class, which is optional, but I've found it useful since I only use it to return views and I usually need to have access to the user identity. In this example, I'm also injecting the IdentityProvider from my Arex388.AspNetCore NuGet package. I also constrain the TProjection and TView parameters to inherit from the ProjectionBase and ViewBase base classes.

public abstract class QueryHandlerBase<TQuery, TProjection, TView> :
    AsyncProjectionHandlerBase<TQuery, TProjection, TView>
    where TQuery : IRequest<TView>
    where TProjection : ProjectionBase, new()
    where TView : ViewBase {
    protected IdentityProvider Identity { get; }

    protected QueryHandlerBase(
        MyDbContext context,
        IMapper mapper,
        IdentityProvider identity) => Identity = identity;
}

Summary

With all of that code, I'm wrapping up this post. Really, the Projection-Result Pattern should be thought of as a generic version of the Projection-View Pattern, but it doesn't replace it. Both patterns have their places and use. The Projection-View Pattern simply specializes the Projection-Result Pattern when dealing with returning views to the user.

I hope either pattern will help someone in their coding, they've surely helped me in improving my data access as well as standardizing on a common coding pattern. Between the two patterns, I probably have about 250 or more classes that inherit from them in my work's project.

Arex388.SunriseSunset 1.0.0 Released

I'm starting a new project, and it has a requirement to be able to pull the sunset time for each day. I looked around a bit for an API and found that sunrise-sunset.org has such an API.

I figured I might as well add to my collection of API clients, so I made a C# client for it. It's called Arex388.SunriseSunset, as you might have guessed by now.

The source code is available on GitHub, and a package is available on NuGet.

Arex388.Geocodio 1.2.0 Released

This update includes backwards compatibility support. The GeocodioClient now accepts a third argument for the endpoint version. By default the client will always use the latest version, but it can be changed using the new EndpointVersions constant.

Arex388.Geocodio 1.1.0 Released

This update includes full support for all fields and their return values. Originally, I had implemented the lookup for fields, but I omitted the return values for some reason. Since Geocodio had an update to the fields I decided to rectify this omission. Please be aware that field lookups will result in additional charges from Geocodio.

Projection-View Pattern: Improving on the Vertical Slices Architecture

Around four and a half years ago, I started a project at my work with the goal of it becoming our admin system and to remove our painfully expensive dependency on Salesforce. When I started the project, I applied a layered design to the architecture because I thought it was going to be robust and scalable, and everyone was doing it. After some time, it started to become clear that it was anything but that. Time was precious and I had to commit to the architecture.

The solution was split into 10 different projects. Some were utilities or extensions, and others were the core of the system. Those core projects were very tightly coupled to each other and were very rigid. Changes needed to propagate all the way through all the layers and sometimes they didn't quite fit or feel right. Slowly, but surely, the system started to become difficult to maintain, and almost impossible to add new features to.

As I kept going with this monster I had created, I happened to read an article by Jimmy Bogard about the Vertical Slices architecture. I "understood" it, but it didn't become very clear until I watched the recording of a talk he did about the architecture. There's a more recent talk he did on the architecture that I found as I was preparing my material for this post. In the talks he shows how MediatR came about and how to use it to implement a Vertical Slices architecture, so I decided to give it a shot since the layered architecture I was using wasn't going to get any better.

I had some trial and error periods until I started to get the hang of it and morph my thought process to the new architecture. While I started to get some improvements, I also started to run into issues with the way I was querying the database. Jimmy came to the rescue again with another article where he spoke of Entity Framework Plus and its future queries.

After implementing EFP the load on the database improved, but it wasn't quite enough. You see, I was carrying over a relic from the old architecture where I had set up massive projections in AutoMapper to literally project into a complete View. The more data I was trying to query out into a view, the larger and more bloated the queries became. Entity Framework didn't help with the bloat that it generates, but I was easily having queries that were 200+ lines long.

I thought about how to improve the situation and realized that the answer was actually really simple, just break it up into smaller queries. The query into a view "pattern" came about because I was trying to be efficient when querying the database. With EFP in the picture now, I could accomplish the same thing, without having bloated, complex queries.

After breaking up the queries I saw massive improvements, but I also noticed that the projection models didn't always match the view models. This is how what I call the Projection-View pattern came to be. I split the query handlers into two mappings. First, I projected the data from the database into DTOs, then, I mapped those projections to the final view models. Sometimes the projection and view models were the same, but quite often they were not.

So, what does the Projection-View Pattern Look Like?

Let's see if I can make this make more sense with some code examples. First, I introduced a couple of base classes:

  • ProjectionBase, which was responsible for holding onto the projection models.
  • ViewBase, which was responsible for the final view models.
    • Technically, I already had this from long ago, but it was serving a new more proper purpose.
  • QueryHandlerBase<TQuery, TProjection, TView>, which was the new handler for the queries and would perform the mapping of projections and views.

Here are the actual classes.

public abstract class ProjectionBase {
}

public abstract class ViewBase {
}

public abstract class QueryHandlerBase<TQuery, TProjection, TView> :
    HandlerBase<TQuery, TView>
    where TQuery : IRequest<TView>
    where TProjection : ProjectionBase, new()
    where TView : ViewBase {
    protected QueryHandlerBase(
        MyDbContext context,
        IMapper mapper) :
        base(context, mapper) {
    }

    protected override TView Handle(
        TQuery query) => GetView(query);

    protected virtual TProjection GetProjection(
        TQuery query) => new TProjection();

    protected virtual TView GetView(
        TQuery query) {
        var projection = GetProjection(query);
        var view = Mapper.Map<TView>(projection);

        Normalize(projection, view);

        return view;
    }

    protected virtual void Normalize(
        TProjection projection,
        TView view) {
    }
}

The QueryHandlerBase<TQuery, TProjection, TView> class inherits from HandlerBase<TRequest, TResponse> class because it contains the MyDbContext and IMapper properties. The HandlerBase class is also inherited by all command handlers for this same reason.

What About a Real Code Example?

So, how would we use the above QueryHandlerBase then? Let's pretend we have an admin system (built on ASP.NET Core) for a construction company and we need to add, edit and list jobs. Our Add, Edit and List slices would look like this:

Add

public sealed class Add {
    public sealed class Command :
        IRequest<bool> {
        public int? CsrId { get; set; }
        public string Name { get; set; }
        public int? StateId { get; set; }
        public int? StatusId { get; set; }
        public int? TypeId { get; set; }
    }

    public sealed class CommandHandler :
        HandlerBase<Command, int> {
        public CommandHandler(
            MyDbContext context,
            IMapper mapper) :
            base(context, mapper) {
        }

        protected override void Handle(
            Command command) {
            var job = Mapper.Map<Job>(command);

            Context.Add(job);
            Context.SaveChanges();

            return job.Id;
        }

        public sealed class Query :
            IRequest<View> {
        }

        public sealed class QueryHandler :
            QueryHandlerBase<Query, Projection, View> {
            public QueryHandler(
                MyDbContext context,
                IMapper mapper) :
                base(context, mapper) {
            }

            protected override Projection GetProjection(
                Query query) {
                var countries = Context.Countries.OrderByDescending(
                    c => c.Name).ProjectTo<SelectListGroup>(MapperConfig).Future();
                var projection = base.GetProjection(query);

                projection.CsrsSelectListItems = Context.Employees.Where(
                    e => e.IsActive).OrderBy(
                    e => e.Name).ProjectTo<SelectListItem>(MapperConfig).Future();
                projection.StatesSelectListItems = Context.States.Where(
                    s => s.IsActive).OrderBy(
                    s => s.Name).ProjectTo<SelectListItem>(MapperConfig, new {
                        countries
                    }).Future();
                projection.StatusesSelectListItems = Context.Statuses.Where(
                    s => s.IsActive).OrderBy(
                    s => s.Name).ProjectionTo<SelectListItem>(MapperConfig).Future();
                projection.TypesSelectListItems = Context.Types.Where(
                    t => t.IsActive).OrderBy(
                    t => t.Name).ProjectTo<SelectListItem>(MapperConfig).Future();

                return projection;
            }
        }

        public sealed class Projection :
            ProjectionBase {
            public QueryFutureEnumerable<SelectListItem> CsrsSelectListItems { get; set; }
            public QueryFutureEnumerable<SelectListItem> StatesSelectListItems { get; set; }
            public QueryFutureEnumerable<SelectListItem> StatusesSelectListItems { get; set; }
            public QueryFutureEnumerable<SelectListItem> TypesSelectListItems { get; set; }
        }

        public sealed class View :
            ViewBase {
            public IList<SelectListItem> CsrsSelectListItems { get; set; }
            public Command Job { get; } = new Command();
            public IList<SelectListItem> StatesSelectListItems { get; set; }
            public IList<SelectListItem> StatusesSelectListItems { get; set; }
            public IList<SelectListItem> TypesSelectListItems { get; set; }
        }
    }
}

Edit

public sealed class Edit {
    public sealed class Command :
        IRequest<bool> {
        public int? CsrId { get; set; }
        public int Id { get; set; }
        public string Name { get; set; }
        public int? StateId { get; set; }
        public int? StatusId { get; set; }
        public int? TypeId { get; set; }
    }

    public sealed class CommandHandler :
        HandlerBase<Command, bool> {
        public CommandHandler(
            MyDbContext context,
            IMapper mapper) :
            base(context, mapper) {
        }

        protected override void Handle(
            Command command) {
            var job = Context.Jobs.SingleOrDefault(
                j => j.Id == command.Id);

            if (job is null) {
                return false;
            }

            Mapper.Map(command, job);

            Context.SaveChanges();

            return true;
        }

        public sealed class Query :
            IRequest<View> {
            public int Id { get; set; }
        }

        public sealed class QueryHandler :
            QueryHandlerBase<Query, Projection, View> {
            public QueryHandler(
                MyDbContext context,
                IMapper mapper) :
                base(context, mapper) {
            }

            protected override Projection GetProjection(
                Query query) {
                var countries = Context.Countries.OrderByDescending(
                    c => c.Name).ProjectTo<SelectListGroup>(MapperConfig).Future();
                var projection = base.GetProjection(query);

                projection.CsrsSelectListItems = Context.Employees.Where(
                    e => e.IsActive).OrderBy(
                    e => e.Name).ProjectTo<SelectListItem>(MapperConfig).Future();
                projection.Job = Context.Jobs.Where(
                    j => j.Id == query.Id).ProjectTo<Command>(MapperConfig).DeferredSingle().FutureValue();
                projection.StatesSelectListItems = Context.States.Where(
                    s => s.IsActive).OrderBy(
                    s => s.Name).ProjectTo<SelectListItem>(MapperConfig, new {
                        countries
                    }).Future();
                projection.StatusesSelectListItems = Context.Statuses.Where(
                    s => s.IsActive).OrderBy(
                    s => s.Name).ProjectionTo<SelectListItem>(MapperConfig).Future();
                projection.TypesSelectListItems = Context.Types.Where(
                    t => t.IsActive).OrderBy(
                    t => t.Name).ProjectTo<SelectListItem>(MapperConfig).Future();

                return projection;
            }
        }

        public sealed class Projection :
            ProjectionBase {
            public QueryFutureEnumerable<SelectListItem> CsrsSelectListItems { get; set; }
            public QueryFutureValue<Command> Job { get; set; }
            public QueryFutureEnumerable<SelectListItem> StatesSelectListItems { get; set; }
            public QueryFutureEnumerable<SelectListItem> StatusesSelectListItems { get; set; }
            public QueryFutureEnumerable<SelectListItem> TypesSelectListItems { get; set; }
        }

        public sealed class View :
            ViewBase {
            public IList<SelectListItem> CsrsSelectListItems { get; set; }
            public Command Job { get; set; }
            public IList<SelectListItem> StatesSelectListItems { get; set; }
            public IList<SelectListItem> StatusesSelectListItems { get; set; }
            public IList<SelectListItem> TypesSelectListItems { get; set; }
        }
    }
}

List

public sealed class List {
    public sealed class Query :
        IRequest<View> {
    }

    public sealed class QueryHandler :
        QueryHandlerBase<Query, Projection, View> {
        public QueryHandler(
            MyDbContext context,
            IMapper mapper) :
            base(context, mapper) {
        }

        protected override Projection GetProjection(
            Query query) {
            var projection = base.GetProjection(query);

            projection.Jobs = Context.Jobs.OrderBy(
                j => j.Name).ProjectTo<JobProjectionView>(MapperConfig).Future();

            return projection;
        }
    }

    public sealed class Projection :
        ProjectionBase {
        public QueryFutureEnumerable<JobProjectionView> Jobs { get; set; }
    }

    public sealed class View :
        ViewBase {
        public IList<JobProjectionView> Jobs { get; set; }
    }

    public sealed class JobProjectionView {
        public string CsrName { get; set; }
        public int Id { get; set; }
        public string Name { get; set; }
        public string StateName { get; set; }
        public string StatusName { get; set; }
        public string TypeName { get; set; }
    }
}

The Add and Edit slices are quite similar but there are subtle differences that change the projection requirements. I don't use the Normalize() method in this example, but it exists for the few times when you have to manually intervene when mapping from a projection to a view. In the linked video I go into a bit more detail by taking a starter MVC app and morphing it to use the Projection-View pattern.

Concluding the Pattern

That pretty much covers the Projection-View pattern. All I've done is slightly expanded on Jimmy's Vertical Slices architecture and split the projections and views into different models. In my project at work, I have probably 200 or more slices using this pattern so I'm quite confident that it's proven itself. I do have a series planned in the near future where I demonstrate this pattern as well as other techniques in a more functional and realistic example.

I hope I've done a good job explaining the Projection-View pattern and how it can be beneficial to you. I would appreciate it if you watched the linked video and, if you think it was helpful, please leave a like on it. Thanks!

Source Code

The source code can be found here.

API Client Design Patterns I Learned

Over the past couple of years as I've been making API clients to integrate with various services for my own needs, I settled on a design pattern that was inspired from the AWS SDK clients. Every operation is its own self contained unit that has an object describing the request. Depending on the complexity of the request there may be some helper methods for common operations. For example, using the Geocod.io client:

var response = await geocodio.GetGeocodeAsync(
    "1600 Pennsylvania Ave NW, Washington, DC 20500"
);

...and:

var response = await geocodio.GetGeocodeAsync(new GeocodeRequest {
    Address = "1600 Pennsylvania Ave NW, Washington, DC 20500"
});

...do the same request. In fact the first one calls into the second one. This way I can perform a quick simple call or if I need to I can build out a more complex request and pass it through.

In the Kraken.io client, I would probably use custom requests more often depending on my optimization needs because there's so many options that can be configured on how the image should be optimized. Creating a helper method for all those options is simply unpractical and a waste of time.

The same pattern can be applied to the client constructor as well, for example:

public AbcClient(
    string key);

...and:

public AbcClient(new AbcClientOptions {
    Key = "abc"
});

...would create the same instance. I haven't had to use constructor overloads like this yet because the APIs I've integrated with weren't complex enough to warrant it, but the possibility remains. I've yet to find an API where this pattern is not applicable.

Granted, people that spend their time writing API clients, or software really, probably know this already and this post would seem silly to them, but maybe you don't and I hope this helps you settle on a pattern for the API client you might be developing.