Generic Repository & Dependency Injection with .NET Core 23


With the release of .NET Core in late June, everything is new again! It’s incredibly exciting to be a developer in the .NET stack. Kudos to Microsoft and the .NET team for a job well done.

With all of the frenzy I thought I might put together a little sample project. This will be an example of how to get started using a Generic Repository, the built-in Dependency Injection framework, Entity Framework Core, and the new .NET Core.

 

Generic Repository

I’ve been using a Generic Repository in some form or fashion for the last few years. I find it best to abstract away the details of the data access layer from the rest of the application. By using a Generic Repository, it’s much easier to keep from business logic creeping in where it doesn’t belong.

My preference is to keep the Repository as simple and clean as possible. No more than simple CRUD (Create, Read, Update, and Delete) routines should exist here. You may notice that I’ve omitted the Delete in this case. I find it best never to delete anything, choosing instead to mark a record inactive with a simple update.

Let’s start with a simple Interface:

And the implementation:

By using the Generic Repository you can eliminate having numerous explicit repository classes strewn throughout your application. Where you might normally have 1 repository class per database object, now this can be handled by a single Generic Repository.

Of course the Generic Repository pairs up nicely with Entity Framework, my current ORM of choice. There are a few caveats with the first release of EF Core, however.

 

Entity Framework Core

dbfindThanks to Julie Lerman and the Entity Framework team for replying to my tweet regarding DbSet.Find. Find has not yet been implemented, but there are plenty of examples of extension methods to implement this. You’ll notice that I’ve included Find in my Generic Repository, so you’ll either have to implement an extension method, use a nightly build, or wait for the 1.1 release of EF Core.

Julie was kind enough to follow up with a blog post about the roadmap, and a few days later the EF team posted Entity Framework Core 1.1 Plans. More exciting enhancements, improvements, and implementations of missing features to come.

Another potential issue to be aware of, lazy loading has not yet been implemented. While not terribly alarming, if you’ve depended on this in the past, you’ll need to take this into account by using the Include extension or explicit joins within your queries.

As an exercise I would ask you to implement Find on your own.

 

Dependency Injection

It seems the .NET Framework finally has a first-class Dependency Injection Framework. I’ve used a variety of 3rd party Dependency Injection Containers in the past. I’m happy to see the setup and usage of the new DI Framework is as simple and straight forward as many of the other popular players.

Just a few lines to get you started injecting a Generic Repository and a Service from our Business Layer:

Here you can see that we’re injecting the Generic Repository with an empty type argument. Normally we would have to define a specific typed repository (ie: services.AddScoped(IRepository<User>, Repository<User>)). By defining the signature with typeof(IRepository<>) argument we’re able to tell our DI framework to declare and inject the proper concrete class at run-time.

And of course, don’t forget to include your DbContext, which will be used by our Repository:

 

Example Project

I’ve put together a complete solution to play with and made it available on GitHub. Feel free to download, play around, and submit pull requests.

###

Any updates will be listed below:

  • 8/04/2016 – Initial post

 

A Microsoft MVP, John has been a professional developer since 1999. He has focused primarily on web technologies and has experience with everything from PHP to C# to ReactJS to SignalR. Clean code and professionalism are particularly important to him, as well as mentoring and teaching others what he has learned along the way.


Please Consider Sharing This Post:

