DbContext decoupling - c#

I already to put my EF related code in a class library and use it in an asp.net webapi project.
However I still have the following code in my webapi project.
services.AddDbContext<MyOwnDbContext>(
ops => ops.UseSqlite(connection, optionsBuilder => optionsBuilder.MigrationsAssembly("MyProject.API")));
Is there a way to decouple 'MyOwnDbContext: DbContext' class completely from webapi project (using a factory or an interface). Or this is an unnecessary concern? I just don't want to use EF related library in two projects.

I would leave it alone, since you still have to have installed Entity Framework in the entry project so that the library can use it (or hack the way through by copying files manually, but let's not get into that).
However, this is what I did in a recent project where I wanted to keep all my services in a single place, different to the Startup class:
Install Microsoft.Extensions.DependencyInjection to the project where you want your DbContext.
Add something like this:
public static class Injector
{
// you probably want to pass the connection string or an Options class here too
public static IServiceCollection Inject(this IServiceCollection services)
{
services.AddDbContext<...>(...);
return services;
}
}
Inject it, rather than the context itself:
public void Configure(IServiceCollection services)
{
services.Inject();
// and whatever else you need
services.AddMvc();
}
Like this, you do not win a lot, but you could keep going as I mentioned at the beginning.

This is an uneccessary concern. You put this into the root of your application (Startup.cs). Everything is hardwired here (Dependency Injection Container, Contexts, Logging,...).
In fact there is no better place to put it. Because the configuration of the context itself is of no concern for any layer below the application level. Your DAL/Repositories just use the already configured context and that's it.

Related

How can I EFCore DB Context in an N-Tier architecture with an ASP.NET Core application?

I've been trying to follow an asp.net mvc core tutorial online and I noticed that when using entity framework you can enable it in ConfigureServices in the application start up file like so:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyContext>(cfg => cfg.UseSqlServer());
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
but what if I intend to use an n-tier architecture having different projects for the domain and data layers?
So I wouldn't have a reference to EntityFramework or the DBContext in my API layer as these would be separated by a domain layer?
The only solution that comes to mind is to add the Context to a "Common" project but that doesn't feel like the right thing to do?
How would you guys solve this?
This problem is negligible in terms of architecture, but if you are really concerned about separating the EF dependencies into a separate project then you can just separate the dependency injection layer alltogether into separate project and use reference only to that in multiple other projects.
EDIT:
I may not have been elaborate enough on this so here is an example of what I meant. I assume your Example.Domain has some repository which references the your EF YourDbContext
public class YourDomainRepository
{
private readonly YourDbContext _context;
public YourDomainRepository(YourDbContext context)
{
_context = context;
}
...Other repository methods
}
The issue you are describing is that it's not enough to just reference the Example.Domain in your Example.Api because in order for the DI to work you need to add it to the services and you need to add both YourDomainRepository and other services on which it depends (like YourDbContext) which in turns what requires you to reference EF libraries.
So the approach I tried to propose is either:
Option 1 - you create another project for common stuff like DI. That project would house a function like below:
public static class YourDomainDIExtensions
{
public static void AddDomainDataServices(this IServiceCollection services)
{
services.AddDbContext<YourDbContext>(...);
services.AddTransient<YourDomainRepository>();
}
}
Option 2 - you don't create a new project and just have the same extension class in your domain project.
Either way this abstracts the EF dependencies from your Example.API and in there you will just call:
services.AddDomainDataServices();
Which effectively is reusable across multiple projects.
What I am currently doing is creating an extension in my business logic project which has a reference to the data access project that encapsulates EF Core.
The structure is the following:
API (ASP.NET Core API - references Services)
Services (Business Logic - References DataAccess)
DataAccess (EF Core Here)
In my Services project I have an extension like this:
public static class AppExtensions
{
public static IServiceCollection SetUpAppDependencies(this IServiceCollection serviceCollection,
string connectionString)
{
serviceCollection.AddDbContext<MyDbContext>(options => options.UseSqlServer(connectionString));
return serviceCollection;
}
}
Then in ConfigureServices I do this:
// connectionString should come from KeyVault or Configuration
services.SetUpAppDependencies(connectionString);
You only need entity framework in the project (i.e., tier) that actually touches the database. Other projects in the solution can add a reference to the project encapsulating entity framework. For example:
This is a simplistic example, but the Data project has references to EF. The UI project has references to the Data project. In larger projects, I might even have an API project in between the Data and UI tiers. In those cases, the UI project wouldn't reference either the Data or API projects, as it is entirely UI. That is, the UI project wouldn't have controllers, like the simple example does.

Using ADO.NET for a Data Access Layer in ASP.NET Core

I'm trying to roll a high performance DAL for my ASP.NET Core API. I want to use ADO.NET and I am having difficulty designing the software architecture. I'm looking for help discussing a good approach.
What I Have
My codebase will consist of three projects
MyApp.API
MyApp.Repositories (data access layer)
MyApp.Services (business logic)
I'll implement IUnitOfWork within MyApp.Repositories and create a concrete SqlUnitOfWork in MyApp.API. Startup.cs will register IUnitOfWork to SqlUnitOfWork. Later on, when I get more data sources (Mongo, etc.), I can incorporate a UnitOfWorkFactory.
Questions
Should I register each repository in Startup.cs or simply add them as properties of IUnitOfWork? The thinking here is I would use Dependency Injection in my Controllers, Services and Repositories, but only have to inject IUnitOfWork.
How do I pass my connection string into the SqlUnitOfWork? I know the connection string should stay within MyApp.API.
The other answer is irrelevant because it is suggesting I use EF, which I want to avoid.
I implemented Dapper with a repository pattern. I did not use a unit of work because I concluded to would lead to performance loses I did not want to have.
Here is a raw prototype I implemented.
https://github.com/lenardchristopher/AdoAspDotNetCoreTest
I believe you are working with aspnet-core thus using Entity Framework as your ORM will work in this situation.
I agree with you on registering your repositories as part of IUnitOfWork then adding it as a service to your DI container which you will then inject in your controllers.
To answer your second question, let's assume that your SqlUnitOfWork implementation has a constructor that receives a DbContext instance.
In ASP.NET Core, the DbContext is added to the DI container and thus
any other service that requires or has a dependency on DbContext in
it's constructor, it will automatically be resolved by the DI
container.
First remember to have your connection string defined in appsettings.json as so.
Then now lets use that connection string to add a DbContext object to our DI container and a little Futher reading on Configuring DbContext in EF Core
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Database")));
}
After that, registering other services to our DI container that need our context will be very easy since the container will resolve that dependency for us.
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IUnitOfWork, SqlUnitOfWork>();
}
Hope this answers your questions. If not, let me know.

