asp.net 5 DI: Using scoped service outside request - dependency-injection

We have a IOrderManager service which uses some other services registered in DI via AddScoped().
Now we need to use that service in the OnMessage handler for some queue which, obviously, is raised outside any request pipeline.
So when we try to get our service using something like
var orderManager = ServiceProvider.GetRequiredService<IOrderManager>();
we got "Can't access disposed object ..." exception.
Question: is it possible to "tell" DI that we are inside some "fake request" processing to avoid disposing services registered as "scoped"?

If your IOrderManager is outside request scope, you can create your custom scope per-message like this:
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var myService = serviceScope.ServiceProvider.GetRequiredService<MyService>();
}

If you're using scoped services within IOrderManager, IOrderManager needs to also be scoped.
If you don't do this, when the IOrderManager instance is first created, it will "capture" the scoped dependencies from the current request.
Any future usage of IOrderManager will continue to use the old scoped dependencies and not dependencies from the current request scope.
Next, the only reason you should use scoped dependencies is if they somehow maintain state across a single request and need to isolate that state from other requests.
If your IOrderManager doesn't actually need information that is scoped to a request, it shouldn't be scoped and shouldn't use dependencies that are also scoped.
Put another way, if you think it should be usable outside of an active request, it by definition is not scoped does not require scoped dependencies.

Related

Iterate through all sinks and enrichers registered in Serilog

How can I iterate through all sinks (ILogEventSink objects) or enrichers (ILogEventEnricher objects), respective, registered in Serilog?
I'm using Serilog.AspNetCore.
Thanks.
So, my naive idea is:
In Emit operation I must call a third party service that require current HttpContext to be set.
It seems Emit operation runs on background thread that has not got HttpContext assigned. So in Emit operation, I want to resolve IHttpContextAccesor service and set its HttpContext property. Then I can call a third party service requiring HttpContext to be set and all will be fine.
The current httpContext instance I will get is in my custom middleware and just here is the place where I want to inject httpContext instance into the Sink instance (to its [ThreadStatic] field) to accomplish scenario described above.
Another way is recreating all Serilog (and its Sink) in a middleware on each http request and pass httpContext to its constructor as a parameter. Expensive.
Serilog doesn't support this scenario.

How would AddScoped() behave outside Asp.net core?

Let's say I want to use dependency injection in a console application that would run as an Azure web job. Doing so I am reusing my custom service registration method called "AddATonOfServices()" which I use on a related Asp.net application.
My question is, how would the services that are registered in "AddATonOfServices()" using AddScoped() behave now in the console App? are they behaving like Transient or Singleton, or HOW? Would there be any unexpected behavior?
Thanks.
It will be resolved as scoped, if you create a scope via IServiceScopeFactory.
// provider is the root container
using(var scope = provider.GetService<IServiceScopeFactory>().CreateScope())
{
var scopedService = scope.ServiceProvider.GetRequiredService<IScopedService>();
// do something
}
// scope will be disposed and all scoped and transient services which implement IDisposable
If you resolve a scoped service from the root container, then it will be effectively a singleton (assuming provider lives as long as the application does)

Getting a scoped component from a IDocumentStoreListener

I have an ASP.NET 5 app using RavenDB, and I'm trying to create an attribute that will create a "Changeset" document with the keys of all the documents that were stored by the action.
For that purpose, I created an ActionFilterAttribute instantiated via ServiceFilterAttribute, which is registered as Scoped, that sets a flag on another Scoped component, let's call it ChangesetAccessor, which holds the list of changes.
The IDocumentStore is obviously a Singleton, and the listener (IDocumentStoreListener implementation) is manually instantiated. It needs access to the current ChangesetAccessor, so I thought giving it a reference to the IServiceProvider so it can call GetService<ChangesetAccessor> as needed would be enough, but it is receiving a different instance.
How can I get the ChangesetAccessor for the "current request" from my listener?
You can actually access RequestServices off of the HttpContext to get scoped instances. It's kind of backwards, and really will depend on Microsoft.AspNet to do it, but it will work for your situation; interestingly, IHttpContextAccessor is a singleton, too, though it gives you a scoped value.
// injected:
IHttpContextAccessor httpContextAccessor;
// in your method:
httpContextAccessor.HttpContext.RequestServices.GetService<ChangesetAccessor>()

Dependency management in Zend Framework 2 MVC applications