Facebooktwittergoogle_plusredditlinkedinFacebooktwittergoogle_plusredditlinkedin
  • codecore
    • Thanks for pointing this out. I’ve fixed the link.

  • Paul H

    The trouble with calling SaveChanges within the repository is that you remove the ability to use DbContext as your unit of work. If you needed to update multiple aggregates, you cannot do it in a single transaction with this design.

    • A valid concern. With any pattern or practice it’s best to evaluate and adjust to fit your needs. Here, I’m leaning on the DI container to manage my unit of work. You could of course modify the methods of the Repository if needed.

  • Alex

    Yet another good code for simple, useless, toy apps and not real world systems. What about complex queries? performance? transactions? custom SQL? but hey, what can you expect from a “.NET web developer” who uses wordpress for all its projects

    • Hi Alex, thanks for your comments. This is not meant to be an end-all approach, merely a good start. There’s nothing preventing the use of transactions (implicit or explicit) with this solution. I’ve used the same or similar approach on a number of different small, medium, and high volume sites with no performance issues. As with anything, this should be measured, analyzed, and addressed on an as-needed basis. If something comes up that needs to be addressed separately there’s no reason the Repository can’t be extended or something else substituted in it’s place.

  • Martin Dann

    Hi John, Say I want to do an integration test on a Repository layer method to see if I can return the correct data from the DB.
    How would I set up a test that leveraged the dependency injection already defined in the API project. Also how are Configuration settings accessed from outside the API project?

    • Hi Martin,

      For your integration test I suppose it depends on what and how much of the system you’re trying to test. Of course, you could leverage whatever you want for DI, or just new up a concrete class in your setup, depending on what you’re trying to accomplish and what you’re trying to test.

      Here’s a link to some pretty good documentation on Integration Testing with .NET Core, https://docs.asp.net/en/latest/testing/integration-testing.html.

      There’s some great new stuff in EF Core with DI and InMemory databases to aid in testing. I almost never write any level of tests that hit an actual database. I’ll try to put together a post on this soon.

      • Martin Dann

        Thanks John, I’ll check it out.
        I tend to want to test my repository layer to make sure the data I have queried is mapping correctly to my model objects. I have moved away from EF because I’ve had some really frustrating experiences with it in terms of stale data and problems saving data with child objects. I’m favoring Dapper now at the repository layer, for me it takes away the smoke and mirrors and lets you do what you intended. For this reason I feel like I need to test out any parameterized SQL to check the mapping is OK.
        Also I like to test that Update / Inserts work as expected and I don’t encounter any SQL errors.

  • Mike J

    Hi John –

    Can you walk through what this line is doing that’s in your project…

    services.AddScoped(typeof(IMapper), typeof(HorseToHorseSummaryMapper));

  • Ghulam Haider

    Great article…. can you please advise me that how I can implement the Delete and Get methods. I have implemented everything but struck here.

  • Gary

    Thanks for this, really helped! Just needed to know the syntax

    • You’re very welcome, Gary. Glad this post helped.

  • jameswilson122

    Hi, John. Thanks for sharing this, I’ve found it very useful. One of the problems I see with this is that you still require a separate service for each entity in your context. Am I missing something?

    • Yes and no. In the example there are separate services per entity. The example is a bit contrived, simply as an example. You could certainly create a generic/base service for lookup tables for example. In a real world example you would likely only create a service to handle a requirement or set of requirements. This is where your business logic would mostly likely go. As it is 1-to-1 it isn’t providing much use. Keep in mind YAGNI and DRY and you should be fine.

      Thanks for the comment!

  • Great! Thanks!

  • Kuttikrishnan Kodoth

    Hi John ,
    The DI built in to ASP.NET Core requires you to wire-up your concrete implementations within the Startup class. However, the Startup class is defined in the Web API Project. This means that the web app project needs to reference (nearly) all other projects and, with that, we lose our loose coupling.

    • Hi Kuttikrishnan, that is a concern I have as well. I’m currently exploring moving this out of the Web project to avoid this tight coupling. I’ll keep you posted!

      • Kuttikrishnan Kodoth

        Thank you John !

  • Lerry Mashaba

    How to include related entities queries using generic repository and how to create complex queries

    • Hi Lerry. Thanks for the question! You could extend the Repository with something like this:

      IRepository Include(Expression<Func> path);

      This would allow you to use the .Include extension you may be used to in Entity Framework. I’ll try to put another post together outlining more advanced usages. I hope this helps!

  • Mohamed Masrooj

    Hello, im new to ASP .NET Core. Let say i have generated many repositories and services. do i need to add each of then in configure services. or is ther any pattern available to do so?