Dependency Injection with a DAL that has a dynamic connection string - c#

I am trying to build an AspNetCORE WebAPI that has various endpoints you can post to get information from a database.
The problem I am running into is trying to use dependency injection at the root layer to bind my DAL. Each request on the endpoint will carry metadata for the initial catalog. So the connection string has to be built from the request and then opened.
I have built a generic interface to work with my repos and then built a class that implements the interface, but in that implementation it still requires a data source to be newed up which at that point I don't have the DB to connect to.
So this forces me to new up a connection on every request.
If I abstract the DAL into a manager and then use DI to bind the managers, I still am missing the intial catalog detail
The SQL dbs all have the same schema, the only difference is the db name.
Is there a way to bind my DAL at the root while still being able to specify the connection string?
Trying to do this without EF, currently trying to figure out a way to handle this with Tortuga.Chain.

Related

Approach of setting up multi-tenant environment with ASP .NET Core

I have been struggling with the way I should set up my multi-tenant environment. In a previous project I had set it al up as a monolith where there was a tenant entity to bind al the correct data to each other. This way is quite easy to set up but the data of all tenants is in one big database.
My idea now is to set it all up in a different way. I will be using Postgres because of the possibility to also have 'schema'. My idea is to have overall data in the public schema and tenant specific data in the tenants own schema.
There are some struggles that I face where I just can not get my head around. In the picture below, you see a quick sketch of the two scenarios. The bottom one has everything in the public schema where the above one has for example domain and user in the public schema.
My idea with this is that when a customer goes to a tenants specific URL the application does not have to crawl through all possible schemas. Same counts for user. When a user wants to login to the application we also do not want to crawl through all schema's. But how do I set this up in a proper way?
Also when the user manages his domains (add/edit/delete), he is actually managing them on the public schema. Or should I avoid using public at all? I thought of putting them here because otherwise when a user enters a new domain I have to check them also on other tenants schema.
Also can I just simple set the schema name of the tenant in the domain or should this be a connectionstring?
I also read here and there about multi-tenancy but I'm unsure how the application can get the data of a tenant with the use of a different schema (public) to fetch the correct data from the tenants schema.
Should I use Inversion of Control to get a specific implementation depending on calling for Domain (public schema) or customer (tenant specific)?
https://nebulab.it/blog/how-to-switch-solidus-ecommerce-to-multi-tenant/
https://michael-mckenna.com/multi-tenant-asp-dot-net-core-application-tenant-resolution
Which Multi-tenant approach is recommended
I personally do something like your first approach + multidatabase using a first database that tells me where each tenant is located. I call it routing database.
That dB has 2 tables.
databases (if, connection string)
tenants (tenant info, database if)
This way I have the data across multiple databases and still multiple tenants per database.
Also the database id => connection string is cached usually with redis so no need to hit the dB on every request (you can even use in memory for this) with cachemanagercore library.
If a tenant requires its own database not shared is easy to handle too.
Usually a cookie with the dB id picked up on a Middleware and acceded then by a DatabaseResolver class injected where you need to access the dB with a method like DbContext Getdatabse () is all you need

Access connection string in data layer

I'm currently developing a web API in .NET core. I have three projects in my solution with the following references:
Web -> Services -> DataAccess
So the web layer does not have a direct reference to the DataAccess layer.
My question is: What is the right way to get the connectionstring in this type of architecture with three layers? I have read around, but can't find any nice solution where I can access my connectionstring in the third layer, just because the web layer does not have a reference to the third layer.
I came accross this approach:
services.Configure<ConnectionConfig>(Configuration.GetSection("ConnectionStrings"));
services.AddScoped<IQueryHelper>(c => new QueryHelper(cn));
This work well if I just have two layers, where the QueryHelper is in the service-layer.
But I want to access one or multiple connectionstrings in my DataAccess-layer.
Edit: Injecting the configuration might not be the smartest idea as you can read here. Better way would be to configure options for each connection string that can be accessed by the DAL aswell.
services.Configure<MyConnectionInfo>(options => Configuration.GetSection("MyConnectionInfo").Bind(options));
Now in your repository just inject IOptions<MyConnection> and use the values.
Old Answer: Just inject your configuration into your datalayer-classes. Before you have to register the configuration with the ioc-container.
services.AddSingleton(typeof(IConfiguration), Configuration);
Now access the connectionstrings you need by injection the instance of IConfiguration. You could also configure more options instead, but injecting the configuration is fine aswell.

ASP.Net Core dependency injection | How to access user or route data upon creation