As the ServiceLocatorAwareInterface will likely be removed from the AbstractController in ZF3, dependencies should instead be passed via the constructor or via setter methods.
With this in mind, consider the use case of a user or site controller with actions such as register, activate account, login, logout, etc. At a minimum, this would require a UserService and 2 forms. Add a few more related actions (remote authentication, linking of accounts, etc.) and you end up with 4 or 5 forms.
Passing all these dependencies via the constructor would be messy at best, and more importantly, only 1 form is usually required per action.
Which one of the following techniques do you think is better, and why?
Create separate controllers for each action, so that each controller will only require a single form (in addition to a service). For example RegistrationController, LoginController, LinkAccountController, etc.
You end up with lots of controllers this way.
In the factory for the controller, supply different forms based on which action is being requested.
Construction of the controller becomes dependent on this factory, and more specifically the request environment (routing, etc.) You could construct the controller directly (for testing or whatever), but then you would need to ensure that the dependencies were available and throw exceptions if not.
Use the event manager, trigger an event in the controller when a form is required, and let an event handler supply the dependency on demand.
This technique is described here.
Your controller would then be dependent on an EventManager as opposed to a ServiceLocator, which is probably not much better.
Pass the FormElementManager to the controller, and request forms from it.
No better than the SL itself most likely.
Directly construct forms inside controllers.
How does this affect testibility?
The same question would then apply to handling a controller with multiple services (instead of forms).
Other?
See also:
Passing forms vs raw input to service layer
Factory classes vs closures in Zend Framework 2
First, ServiceLocator won't be removed. Maybe just the ServiceLocatorAwareInterface.
As you said, passing the FormElementManager is a solution and it's indeed better than passing the service locator. I'm personally using more and more plugin managers and they are a nice way to solving that kind of problem. A plugin manager is different that a service locator because it allows to retrieve only ONE type of objects (forms, hydrators, input filters...). Of course, as the parent service locator is injected into plugin managers, some people will do the trick of retrieving the service locator from plugin manager (taht's why I'd like to remove in ZF3 the service locator in plugin managers, and instead having a specific factory where the parent locator is passed for injections, although it would complicate a bit the factory interface :/...).
This, with splitting controllers into smaller controllers, should make your code cleaner.
By the way, you are talking about authentication, but imo if you correctly inject an authentication service (or inject the authentication service into a user service or something like that), it reduces significantly the dependencies into the controller.
You need to think about the problem you're trying to solve as a domain. In the User domain, there are many forms. So, aggregate them into a repository. The form repository would be passed into the user service, along with other repos like an entity repository. Then the User service would be passed into the controller.
// UserService
public function getForm($name, $id = null)
{
$form = $this->formRepository->find($name);
if ($id !== null) {
$entity = $this->entityRepository->find($id);
$form->bind($entity);
}
return $form;
}

Inject with different scope when using DbContext with custom resource provider

In an application I have the following components (among others):
MyDbContext : Entity framework data access
DBResourceProviderFactory : A custom ResourceProviderFactory providing a custom IResourceProvider (called DBResourceProvider...)
Other services
StructureMap
The custom resource provider is looking resources up in the db using MyDbContext, injected similarly as described in this SO answer.
The MyDbContext is also used in various other services, and since it is a web application, I use StructureMaps HttpContextScoped method to limit the lifetime of MyDbContext to the lifetime of the request (see an other SO question and its answer on this subject):
x.For<MyDbContext>().HttpContextScoped();
However, it seems that the lifetime of an IResourceProvider is not limited to a single http request. Therefore, DBResourceProvider keeps hanging onto a MyDbContext reference which will be disposed after the first request.
How can I handle this lifetime mismatch - have StructureMap return a transient MyDbContext for IDbResourceProvider while returning HttpContext-scoped instances to all other services?
Do I need two different implementations to do that? A marker interface?
Or is it a bad idea to use Entity Framework to look up localized resources in the first place (performance etc.)?
If you have a service that has (or needs to have) a long lifetime than (one of) its dependencies, the general solution is to use a factory to get those dependencies.
In your situation the solution might be simple. When your DBResourceProvider is defined in your composition root of your MVC application, it would simply succeed to use the DependencyResolver.Current.GetService method to get the MyDbContext.
When the DBResourceProvider service isn't part of the composition root (for instance because it contains business logic that you need to test), you could either extract that logic into its own class, to allow the service to be in the composition root, or you can inject a (singleton) factory (for instance IDbContextFactory or Func<MyDbContext>) that allows you to get the proper instance to be resolved.

Resources