Register the DbContext in my repository instead of the WebApi

I have a question regarding the repository and service pattern in combination with ASP.NET Core and EF Core. I'm in the stage of learning all of this, so I might miss the clear picture fully in front of me right now.
My current project structure looks as follows:
Project.Repository.Contracts
Project.Repository.EF
Project.Repository.FakeData
Project.Service.Contracts
Project.Service
Project.WebAPI
WebApp
In my understanding of the repository pattern, only the Project.Repository.EF project does know about EntityFramework.
But all "Repository, Service, ASP, EF" examples register the DbContext in the ConfigureService method in the WebAPI. By calling services.AddDbContext.
Isn't this a break of the concept?
I want to avoid to have the EntityFramework dependency in my WebApi.
So my question is, how can i archieve this?
This is my code so far:
WebApp.Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
Project.WebApi.Module.ConfigureServices(services);
services.AddAutoMapper();
}
}
Project.WebAPI.Module.cs
public class Module
{
public static void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IProjectService, ProjectService>();
services.AddSingleton<IProjectRepository, ProjectRepositoryEF>();
}
}
The Service and Repository are just stubs at the moment.
So again, what I want to avoid is, that I have to call services.AddDbContext in my Project.WebAPI.Module.cs class.
What I want to, is to register the DbContext in my Project.Repository.EF Project without hardcoupling it with my WebAPI.
Is this even possible?
Ok so let me make it a bit clearer for you.
The Repository pattern is more than just a data access layer that does some CRUD operations but I will try to limit my answer just to your problem to help you understand it.
(Keep in mind that the answer below is only relevant if you have a need to use repositories)
First lets talk a bit the naming of your projects.
The project Project.Repository.Contracts should be renamed to Project.Repository.DTOs to make it clearer.
This project contains Data Transfer Objects which is what your DataContext will use to generate your db and handle all the operations.
Then the Project.Service.Contracts can be renamed to Project.Domain in which you will have all your business logic related models.
Automapper will be used to do the two way mapping from dtos to domain objects and vice versa.
Now we will have to split your Project.Repository.EF project to two different projects.
You see, the repositories only need to know about the data context. EF doesn't need to know about the repositories.
So from the Project.Repository.EF project you will create Project.Data and Project.Repository
Your migrations and data context itself is in the Data project while the repositories are in the Repository project which references the Data project.
Now the Data project can be refered in the API project in order to be used in the startup class and as long as the services only know about the repositories project (and the web project only about services), you should be fine.
I would also make an extension method in the Data project instead of a static call like this Project.WebApi.Module.ConfigureServices(services);. It's cleaner.
You can also have your Startup class in a shared project between the dependencies and reference this single project on the project from which you start the host as well. Keep in mind that both DbContext, Services and repositories need to be configured at the IoC somehow. My cuppa is to create assembly markers and use Scrutor to scan for these dependencies.
EDIT: As Camilo suggested however, there's absolutely no need for a repository pattern in Entity Framework Core. EF Core is based on interfaces so you can implement your own classes around them.
The main reason why you would need a repository on top of EF was mocking.
This is no longer needed because:
In memory database built-in into EF Core
Is based on interfaces so you can implement your own classes around them
This may not be the best answer or the one you're looking for, but I hope it helps.
Isn't this a break of the concept?
From an idealistic view, perhaps. The important portion that you're separating out into another project(s) is the implementation of your repository, the setup of your context (mappings, etc).
The value in that is two-fold (at least):
You can reuse these in other projects
You can switch them out with a different implementation (with a matching interface) within the same WebAPI project. For instance, if you were supporting a legacy database and a new database.
Is this even possible?
Possibly with extra work and complexity, but is it practical? IME, I haven't seen a situation where it would improve the readability and maintainability of the code.
The question I would ask is, Am I going to need to dynamically choose between EF and a completely different repository type (such as Dapper, NHibernate, etc)? If the answer is no, or even not in the near future, I wouldn't add to the complexity.
As my grandmother used to say, "Don't borrow trouble." If you do need to completely switch to a different repository framework / ORM down the road, switching out the lines in ConfigureServices will be trivial. It's only complicated if you need to support two or more at once.

