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.
Related
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.
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.
Scenario:
I am consuming a web service in my class library project and it generates a binding name and end point in app.config. If I reference the class library in my UI project, I also have to include the same configuration in web.config. My problem is I don't want to include this configuration in web.config because of the dependency. I want to use assembly as it own with out any dependency.
My solution approach:
When I create the instance of proxy class in the class library project it shows me constructor to pass binding and endpoint.
Example
wsProxy proxyClass = new wsProxy(System.ServiceModel.Channels.Binding binding, System.ServiceModel.Endpoint endpoint)
I was wondering if I can pass the same binding and endpoint that I have in app.config so that I don't have to include either in app.config and web.config.
Yes, you can create these classes without having matching configuration in the main .config file. Where you get that configuration is up to you; it could be App.config, a YML configuration file, a database, etc. As long as your code satisfies the constructor requirements for the classes you're instantiating, you'll be fine.
With WCF, everything defined in your configuration file can be done programmatically.
You just need to create the objects needed to instantiate your client. Depending on the WCF features you want your application to be leveraging, you'll need classes like EndpointAddress, AddressHeaderCollection, Uri, EndpointIdentity (DnsEndpointIdentity or SpnEndpointIdentity), Binding (WSHttpBinding, NetTcpBinding etc.). And you might want to have these objects populated from a decoupled, centralized configuration store such as a database.
I have around 6 WCF services that I want to host in an MVC application, routing requests to /services/foo to WcfFooService and /services/bar to WcfBarService
I can accomplish IoC with StructureMap within the services and inject my constructor dependencies by using the example that Jimmy Bogard blogged about here:
Jimmy's article is great, but I'm trying to extend it to work with multiple services hosted within the same MVC application. Essentially, the part at the bottom is the part that is causing me a few headaches:
public class StructureMapServiceHostFactory : ServiceHostFactory
{
public StructureMapServiceHostFactory()
{
ObjectFactory.Initialize(x => x.AddRegistry<FooRegistry>());
//var iTriedThisToo = ObjectFactory.Container;
//container.Configure(x => x.[etc]);
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new StructureMapServiceHost(serviceType, baseAddresses);
}
}
With a single WCF service - routing MVC requests to a specific url via the StructureMapServiceHostFactory shown above works brilliantly - but - If (for example) I create a StructureMapServiceHostFactory2 for the /services/bar call, to allow for a different Registry to be used, when the MVC app spins up, it appears to call each factory in turn as it runs through RouteConfig.cs and adds the routes, so ultimately I don't get configured instances that the first ServiceHostFactory should provide.
It doesn't make a difference if I call Initialize(); or attempt to grab the Container property and call Configure on it, either.
Am I on a hiding to nothing with this? The major reason for requiring registry isolation is due to different NHibernate configuration, but I could configure Named instances of SessionFactory and Session for NHibernate purposes and then use a single registry to get around this. In my mind I wanted the WCF service and MVC-hosting to be capable of using their own IoC containers in isolation, which is why I went down this route.
Is there any way that I can accomplish this?
Ok, so it would appear the only person capable of answering this was me, by virtue of a re-think and 're-architecting' the solution so that the problem doesn't exist in the first place.
I now have a capable way of hosting these services and maintaining IoC with StructureMap neatly per service, without any conflicting concerns.
If you find yourself in a similar position with SOA taking over (SOATO?) - taking a step back is a good start ;)
I have a DDD class library. In it, I have the following structure:
> Core
> - DataAccess ( my LINQ repositories)
> - Domain ( my data objects)
> - Impl (my services)
I have recently added a WCF project to my solution. This project will
be exposing JSON web methods to an iPhone client. The WCF methods are
not too sophisticated - GetCustomers / GetCustomerDetails / GetAlerts
GetAlertDetails / GetProblems / GetProblemDetails / GetInventory /
GetInventoryDetails, GetDataPoints / GetDataPointDetails / etc...
What I am noticing is that most of the methods in WCF are exposed
by my services layer in my DDD model. So, I am finding myself doing
a lot of code like this:
public List<Alert> GetAlerts()
{
AlertSerice _as = new AlertService;
List<Alert> alerts = _as.GetAlerts();
return alerts;
}
This doesn't feel right to me. I am wondering if I should be doing away with my Impl folder (with all
the DDD services) and recompile. Then, add the DLL as a refcerence in my WCF project and code my
previous DDD services as WCF methods?
Does WCF really just need the Domain and DataAccess layers?
Thanks in advance.
AlertSerice _as = new AlertService;
List<Alert> alerts = _as.GetAlerts();
It seems possible you may be using Domain Services incorrectly.
In DDD, Domain Services are used when multiple aggregate roots must be involved in an operation.
GetAlerts would appear to be functionality that clearly belongs in an AlertRepository (and not just belongs, but is the core functionality of that Repository).
As for WCF Services, they are a public endpoint. Their job is to receive requests from a client and carry out commands on the domain or queries. The focus in this sort of service is usually translation - from primitive typed input parameters to DTO's for output.
From an architectural perspective using a distinct service layer to expose your data allows a level of abstraction, and isolation for protected and internal methods, you can simply plug in a different service handler (Service configuration) to expose the data in a binary or XML format. Where you need to spend your time is ensuring the levels of abstraction are clearly defined and ensure code access rules and security between layers exposed to the service layer are implemented.