How would you configure the middleware to change the DBContext connection string based on a sub-domain of the income request?
It appears that the DBContext is set in the Startup... which looks too early to determine the HTTPRequest to resolve the connection string.
Well, this might not suit your needs entirely, but here's what I would do:
Create a DbContextFactory class. This DbContextFactory class can create instances of the DbContext and can pass in any string to the DbContext constructor. Then inject this factory and whenever you need an instance of the dbcontext, just ask the factory to return one for you. Of course you have to manage the lifetime of the created contexts yourself (i.e. using block).
Another option can be to create the DbContextFactory so that it holds an instance of a DbContext. When you ask for a context object from the factory, the factory creates a new one and also stores it in a private field, and subsequent calls return that same instance. Make the factory IDisposable and in its Dispose() method, dispose the context as well. This way you don't have to worry about managing lifetime (if you use a Scoped registration).
Related
I am developing an application with multiple tenants. Each tenant can be associated with a user to identify the database that it will have access to, through the connection string that is stored in the database.
The problem I am having is that I only identify this connection string at the moment the user logs in, however I need to register this connection string when the StartUp class is executed.
I tried to do this using session variables, I got the ConfigureServices method of the StartUp class to run again with the correct value, but I can not get this new configuration to take effect.
services.AddScoped<IDapperContext>(s => new DapperContext(connectionString));
I guess I need to rebuild for the new setting to take effect.
How can I do this?
Am I on the right path?
Is there any other way to solve this problem?
I recently read this article, which talks about injecting the HTTPContext into your service.
https://www.strathweb.com/2016/12/accessing-httpcontext-outside-of-framework-components-in-asp-net-core/
Once you have the context, you can get the authenticated user, and retrieve your connection string from a second DB or source that maps users to databases. You would have to configure your context options during construction of the context, in order to control the connection string for the context as a scoped service.
You might want to consider using a context factory instead that does this for you.
The code in startup.cs would add a context for the database with your connection strings, and then your factory would accept that as an injected dependency. Your factory would also take in IHttpContextAccessor as a dependency giving you access to the user in the context. Together you could then obtain the connection string, and wire up the DbContextOptions to pass to a new instance of your context.
This seems like the easiest approach for DI to me.
I am new to spring and not able to understand when to instantiate the class with new operator and when by using spring container.
example i found a code
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
EmployeeDao dao=(EmployeeDao)ctx.getBean("edao");
int status=dao.saveEmployee(new Employee(102,"Amit",35000));
System.out.println(status);
int status=dao.updateEmployee(new Employee(102,"Sonoo",15000));
System.out.println(status);
Employee e=new Employee();
e.setId(102);
int status=dao.deleteEmployee(e);
System.out.println(status);
}
}
i am using jdbc template. i have a doubt why we have new to instatiate employee class instead we should have used (Employee)ctx.getBean("employee"). using new operator would create dependency?
Pls help
From ProSpring book,
"Of the applications that we have built using Spring,
the only objects that are consistently not managed by Spring are domain objects. (Even though in Spring
it’s possible to have Spring manage domain objects by applying the #Component annotation to the classes
and assigning them with prototype scope, most of the time we will choose to manage domain objects
within the application.) The reason for this is that, practically, Spring does not need to be involved with
domain objects. Generally, you create many instances of your domain objects using the new() operator
and perform processing either in the service or data access layer. Although Spring also supports the
injection of new instance of domain objects every time it was requested (by using the bean scope
prototype), generally developers will not adopt this approach since typically domain objects do not take
advantage of Dependency Injection, because they generally have few dependencies outside of the DOM
itself, and they don’t require much configuration."
So, yes you could create beans of type Employee but then they wil have to be defined as prototype as be default all beans in spring are singletons. because there can be many employees and their objects, you obviously cannot have Employee as a singleton. but your concentration as to the utilization of spring features should be much more than managing domain objects.
The Spring IOC container is at the core of the Spring Framework. The container will create the objects, wire them together, configure them, and manage their complete lifecycle from creation till destruction.The IoC container gets informations/metadata either from XML or by Java annotations, or by Java code.
Yeah you can create Employee bean in your spring context xml file and make sure scope is prototype as
<bean id="employee" class="com.mycompany.Employee" scope="prototype"/>
so that on every request of Employee bean, you will get a new object Employee.
There are other scopes of beans
singleton : This scopes the bean definition to a single instance per Spring IoC container (default).
request : On every HTTP request a new bean will created and delivered.
prototype : on every request(api request) a new bean will be created.
session : This scope a bean definition to an HTTP session.
Note : It is not recomemded to create beans for database model class.because your persistent layer will take care of it.
I want to know whether I can use object of service layer marked with #Service annotation and call one of its method in non mvc-spring class ?
Say there is a method getUsers() in service layer which calls getUsers() of Dao layer. In order to use it in contoller I have to add the #Autowired-annotation in the service layer instance. But if I want to use the class method getUsers() in non-mvc class, how can I do that?
In order to use a service, that object must be container managed. That is, this object's life cycle must be managed by Spring (creation, destruction, initialisation,...).
So to inject an instance of your service in an object, it must be a Spring bean too (Service, Component, Controller...).
So, it may be an MVC object, but it doesn't have to.
On the other hand, there is another alternative: use the annotation #Configurable.
An object with this annotation can be application managed but Spring, using byte code aspects, can inject it's dependencies. So although you create the object with a new statement, Spring instruments this call and resolve all the annotated dependencies.
Read this for more detail:
http://docs.spring.io/spring/docs/3.0.0.M3/spring-framework-reference/html/ch08s08.html
I've been thinking of how I could use one instance of a DbContext per HttpRequest in a layered application. One of the solutions I came up with would be to create an HttpModule that would initialize an instance of the context in HttpContext.Current.Items in the BeginRequest event handler and then dispose it in the EndRequest event handler.
The approach above poses a problem though: I need to reference System.Web in my data layer and business layer in order to get a hold of the stored DbContext instance. This is probably okay but I prefer to avoid going that route. What if I wanted to reference and use my data layer and business layers from a non-web application?
Any ideas?
You can use dependency injection. Simply create interface IContextHolder with method to get a context and inject the instance into your lower layer from the web application. The implementation of this interface will be different for different types of applications - it will wrap the access to the real storage for your context instance.
One of the simplest solutions would be to wrap the access to the data context in a static property in a facade/gateway class.
This way, in a web application, the property could access the HttpContext.Current.Items and store the context there. On the other hand, if the http context is missing, you could implement any other lifetime management policy for a non-web application.
public static TheDbContext Current {
get {
if ( HttpContext.Current != null ) {
// lifetime management for a web app
// e.g. with the Items container
}
else {
// lifetime management for a non-web app
}
}
}
The facade itself doesn't have to be a part of the data layer, you don't then reference System.Web in a data layer.
I got a webapp that stores a config object in ApplicationState.
This object contains the connection string to the database among other things.
Sometimes i start a async thread to do a few longer running tasks, like sending emails and updating the database.
However since this thread don't have a HttpContext i can't get at the config object.
I know this design that everything depends on HttpContext is bad, but thats too late to change now.
Looking at reflector i see that the HttpContext class just uses a static internal class to get the ApplicationState. Is there any other way to get at it?
All those internal classes in .net are really annoying.
Just pass whatever you like to your thread when you start it. Use a ParameterizedThreadStart delegate to start it instead of just a ThreadStart delegate. You could either pass it HttpContext.Current, or else bundle together the information you want your thread to have, and pass it.
If you really need access to Application State (or similar) from async handlers you should modify your HttpApplication subclass (e.g. Global.asax) to store the Application State instance (this.Application) to a static property during Application_Start:
public static HttpApplicationStateWrapper State { get; private set; }
protected void Application_Start()
{
State = new HttpApplicationStateWrapper(this.Application);
}
It would be more appropriate to use a DI framework to register this instance, but if you have one available you could probably avoid the use of Application State altogether for storing config. Further, there is a configuration framework in .NET that directly addresses this need and provides the ability to read configuration from anywhere.