I'm currently using WebApiRequestLifestyle has the default scoped lifestyle. I want to inject a service in the OWIN Middleware and in one of the API controllers, and the service's scope should be still WebAPI i.e., for the entire request, there should be only one instance of the service.
public class TestMiddleware : OwinMiddleware
{
private readonly ITestService _testService;
public TestMiddleware(OwinMiddleware next, ITestService testService) : base(next)
{
_testService = testService;
}
public override async Task Invoke(IOwinContext context)
{
var test = _testService.DoSomething();
await Next.Invoke(context);
}
}
public class ValuesController : ApiController
{
private readonly ITestService _testService;
public ValuesController(ITestService testService)
{
_testService = testService;
}
}
ITestService instance should be same for the entire request. How should I register the middleware?
This is how I'm doing it now:
using (container.BeginExecutionContextScope())
{
var testService = container.GetInstance<ITestService>();
app.Use<TestMiddleware>(testService);
}
The problem with this approach is - one instance of ITestService is getting created for the middleware during registration and stays forever (like a singleton), and for every webapi request, a new instance gets created and shared across the controllers (webapi scope)
Please don't point me to these questions - WebApi + Simple Injector + OWIN
Injecting a dependency into OWIN Middleware and per web-request with Simple Injector
OWIN's Use<T> method registers the supplied T as singleton in the OWIN pipeline, no matter what lifetime you configured that type with in your container. So while you resolve the middleware in an active scope, you (implicitly) tell OWIN to cache this instance for ever.
You have two choices here:
Make sure that the middleware component can be used as singleton in the OWIN pipeline, or
Resolve the middleware component on each request.
Making sure the middleware component can be used as singleton is easy. Just register it as singleton in Simple Injector, and when you call Verify(), Simple Injector will detect whether or not this component can be used as singleton, or whether it has dependencies with a shorter lifestyle. This does mean however that all dependencies should be singletons and runtime data (like DbContext's and other data objects) should be passed through method calls after the object graph is built. I consider this good practice, but this might be quite a change in your application and probably quite a mind shift. Because of this I consider this to be out of scope for this question, so you should go for option 2.
In case your middleware component has dependencies with a shorter lifestyle, you are should resolve that middleware per request request. This means you should not use OWIN's Use<T>(middleware) method, because that would make it a singleton.
This is how to do it:
app.Use(async (context, next) =>
{
var middleware = container.GetInstance<TestMiddleware>();
await middleware.Invoke(context, next);
});
Note that the TestMiddleware is resolved on each request. This gives Simple Injector full control over the built object graph. This means however that you need to make a small adjustment to your TestMiddleware class. This is how it should look:
public sealed class TestMiddleware
{
private readonly ITestService _testService;
public TestMiddleware(ITestService testService)
{
_testService = testService;
}
public async Task Invoke(IOwinContext context, Func<Task> next)
{
var test = _testService.DoSomething();
await next();
}
}
Note that the OwinMiddleware parameter removed from the constructor, and replaced by a Func<Task> parameter in the Invoke method. This allows Simple Injector to construct the type, because its constructor won't contain any runtime parameters anymore. Remember: compile time dependencies through the constructor, runtime data through method calls.
Also note that the middleware doesn't inherit from OwinMiddleware anymore. Since the middleware didn't inject a wrapped middleware, inheriting from it became useless.
After reading Steven's answer, this is what I did:
Registered the middleware like this:
using (AsyncScopedLifestyle.BeginScope(ServiceLocator.Container))
{
app.Use<TestMiddleware>();
}
Inside the middleware, I used ServiceLocator to resolve the dependency as Steven suggested (I know ServiceLocator is an anti-pattern, but we are already using it in a few unavoidable places in the app)
public override async Task Invoke(IOwinContext context)
{
var testService = ServiceLocator.Current.GetInstance<ITestService>();
testService.DoSomething();
await Next.Invoke(context);
}
Note: I assume Simple Injector (or any DI library) uses CallContext to maintain the scoped instances; if so, just wanted to share that the CallContext doesn't flow properly after some middlewares. Here is my another question that I posted a while ago reporting the same - OWIN Middleware & CallContext
Related
I recently came across AddPooledDbContextFactory concept as part of my NET 5 self-education piece and am keen to implement it properly. However, I am not sure how to use it with generics that I generally use.
Example of my current setup:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TestDbContext>(
(s, o) => o.UseNpgsql(Configuration.GetConnectionString("DatabaseConnection"))
.UseLoggerFactory(s.GetRequiredService<ILoggerFactory>()));
// other code //
}
my repository generic:
public class Repository<T> : IRepository<T> where T
{
private readonly TestDbContext _dbContext;
public Repository(TestDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task Create(T entity)
{
await _dbContext.Set<T>().AddAsync(entity);
await _dbContext.SaveChangesAsync();
}
// other methods //
}
this is invoked in following manner as example:
public class WeatherForecastController : ControllerBase
{
private readonly IRepository<Test> testRepo;
public WeatherForecastController(IRepository<Test> testRepo)
{
this.testRepo= testRepo;
}
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> GetAsync()
{
await testRepo.Create(new Test { Name = "Superman" });
// other code
}
}
I would like to convert this to use the new AddPooledDbContextFactory concept but cannot find enough documentation to figure out how to do this.
Atm only thing that comes to mind is using statements at each method but that doesn't make sense.
Any advice on this?
Documentation is not yet complete and is in progress, you track this issue
https://github.com/dotnet/EntityFramework.Docs/issues/2523
You can also a look at the tests for AddPooledDbContextFactory to see how to register DbContext with
https://github.com/dotnet/efcore/search?q=AddPooledDbContextFactory
for example to register DbContext:
services.AddPooledDbContextFactory<TContext>(ob =>
ob.UseSqlServer("ConnectionString").EnableServiceProviderCaching(false), poolSize: 32)
Then in your class, inject an IDbContextFactory<TContext> and use it like this:
using(var context = _factory.CreateDbContext())
{
var orders = await context.Orders.Where(o => o.Id > 3).ToListAsync();
}
According to this post:
Note that the DbContext instances created in this way are not managed
by the application's service provider and therefore must be disposed
by the application
You can also check out this post to see how to use IDbContextFactory:
https://learn.microsoft.com/en-us/aspnet/core/blazor/blazor-server-ef-core?view=aspnetcore-5.0
#Aeseir your code looks good to me. You are following best practices and you don't need to change it.
You are using the Repository Pattern, so your Repository class has all of your query logic which helps create loosely coupled and maintainable code.
In your ConfigureServices, calling: services.AddDbContext<TestDbContext>() registers TestDbContext with Scoped service lifetime. This is the way that DbContext is designed to work, and it will also work well with ASP.NET controllers, since they have a Scoped lifetime as well.
You did not show your code for registering IRepository, but that service lifetime should be Scoped as well. Btw, you can tell BuildServiceProvider() to validate scope registrations:
builder.Services.BuildServiceProvider(validateScopes: true);
Since DbContext is designed to have a Scoped service lifetime, and since your IRepository and Controller services are Scoped as well, every request gets brand new:
Controller
IRepository
DbContext
Those services are used for the request and then Diposed. This is how ASP.NET is intended to work.
Apparently at some point, DbContext pooling has been introduced to improve performance. In this case, EF Core manages a pool of context instances for you and resets them after each request. This can improve performance, although in some situations, the benefit might be small. See MSDN documentation for more details.
I think for use with ASP.NET controllers (i.e. the code you posted above) all you need to do to take advantage of EF Core context pooling is call AddDbContextPool():
builder.Services.AddDbContextPool<ApplicationDbContext>(/* ... */);
However, if you needed to use DbContext in services registered with Singleton lifetime, then the pattern above would not work well. Because when a Scoped service gets used in a Singleton service, the Scoped service is essentially a Singleton. Each request would not get a new DbContext, nor a reset one from the pool. (See QUESTION below.)
In that case, you might want to use the DbContext factory pattern instead:
builder.Services.AddDbContextFactory<ApplicationDbContext>(/* ... */);
Or, if you want to use context pooling with a factory pattern:
builder.Services.AddPooledDbContextFactory<ApplicationDbContext>(/* ... */);
The DbContextFactory can then be used in other services through constructor injection. For example:
private readonly IDbContextFactory<ApplicationDbContext> _contextFactory;
public MyController(IDbContextFactory<ApplicationDbContext> contextFactory)
{
_contextFactory = contextFactory;
}
The injected factory can then be used to construct DbContext instances in the controller code. For example:
public void DoSomething()
{
using (var context = _contextFactory.CreateDbContext())
{
// ...
}
}
Keep in mind that when you call CreateDbContext(), context instances are not managed by the service provider and therefore must be disposed by the application. Hence you need to Dispose of them yourself, such as in the example above which does so with the using statement.
QUESTION
I am doing my best to understand this stuff and explain it, but I might be wrong, so please call out an inaccuracies in my post.
When using AddDbContextPool(), does the DbContext get registered as a Singleton or Scoped?
I found in MSDN documentation that it's effectively registered as a Singleton:
Context pooling works by reusing the same context instance across requests; this means that it's effectively registered as a Singleton, and the same instance is reused across multiple requests (or DI scopes). This means that special care must be taken when the context involves any state that may change between requests.
However, I have found that if AddDbContextPool() is used along with true for validatedScopes:
builder.Services.BuildServiceProvider(validateScopes: true)
When DbContext is consumed from another service which is registered as a Singleton, the following exception is thrown:
System.InvalidOperationException: 'Cannot consume scoped service 'ApplicationDbContext' from singleton 'IRepository'.'
Hence why I stated above that DbContext still gets Scoped service lifetime.
I have a scoped service:
public class GetLatestStatus:IGetLatestStatus{
private HttpClient _httpClient;
private readonly int _status;
public GetLatestStatus(HttpClient httpClient){
_httpClient = httpClient;
_date= GetStatusFromService();
}
public string GetStatus(){
return _status;
}
private string GetStatusFromService(){
Logger.Info($"Calling service...");
var request = new HttpGetRequest{Url = "http://some.service/get/status"};
var result = _httpClient.Get(request).Result;
return result.Status;
}
}
Here is how it is defined in the startup:
public virtual void ConfigureServices(IServiceCollection services){
services.AddScoped<IGetLatestStatus, GetLatestStatus>()
.AddHttpClient<IGetLatestStatus, GetLatestStatus>();
services.AddTransient<ISomeClass1, SomeClass1>();
services.AddTransient<ISomeClass2, SomeClass2>();
services.AddTransient<ISomeClass3, SomeClass3>();
}
It is being used by three transient classes.
The intent of this class is that _status is defined only once, when the request comes in. Then it is stored throughout the lifecycle of the request.
Instead, it seems that GetStatusFromService() is being called three times, one per transient class, when the request first comes in.
How do I make this class work the way I intended? I thought that defining something as a Scoped Service means that there's only one copy for the lifecycle of the request. Thank you all for the help!
TL:DR
It happens because you register GetLatestStatus like this after scoped registration .AddHttpClient<IGetLatestStatus, GetLatestStatus>();
So may create another class to store the status and register it as scoped. Then use the Http Configured service to reach the service from it
According to MSDN;
To configure the above structure, add HttpClientFactory in your application by installing the Microsoft.Extensions.Http NuGet package that includes the AddHttpClient() extension method for IServiceCollection. This extension method registers the DefaultHttpClientFactory to be used as a singleton for the interface IHttpClientFactory. It defines a transient configuration for the HttpMessageHandlerBuilder. This message handler (HttpMessageHandler object), taken from a pool, is used by the HttpClient returned from the factory.
Please check the link for more information https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
I am using AutoFac in my Web API application (using the latest versions available as of time this question was posted). One of my service dependencies is an AuditService which uses an instance of by DbContext type (let's call it MyDbContext for now). Most of my services and the MyDbContext type are all registered using InstancePerRequest. For my AuditService I want to make an exception, I always want to inject an owned (new) instance of my MyDbContext.
Question: Using AutoFac registrations, how do I register my AuditService in such a way that it always gets an owned (new) instance of MyDbContext?
What could work:
I could hard code the creation of MyDbContext in the constructor of AuditService thus circumventing AutoFac all together.
I could use PropertyInjection or MethodInjection and provide a new instance of MyDbContext in the Life Time event OnActivating
I could define a second interface on MyDbContext and provide a second registration and use InstancePerOwned.
Do I have to pick one of these above options (if so I would lean towards 3) or am I missing something simple? Is there a way to define what I want in my registration code?
// registration called in web api startup code
public void RegisterAutofac(ContainerBuilder builder)
{
builder.RegisterType<MyDbContext>()
.As<IMyDbContext>()
.InstancePerRequest();
builder.RegisterType<BusinessService>()
.As<IBusinessService>()
.InstancePerRequest();
builder.RegisterType<AuditService>()
.As<IAuditService>()
.InstancePerRequest();
}
public class AuditService
{
// expects an isolated instance on this request
private readonly IMyDbContext _dbContext;
public AuditService(IMyDbContext dbContext)
{
_dbContext = dbContext;
}
}
public class BusinessService
{
// expect a shared IMyDbContext instance across the request
private readonly IMyDbContext _dbContext;
public BusinessService(IMyDbContext dbContext)
{
_dbContext = dbContext;
}
}
Solution Attempts with InstancePerOwned
This causes an exception
builder.RegisterType<MyDbContext>()
.As<IMyDbContext>()
.InstancePerRequest()
.InstancePerOwned<AuditService>();
Autofac.Core.DependencyResolutionException: "No scope with a tag matching 'AuditService' is visible from the scope in which the instance was requested. If you see this during execution of a web application, it generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario). Under the web integration always request dependencies from the dependency resolver or the request lifetime scope, never from the container itself.
at Autofac.Core.Lifetime.MatchingScopeLifetime.FindScope(ISharingLifetimeScope mostNestedVisibleScope)
at Autofac.Core.Resolving.InstanceLookup..ctor(IComponentRegistration registration, IResolveOperation context, ISharingLifetimeScope mostNestedVisibleScope, IEnumerable`1 parameter
I tried reversing the order of InstancePerOwned and InstancePerRequest calls but this seems to have no effect, the same MyDbContext instance is reused for both BusinessService and AuditService instances in the same request. This was tested with object.ReferenceEquals from in an ApiController and passed in both instance's _dbContext fields.
builder.RegisterType<MyDbContext>()
.As<IMyDbContext>()
.InstancePerOwned<AuditService>()
.InstancePerRequest();
Try switching from InstancePerRequest to InstancePerLifetimeScope. In most apps this generally behaves the same and is the way to share registrations across apps that both do and don't have per-request semantics anyway. (Which is to say, this is pretty common.)
Once you have InstancePerLifetimeScope on your context object, you can use Owned<T> in your AuditService constructor to get a fresh copy.
So...
builder.RegisterType<MyDbContext>()
.As<IMyDbContext>()
.InstancePerLifetimeScope();
then...
public AuditService(Owned<IMyDbContext> dbContext)
Note your AuditService will be responsible for disposing of the dbContext when it's done, so you'll have to handle that manually (that's part of using Owned<T>). But if you've already got some one-off stuff going on, that shouldn't be a big deal.
Controller
public class LocationsController : ApiController
{
private readonly IMediator _mediator;
public LocationsController(IMediator mediator)
{
_mediator = mediator;
}
public IEnumerable<Place> Get()
{
return _mediator.Send(new GetLatestMapData<Place>());
}
}
On first request of Get() action, the Handler is instantiated by SimpleInjector and executed correctly.
On the second request (F5 in browser for e.g.), it fails with :
Handler was not found for request of type ....
Container or service locator not configured properly or handlers not registered with your container.
and inner exception of:
Cannot access a disposed object.
Object name: 'The ThreadLocal object has been disposed.'
OWIN Startup
public class Startup
{
public void Configuration(IAppBuilder app)
{
// SimpleInjector
var container = CompositionRoot.CreateContainer();
var config = GlobalConfiguration.Configuration;
config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
// Routing
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
config.EnsureInitialized();
app.UseWebApi(config);
}
}
SimpleInjector IPackage for WebAPI project
public class Installer : IPackage
{
public void RegisterServices(Container c)
{
c.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
c.RegisterWebApiControllers(GlobalConfiguration.Configuration);
}
}
I think what's happening is the Handler is correctly created, and then disposed after the first request.
Now, I don't know why, but on subsequent requests, the Handler isn't re-created. I know this because if I change the WebApiRequestLifestyle to 'not dispose when scope ends', it works for every request:
c.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle(false
/*disposeInstanceWhenScopeEnds*/);
Questions
Should I keep the disposeInstanceWhenScopeEnds parameter set to false?
If not, what is the correct solution?
I see this has been solved before by creating a LifetimeScopeDecorator... however, surely this functionality is already provided by the SimpleInjector WebApi integration library? What am I missing?
(And thank you for reading)
This link provides good guidance on dependency resolution and using the IDependencyResolver / IDependencyScope Interfaces.
Immediately you will see that they touch on life spans which tend to get a little tricky.
This section in particular is interesting:
Dependenecy Scope and Controller Lifetime
Controllers are created per request. To manage object lifetimes,
IDependencyResolver uses the concept of a scope.
The dependency resolver attached to the HttpConfiguration object has
global scope. When Web API creates a controller, it calls BeginScope.
This method returns an IDependencyScope that represents a child scope.
Web API then calls GetService on the child scope to create the
controller. When request is complete, Web API calls Dispose on the
child scope. Use the Dispose method to dispose of the controller’s
dependencies.
Conventionally bootstrapping a service would occur once during the app start-up and as you know resolve any dependencies at that time. Only when the worker process was shutting down (no activity, for example) would this then invoke dispose.
Ordinarily I think it is quite normal for resolved instances to remain for the life cycle unless it is imperative that they are destroyed after use. But the example given explains that we must correctly dispose once the request is complete. So I would recommend that you dispose of your instances correctly using the examples provided as guidance.
This helped me when working with IoC and WebApi. I hope this helps!
You need to arrange your Lifetime scoped
Code:
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
container.Options.LifestyleSelectionBehavior = new WebApiInjectionLifestyle();
internal class WebApiInjectionLifestyle : ILifestyleSelectionBehavior
{
public Lifestyle SelectLifestyle(Type serviceType, Type implementationType)
{
return Lifestyle.Scoped;
}
}
More Detail
https://simpleinjector.readthedocs.io/en/latest/lifetimes.html
I am trying to work out how to best inject all of my dependencies into the custom OWIN Middleware I have written for a Web API Application. A simple example would be the DbContext I am using. I have some middleware that needs to potentially query based on the request. The issue I have is that I want my DbContext to otherwise have a WebApiRequestLifestyle scope. My DbContext is registered as such:
container.Register<MobileDbContext>(Lifestyle.Scoped);
Obviously, this does not work:
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
Because I need the MobileDbContext in my Middleware using something like:
app.CreatePerOwinContext(() =>
{
return container.GetInstance<MobileDbContext>();
};
I tried a hybrid lifestyle, but that also didn't work because I don't think the Middleware is technically something that can fall under a "scoped" lifestyle. It is probably closer to a singleton, I would think.
Is there a better way to design my app to avoid this problem or address it with some sort of custom scoped lifestyle?
The documentation shows an example of how to wrap an OWIN request in a scope:
public void Configuration(IAppBuilder app) {
app.Use(async (context, next) => {
using (AsyncScopedLifedtyle.BeginScope (container)) {
await next();
}
});
}
What this does is wrapping an OWIN request in an execution context scope. All you have to do now is make the execution contest scope the default scoped lifestyle as follows:
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();