Asp.Net core: Get required service via depedency injection in non-controller libraries. E.g. C# Common library

As I am using default dependency inject functionality of Asp.net core, it works great by resolving dependency via Constructor.
E.g.
Registration:
public static void AddServices(this IServiceCollection services, IConfigurationRoot configuration)
{
services.AddScoped<ICookieManager, CookieManager>();
}
Access via constructor:
protected ICookieManager CookieManager { get; set; }
public HomeController(ICookieManager cookieManager)
{
this.CookieManager = cookieManager;
}
The above code works great!
Now, I have a library called Library.Common where I have some common functionality written which can be used by different project.
In my common library code, how would I resolve the dependency without constructor?
I want something like this:
public void CalculateOrder()
{
var cookieManager = ServiceLocator.Instance.GetService<ICookieManager>();
}
Would anybody help me to find out how would I resolve the dependency without constructor in Asp.net core? Like resolving in common library, in static methods without constructor.
Thanks in advance!
Leave it as a constructor injected dependency. If your common library is to be used across multiple projects where DI is used it will work fine (assuming you configure the DI container correctly). If DI is not used you can simply construct an instance of an ICookieManager implementation and pass it into the constructor as an argument.
You could also consider using property injection for the dependency, although this would be most suitable where your method, CalculateOrder(), can still provide some functional value without the ICookieManager dependency.
The existing answer is correct in saying that it's probably better for a multitude of reasons to use constructor DI. If this is a new project inside .NET Core, you are better off doing things right from the start.
That being said, if you have an extreme need for using ServiceLocator or you are migrating a project across and you don't want to have to redo everything in one go to use constructor DI, you can simply create a static ServiceLocator class that uses .NET Core's injectable DI.
An example of this is here : https://dotnetcoretutorials.com/2018/05/06/servicelocator-shim-for-net-core/ Where you just create a static class that simply runs the "GetService" method from .NET Core's Service Collection.

Is there any extensibility point in Asp.Net core to register services anywhere other than startup.cs?

Basically in Asp.Net Core we register services inside startups.cs file. Now the question is , is there any extensibility point in Asp.Net Core giving us the chance to hook into some kind of registrar method (by implementing a specific interface for example) and don't mess up with startup.cs?
Avoid making a mess of Startup
If you just want to avoid making a mess in Startup.cs just delegate the service registration logic to another method, perhaps in another static class.
ServiceRegistry.RegisterAllServices(services);
Hooking into ASP.Net Startup pipeline
If you really want to hack your way into startup logic of ASP.Net I'm afraid you're out if luck. The build up of the ServicesCollection takes place in the BuildCommonServices method. As you can see there is no easy way to hook into the logic here.
In short what happens when an ASP.Net app start is the following:
In .Net core there is only one app model - Console Apps; so Main is called.
Some magic happens and we arrive at StartupLoader.LoadMethods.
Three methods are located Configure, ConfigureContainer and ConfigureServices.
All three lookups are passed to FindMethod which always looks up in the startupType and the startupType only. (REF)
How to register services post startup
Registering additional services into the IOC Container that comes with ASP.Net Core is not trivial.
The DI Framework itself is very basic and if you find yourself trying to do something that is not trivial you probably should upgrade yourself to a more mature and feature complete IOC Container.
You can find some links in the README file on the aspnet/DependencyInjection repository on GitHub.
I have to note though, registering services after the container is created is considered a bad practice.
Good answer here already, but just to add my 2c.
I think what you are essentially looking for is something like "Profiles" or "Modules" and the IOC does an assembly scan. You can do this already, but you would need to create your own interface/reflection code.
Another option is to use the ServiceCollection Extension pattern which seems to be the default way to add "services".
For example take this code :
public static class ServicesConfiguration
{
public static void AddCustomServices(this IServiceCollection services)
{
services.AddTransient<IMyService, MyService>();
}
}
Then your Configure Services method would look more like :
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddCustomServices();
}
In some ways I prefer this as you can still at a glance see what is being loaded in and follow the trail rather than having some mystery reflection going on.
Further reading : http://dotnetcoretutorials.com/2017/01/24/servicecollection-extension-pattern/

Categories

Resources