I want to add per session lifestyle for one of my controllers in an ASP.NET MVC app but it currently has no such option. I've searched the stackoverflow and found the next solution
public class PerSessionLifestyleManager : AbstractLifestyleManager
{
private readonly string PerSessionObjectID = "PerSessionLifestyleManager_" + Guid.NewGuid().ToString();
public override object Resolve(CreationContext context)
{
if (HttpContext.Current.Session[PerSessionObjectID] == null)
{
// Create the actual object
HttpContext.Current.Session[PerSessionObjectID] = base.Resolve(context);
}
return HttpContext.Current.Session[PerSessionObjectID];
}
public override void Dispose()
{
}
}
But I want to be able to write somethink like
cr => cr.LifeStyle.PerSession.Named(cr.Implementation.Name)
I use Castle Windsor 3.0 and found that LifestyleType enum is contained inside Castle.Core namespace, it is being used by the DefaultKernel. My suggestion is to override the DefaultKernel but I do not really know how to do it bug free and seemlessly as if PerSession lifestyle if shipped with the dll.
So there are two things that you're asking about.
First is how to implement the lifestyle. Good starting point would be to look at how per-web-request lifestyle is implemented (use Scoped lifestyle with custom scope and scope accessor)
Second, how to surface that in the API. what I recommend is to have an extension method that encapsulates your lower level call to LifestyleScoped<YourCustomScopeAccessor>() with LifestylePerSession() similar to how WCF Facility does it.
Related
How to replicate this code with Autofac syntax?
public static class MenuConfig
{
public static void Initialize()
{
var _menuService = DependecyFactory.GetInstance<IMenuService>();
Parameters.Menu = _menuService.Menu();
}
}
Before calling this a "duplicate question" please note that I'm looking for an Autofac command. I CANNOT inject the interface anywhere and then call "Resolve". What I need to is perform an "InstancePerRequest" inline and uninjected so I don't have to do this:
var _service = new Service(new Dependency(new context()));
LightInject has a method that allows instantiation from an interface OUTSIDE of a constructor like this:
var _service = DependecyFactory.GetInstance<IService>();
What is the equivalent method for Autofac?
When calling containerBuilder.Build() you get back a container which implements IContainer and ILifetimeScope, whenever you get hold of one of these interfaces, you can resolve types from it:
container.Resolve<IService>();
If you want this container to be static, you could add the container as a static property to the Program or Startup class (depending if you're creating a Console or ASP.NET application).
Remember that the root container will be around for the entire duration of your application, so this can result in unwanted memory leaks when used incorrectly. Also see the warning in the documentation.
Still, it's perfectly possible to do the memory management yourself by resolving an Owned<> version from your interface:
using (var service = Program.Container.Resolve<Owned<IService>>())
{
service.Value.UseService();
}
Anyway, since you mention a static class in the comments, the best solution is to change that into a non-static class and register it as a singleton with Autofac. Then you can inject a Func<Owned<IService>> serviceFactory into that singleton and create/dispose an instance of the service wherever you need it.
using (var service = serviceFactory())
{
service.Value.UseService();
}
This is simply not possible with Autofac. All other solutions involving Autofac will require code refactoring which may potentially break software functionality. So unfortunately, the most elegant and least disruptive solution is this:
var _service = new Service(new Dependency(new context()));
Since this is an edge case addressing only one part of the software, this compromise is acceptable. It would be nice, however, if Autofac implemented this functionality in some future release.
Say I've a MVC Core Controller like this:
public class SomeController
{
public SomeController(IConfiguration appConfig, Func<string> someDelegate)
{
}
}
Also, I'm using AutoFac to resolve injections. Object injections are working flawlessly while adding a delegate injection produces an ASP.NET Core exception which tells that Func<string> can't be injected because there's no component to inject with such type.
When I try to manually resolve SomeController using AutoFac I get the desired behavior.
Is there any way to support this scenario without using AutoFac to resolve controllers?
Controllers are not resolved via DI by default, they are constructed in the DefaultControllerFactory or so.
Update
Microsoft.Extensions.DependencyInjection doesn't support named components, discovery, auto registrations, decorators etc.
It's meant to be simple out of the box IoC and provide the base for DI for basic applications and offer easy way for 3rd party IoC containers (with advanced features such as auto discovery, decorators etc.) to be integrated (basically all they need is process the information in IServiceCollection and return their own implementation of IServiceProvider from Configure method).
Tag helpers, controllers and view components are different in this aspect as they have their own activators (the default one use activation utilities, which at some point further down the pipeline use the service provider). For that reasons AddControllersAsServices exists, because it replaces DefaultControllerActivator (which uses ActivationUtilities, see DefaultControllerActivator.cs) with ServiceBasedActivator (which uses IServiceProvider, see ServiceBasedControllerActivator).
Also see this related answer for details on how to resolve controllers, tag helpers and view components via DI.
var builder = services
.AddMvc()
.AddControllersAsServices() // this one for your case
.AddViewComponentsAsServices()
.AddTagHelpersAsServices();
I was just run into this issue myself so I thought I would share for future reference as I had one case where I wanted to resolve a delegate but including an additional library seemed like overkill.
Given the following defintions:
public interface ISomething { /*...*/ };
public interface ISomeService { /*...*/ }
public class SomeService : ISomeService { /*...*/ }
public class Something
{
public Something(ISomeService service, string key) { /*...*/ }
}
// I prefer using a delegate for readability but you
// don't have to use one
public delegate ISomething CreateSomething(string key);
The delegate can be registered like this:
var builder = services
.AddSingleton<ISomeService, SomeService>()
.AddTrasient<CreateSomething>(provider => key => new Something(provider.GetRequiredService<ISomeService>(), key));
I am facing problem with disposing unnecessary objects from DI container. I use Prism for Xamarin.Forms with Unity container.
Application gets configuration from some database, creates some services using this configuration and registers this services in container using ContainerControlledLifetimeManager. This services are used while resolving views and viewmodels.
When configuration changes application retrieves again changed configuration and now problem comes: how can I remove previous registrations and register new services? If I simply re-register service then previous service is not GC-ed until disposing container.
I cannot dispose container, because it is created and managed by Prism (can I?).
I cannot use child container because Prism will not resolve views and viewmodels using child container (can I?)
Should I use different DI? Does Autofac or other DI support such approach?
EDIT:
I just have tested disposing of re-registered objects in Unity. It came out that re-registering using:
Container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager())
really releases previously registered objects. But I have also registrations using just type:
Container.RegisterType<Foo>(new ContainerControlledLifetimeManager())
or using instance:
Container.RegisterInstance(new Foo())
and these objects are not released when re-registering.
So now the only solution is to reconstruct the Unity container? Or give a try to other ioc container?
Without knowing all of the specifics of what you are looking to accomplish it's impossible to give you a solid roadmap, so I'll touch on some things to consider.
Reregistering Services
If you have some service IFoo, and two implementations FooA and FooB and you initially registered FooA as the implementation for IFoo (with a container controlled lifetime, registering FooB with the container should dispose of the FooA instance and FooB should be generated going forward.
Reconstructing the container
If you have to reconstruct the Container, it should possible. I haven't ever run into a use case where I have had to try something like what you are looking to do. For starters you probably want to take a look at the Initialize method from PrismApplicationBase. This is where the container gets constructed and setup. To handle the reconstruction, you will want to create an event that you subscribe to in your App class.
public partial class App
{
protected override void OnInitialized()
{
var ea = Container.Resolve<IEventAggregator>();
ea.GetEvent<SettingsChangedEvent>().Subscribe(OnSettingsChangedEvent);
// navigate
}
private void OnSettingsChangedEvent()
{
var ea = Container.Resolve<IEventAggregator>();
// prevent a memory leak
ea.GetEvent<SettingsChangedEvent>().Unsubscribe(OnSettingsChangedEvent);
// If you need platform specific types be sure to register either the
// IPlatformInitializer or some similar helper
var platformInitializer = Container.Resolve<IPlatformInitializer>();
ModuleCatalog = CreateModuleCatalog();
ConfigureModuleCatalog();
Container = CreateContainer();
ConfigureContainer();
// This would be your original RegisterTypes, so this assumes you
// look at your settings when initially registering types.
RegisterTypes();
// See notes above
platformInitializer.RegisterTypes(Container);
NavigationService = CreateNavigationService();
InitializeModules();
// Your container is now reset.
var ea = Container.Resolve<IEventAggregator>();
ea.GetEvent<SettingsChangedEvent>().Subscribe(OnSettingsChangedEvent>()
}
}
Containers
As for choosing a container. There is nothing wrong with Unity. Just know that when you're working with Unity, you're going to be stuck with the way it is since it apparently it is a dead project now. Ninject for Prism Forms uses a PCL variant that doesn't seem to be maintained anymore, but when the switch to NetStandard is made Prism will be able to target the current version of Ninject. As for Autofac, there you are dealing with an immutable container so the moment you resolve something you cannot update any new registrations. Autofac for Prism Forms is also a version behind for the same reason as Ninject. DryIoc for Prism forms is a great container and actually the one I am using on all of my current projects. It is also being actively maintained so you can expect use cases you run into to at least be heard.
Thanks for help to Dan S. and R. Richards.
Recreating Prism container caused problems in navigation. Maybe it is possible to fix it but I do not know how.
Using different IOC container would require too much time to learn it.
I ended up with custom lifetime manager (the solution provided in R. Richards link):
class CustomLifetimeManager : LifetimeManager
{
private object _Value;
public override object GetValue()
{
return _Value;
}
public override void RemoveValue()
{
_Value = null;
}
public override void SetValue(object newValue)
{
_Value = newValue;
}
}
Above lifetime manager allows to remove registrations:
public static class UnityContainerExtension
{
/// <summary>
/// Removes registrations that were registred using <see cref="CustomLifetimeManager"/>
/// </summary>
/// <param name="container"></param>
public static void RemoveCustomLifetimeRegistrations(this IUnityContainer container)
{
var registrations = container.Registrations.Where(r => r.LifetimeManagerType == typeof(CustomLifetimeManager));
foreach(var r in registrations)
{
r.LifetimeManager.RemoveValue();
}
}
}
I'm new to C#/ASP coming from a Java world. I've read this article: https://docs.asp.net/en/latest/fundamentals/dependency-injection.html#service-lifetimes-and-registration-options which wisely warns about the dangers associated with injecting a dependency with a smaller scope. Unfortunately it does not explain how to solve this issue in C#/ASP.
In Java there's a concept of Provider
interface Provider<T> { T get(); }
which, among other things helps to solve the scoping issue:
whenever a binding for some type T is register we can inject an automatically generated instance of Provider<T> instead of T and then get an instance of T whenever it is needed: an automatically generated Provider makes sure that we get an instance appropriate for the current scope (whatever this scope is: HTTP request, HTTP session or other custom scopes). The standard DI framework built into ASP.NET core does not have anything like this, but I thought in C# it should be very easy to implement as C# generics don't suck like java's do (https://docs.oracle.com/javase/tutorial/java/generics/erasure.html). So I've created the following class:
public class Provider<T>: IProvider<T> {
private readonly IServiceProvider serviceProvider;
public Provider(IServiceProvider serviceProvider) {
this.serviceProvider = serviceProvider;
}
public T IProvider<T>.Get() {
return serviceProvider.GetService<T>();
}
}
and I attemtped to use it the following way:
public class SingletonService : ISingletonService {
private readonly IProvider<IScopedService> scopedServiceProvider;
public SingletonService(IProvider<IScopedService> scopedServiceProvider) {
this.scopedServiceProvider = scopedServiceProvider;
}
public string PerformMyTask() {
var scopedDependency = scopedServiceProvider.Get();
// do something with scopedDependency to verify we get instances
// appropriate for the current scope
}
}
and in my Startup class:
public void ConfigureServices(IServiceCollection services) {
services.AddSingleton<ISingletonService, SingletonService>();
services.AddScoped<IScopedService, ScopedService>();
services.AddTransient<IProvider<IScopedService>, Provider<IScopedService>>();
// other bindings here
}
Unfortunately this does not work the way I intended as IServiceProvider instance seems to be also scoped to the current HTTP request and I get exactly the same instance of ScopedDependency from my provider during processing of different requests :(
Any hints how can I solve this problem?
Is there any "higher level" object than ServiceProvider maybe, bound roughly to application lifecycle (not to the current request) that creates instances of request scoped objects (or of ServiceProvider itself) that I can inject into my Provider objects instead of ServiceProvider? For example in Java if I use google Guice as a DI framework there is an Injector object, usually created at the startup of an application which holds all the type bindings and has a method
<T> T getInstance(Class<T> type);
which checks what is the current scope and returns a corresponding instance.
edit:
I think that one possible way to do it would be to get a new reference to instance of ServiceProvider each time in the Proivder<T>.Get() method instead of injecting in the constructor and storing as an instance var. This way my components would still not be polluted with a reference to the framework specific IServiceProvider as it would be hidden from them in the implementation of Provider<T> that they access via the abstract IProvider<T> interface. I can't however find on the web if it's possible to get such a reference from my Provider class and how to do this. Any pointers in this direction would be appreciated :)
Thanks!
ok, found it:
public class Provider<T> : IProvider<T> {
IHttpContextAccessor contextAccessor;
public Provider(IHttpContextAccessor contextAccessor) {
this.contextAccessor = contextAccessor;
}
T IProvider<T>.Get() {
return contextAccessor.HttpContext.RequestServices.GetService<T>();
}
}
and in Startup:
public void ConfigureServices(IServiceCollection services) {
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<ISingletonService, SingletonService>();
services.AddScoped<IScopedService, ScopedService>();
services.AddTransient<IProvider<IScopedService>, Provider<IScopedService>>();
// other bindings
}
:)
see https://github.com/aspnet/Hosting/issues/793 for more details about using and registering HttpContextAccessor
I've taken this approach to injecting a custom resource provider in my ASP.NET MVC application, but I'm having some problems with object lifetime management.
I'm using Castle Windsor, so I have the following implementation of the factory:
public class DefaultResourceProviderFactory : ResourceProviderFactory
{
public override IResourceProvider CreateGlobalResourceProvider(string classKey)
{
// IoC is a static helper class that gives me static access to the
// container. IoC.Resolve<T>(args...) simply calls container.Resolve<T>(args...).
return IoC.Resolve<IResourceProvider>(new { resourceType = "Global" });
}
public override IResourceProvider CreateLocalResourceProvider(string virtualPath)
{
// resourceType
return IoC.Resolve<IResourceProvider>(new { ResourceType = virtualPath });
}
}
However, the IResourceProvider I have registered in the container doesn't seem to have its lifetime managed correctly. It has some other dependencies of its own, some of which have somewhat complicated lifestyles (per web request or per transaction), so I've registered the IResourceProvider as transient to ensure that its dependencies are always valid. But the MVC framework is stepping on my toes, keeping a reference to the IResourceProvider across web requests, which causes ObjectDisposedExceptions when its dependencies have been invalidated on the next request.
What I'd like to do, is to make the MVC framework use the factory every time it needs an instance of my IResourceProvider, and - if possible - also to invoke IoC.Release(provider) or something similar when it's done with it.
How do I micro-manage the lifestyle of the custom IResourceProvider in a way that the MVC framework will respect?
After searching around for various ways to control the lifetime of the IResourceProvider itself, I decided that it was better to refactor my implementation to utilize the Typed Factory Facility.
My IResourceProvider implementation formerly looked something like this:
public class CachedResourceProvider : IResourceProvider {
CachedResourceProvider(IResourceRecordRepository repo) { /* ... */ }
// other members...
}
Now, I changed it to this instead:
public class CachedResourceProvider : IResourceProvider {
CachedResourceProvider(IResourceRecordRepositoryFactory repo) { /* ... */ }
// other members...
}
The factory interface is a new one, defined as
public interface IResourceRecordRepositoryFactory {
IResourceRecord NewInstance();
void Release(IResourceRecord instance);
}
and every usage of the private _repo instance in the CachedResourceProvider was refactored to three statements: get a repo instance from the factory, use the repo instance to fetch/save something, release the instance through the factory.
I registered them like this:
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IResourceRecordRepositoryFactory>().AsFactory());
Now, even though MVC is keeping a reference to my resource provider across web requests, the services it uses are re-fetched from the Windsor container each time they're used, so the container is in full control of their lifetime.