Scenario
I am working to follow the IoC pattern and use the Microsoft DI Framework, but I'm hitting a wall and can't decide if it's my mindset, my approach, or I'm just doing it wrong.
I have a multi-tenant application that utilizes a Utility class to handle isolation and accessing the data of the tenant based on their unique configuration. The tenant is identified during authentication, but the tenant data has to be accessible and handled based on the request. This Utility class is registered under ConfigureServices in the Startup.cs and the constructor requires two parameters - a TenantDbContext and a Tenant.
public class TenantUtility{
public TenantUtility(TenantDbContext context, Tenant tenant){/*...*/}
}
Problem
Realizing that I'm probably pushing the limits of the DI Framework, I'm trying to build an implementationFactory in the Startup.cs. I've tried two approaches for accessing the tenant Id to build the Tenant object: one is using a User Claim, the second is a Route parameter.
services.AddTransient<TenantUtility>((svc)=> {
var tenantContext = svc.GetService<TenantDbContext>();
var accessor = svc.GetService<IHttpContextAccessor>();
var httpContext = accessor.HttpContext;
//httpContext is NULL...
//How do I get access to the tenant?
Common.Tenant t = new Common.Tenant();
//Set Tenant Identifier in t (once I get it)
return new StudentDataManager(tenantContext, t);
});
In both situations, when I setup the ImplementationFactory inside the Startup.cs, I don't have access to the user and I don't have access to the RouteData (or can't figure out how to get it) -- I even tried using IHttpContextAccessor, but the HttpContext property is null.
Am I approaching the pattern incorrectly? Should I be able to use DI for this level of detail be injected into the Utility before the Utility class is passed into the Controller?
You shouldn't pass in non-DI-managed types into services you want the container to provide for you (in this case, your Tenant parameter). Only request services that the container can provide. If you need a tenant, perhaps another service like an ITenantAccessor could be injected and would be able to get one.
I suspect your implementation could be done in middleware (if not using MVC) or as a filter (if using MVC). In either case, you can use DI from the filter or middleware class to inject your tenant service. In the class's invoke method, you will have access to the current context and request and should be able to do the things you need to. Remember that ConfigureServices runs before the app has started, so there is no context and no request is yet being made.
If you want to see some examples of filters, and especially how to do DI into filters, check out:
https://github.com/ardalis/GettingStartedWithFilters
and
http://ardalis.com/real-world-aspnet-core-mvc-filters
If you want to do it in middleware, then these might help:
https://github.com/ardalis/NotFoundMiddlewareSample
and
http://ardalis.com/using-custom-middleware-to-record-and-fix-404s-in-aspnet-core-apps
It seems to me that what you are injecting in the TenantUtility as a frist parameter is a valid abstraction (though it's probably better to use some interface), but the other one is a value-object. You don't generally inject value objects as they are not abstraction of some operations that you need to perform, but data. So I would pass the Tenant as a parameter to an operation on the TenantUtility class.
Another thing that I can suggest is to use a full-blown DI container like SimpleInjector (there are many others like Ninject, CastlWindsor, etc.). They are much more advanced as far as I know and can easily be integrated. Many of them have .Net Core integration already.

Configuring Entity Framework In ASP.NET 5 using a DAL

I'm trying to completely separate the repository / data access later whilst still using configuration in the main project (through appsettings.json)
My current solution is either to hard code the connection string in the OnConfiguring method in the DbContext which is not ideal. Or perhaps create a config file just for the repository layer and read from that.
I would like the main project (web service in this case) to be completely independent of the data access layer (as I will be communicating to it using a service layer anyway), but be able to configure it at start-up using the default appsettings.json
Is there a good approach of doing this? Or must the main project have a reference to the repository layer.
Project layout:
Project.WebService
- Startup.cs
- EmployeeController.cs
- appsettings.json
Project.Service
- EmployeeService.cs
- EmployeeDTO.cs
Project.DAL
- DbContext.cs
- EmployeeRepository.cs
Project.Entities
- Employee.cs
The WebService references the Service, the Service references the DAL and the DAL references the Entities / POCOs
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
string connString = Configuration["AppSettings:ConnectionString"];
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<MyDbContext>(options => options.UseSqlServer(connString));
}
The above doesn't work anyway with the DbContext being in another class library. The following exception gets thrown.
An exception of type 'System.InvalidOperationException' occurred in
EntityFramework.Core.dll but was not handled in user code
Additional information: No database providers are configured.
Configure a database provider by overriding OnConfiguring in your
DbContext class or in the AddDbContext method when setting up
services.
Which is one reason why I hard-coded the connection string into the OnConfiguring method.
Does anyone have any good approaches / solutions for this or am I missing something? The web service doesn't need to know what database it is talking to, or have any reference to it at all. It simply calls a service, a receives a DTO or, sends a DTO.
Hook up all dependencies:
If you really insist on your webservice not having a reference to your DAL, you could always try an 'IT ops' layer.
Some infrastructure layer (which you can call for instance "InfratructureService", which has a reference to all your projects (webservice, Service, DAL, Entities). In this infrastructure layer you create the container which every project is going to use.
Then all your projects should have a class which is called "ConfigureMe" or something, with 1 method called "Configure" for instance. That method takes as parameter an instance of the container which was build in InfratructureService. At startup your Webservice is going to give "InfratructureService" a sign to build the container and call every "Configure" method of every "ConfigureMe" class of every project it references.
In those "Configure" methods each project can ofcourse register their own depedencies in the container. And voila, all dependencies are known in the container without making unnecessary references and ready to be resolved via constructor injection.
The connectionstring problem:
Now as for your hardcoded connectionstring, you know about configuration in asp.net core right? Once you've set up your configuration as described here you can insert via dependency injection the IOptions anywhere you want. That means also in your DAL.
Let me know if anything is unclear or you can't figure it out.

STE as Data Contract?

Is there any way to share self tracking entities with client tier(from server tier which is WCF) like Data Contract.
I mean, do not include any assembly with STE to client, just get them from server e.g.
If "DAL" is the service reference, I want some like:
DAL.SomeEntity = new DAL.SomeEntity();
Self tracking entities must be shared with client in form of code or assembly. That is the main requirement to use them because they are not just a contract they also contain logic responsible for change tracking and this logic cannot be shared with the client in any other form.

Categories

Resources