LifetimeManager in Builder Strategy - c#

I want to implement a disposing transient lifetime manager for Unity version 3.5. The problem is that I don't know how to access the LifetimeManager in the PostTearDown,etc. steps of the BuilderStrategy class. context.Lifetime works fine in Unity 2.
Basically I have the following:
Container = new UnityContainer();
Container.AddNewExtension<DisposableStrategyExtension>();
Container.RegisterType<ITest, Test>(new DisposingTransientLifetimeManager());
public class DisposingLifetimeStrategy : BuilderStrategy
{
public override void PreBuildUp(IBuilderContext context)
{
base.PreBuildUp(context);
// context.Lifetime.Count == 0 here and in all other methods.
// In version 2 of unity this is set.
}
// implement rest of methods, but context.Lifetime.Count is 0 in all of them too.
public class DisposingTransientLifetimeManager : LifetimeManager
// implement abstract methods minimally

You can get the lifetime manager from the policy list:
public class DisposingLifetimeStrategy : BuilderStrategy
{
public override void PreBuildUp(IBuilderContext context)
{
ILifetimePolicy lifeTime = context.Policies.Get<ILifetimePolicy>(context.BuildKey);
base.PreBuildUp(context);
}
public override void PreTearDown(IBuilderContext context)
{
// Assumes registration name is null
var buildKey = new NamedTypeBuildKey(context.Existing.GetType());
ILifetimePolicy lifeTime = context.Policies.Get<ILifetimePolicy>(buildKey);
base.PreTearDown(context);
}
}
If you are calling IUnityContainer.Teardown(obj) then the PreTearDown and PostTearDown methods will not know the name of the resolved object. That may not matter as long as a default (null) registration exists (since I assume you just want to cast the object to an IDisposable and then Dispose the object).

Related

The type XXX is not assignable to service YYY

I need help with my autofac generics configuration. I get the below error which I can't seem to get around. I have an interface using generics called IScript<TOptionType>.
Implementing that interface is an abstract class called Script<TOptionType> : IScript<TOptionType>. Derived from that abstract class are two concrete classes that set their preferred TOptionType.
I've uploaded a sample .net core application that exhibits the problem here: https://github.com/Strandedpirate/agr
To run go to agr\autofac-generic-registration and type in dotnet run.
C# seems to have no problems boxing the concrete types to either the interface or abstract base class. So why is autofac complaining here?
C:\Users\strandedpirate\source\repos\agr\autofac-generic-registration (master -> origin)
λ dotnet run
Unhandled Exception: System.ArgumentException: The type 'agr.TableScript' is not assignable to service 'agr.Script`1'.
at Autofac.Builder.RegistrationBuilder.CreateRegistration(Guid id, RegistrationData data, IInstanceActivator activator, Service[] services, IComponentRegistration target) in C:\projects\autofac\src\Autofac\Builder\RegistrationBuilder.cs:line 192
at Autofac.Builder.RegistrationBuilder.CreateRegistration[TLimit,TActivatorData,TSingleRegistrationStyle](IRegistrationBuilder`3 builder) in C:\projects\autofac\src\Autofac\Builder\RegistrationBuilder.cs:line 132
at Autofac.Builder.RegistrationBuilder.RegisterSingleComponent[TLimit,TActivatorData,TSingleRegistrationStyle](IComponentRegistry cr, IRegistrationBuilder`3 builder) in C:\projects\autofac\src\Autofac\Builder\RegistrationBuilder.cs:line 249
at Autofac.ContainerBuilder.Build(IComponentRegistry componentRegistry, Boolean excludeDefaultModules) in C:\projects\autofac\src\Autofac\ContainerBuilder.cs:line 240
at Autofac.ContainerBuilder.Build(ContainerBuildOptions options) in C:\projects\autofac\src\Autofac\ContainerBuilder.cs:line 148
at agr.Program.Main(String[] args) in C:\Users\strandedpirate\source\repos\agr\autofac-generic-registration\Program.cs:line 22
Program.cs
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
// comment out the next registrations to see the program run.
builder.RegisterType<TableScript>()
.As<Script<TableScriptOptions>>()
.InstancePerLifetimeScope();
builder.RegisterType<TableScript>()
.As(typeof(Script<>))
.InstancePerLifetimeScope();
builder.RegisterType<TableScript>()
.As(typeof(IScript<>))
.InstancePerLifetimeScope();
// explodes here during autofac building.
var container = builder.Build();
// if you comment out the above autofac configuration this will succeed compile and run-time.
// why does c# have no problems converting TableScript to IScript<T> and Script<T> but autofac is complaining?
TestInterface(new TableScript());
TestAbstractBase(new TableScript());
using (var scope = container.BeginLifetimeScope())
{
Console.WriteLine("Resolving IScript instance...");
var instance = scope.Resolve(typeof(IScript<>)) as IScript<object>;
instance.Run();
}
}
static void TestInterface<T>(IScript<T> a)
where T : class, new()
{
Console.WriteLine($"{nameof(TestInterface)} called - {a.CanHandle("table")}");
}
static void TestAbstractBase<T>(Script<T> a)
where T : class, new()
{
Console.WriteLine($"{nameof(TestAbstractBase)} called - {a.CanHandle("table")}");
}
}
IScript.cs
public interface IScript<TOptionType>
where TOptionType : class, new()
{
bool CanHandle(string key);
Task Run();
bool Validate(TOptionType options);
}
Script.cs
public abstract class Script<TOptionType> : IScript<TOptionType>
where TOptionType : class, new()
{
public abstract bool CanHandle(string key);
public abstract Task Run();
public virtual bool Validate(TOptionType options)
{
return true;
}
}
TableScript.cs
public class TableScript : Script<TableScriptOptions>
{
public override bool CanHandle(string key)
{
return key == "table";
}
public override Task Run()
{
Console.WriteLine($"{nameof(TableScript)} executed");
return Task.CompletedTask;
}
}
FileScript.cs
public class FileScript : Script<FileScriptOptions>
{
public override bool CanHandle(string key)
{
return key == "file";
}
public override Task Run()
{
Console.WriteLine($"{nameof(FileScript)} executed");
return Task.CompletedTask;
}
}
There are a couple of issues.
First, your TableScript registration:
builder.RegisterType<TableScript>()
.As(typeof(Script<>))
.InstancePerLifetimeScope();
builder.RegisterType<TableScript>()
.As(typeof(IScript<>))
.InstancePerLifetimeScope();
You're trying to register a closed generic as an open generic. If you think about what that means, it'd be like saying "TableScript can allow any T for Script<T> and IScript<T>". For example, I see TableScript : Script<TableScriptOptions> - what the open generic registration is saying is it should somehow also work for Script<IntegerScriptOptions> or anything else that could possibly go inside those angle brackets.
Instead, register it as the closed generic it is. And I would recommend doing it on the same registration or you could get two different instances of TableScript per lifetime scope depending on which service gets resolved.
builder.RegisterType<TableScript>()
.As<Script<TableScriptOptions>>()
.As<IScript<TableScriptOptions>>()
.InstancePerLifetimeScope();
Next, the resolution of IScript<T>:
scope.Resolve(typeof(IScript<>)) as IScript<object>;
Think of Resolve as being a lot like new. If you can't use new or Activator.CreateInstance in its place (basically) then it won't work. For example, you can't do this:
// This isn't a thing
new Script<>();
You also can't put an open generic into a constructor of an object quite like this:
public class MyClass
{
// This also isn't a thing
public MyClass(IScript<> script) { /* ... */ }
}
You can't new-up an open generic. The compiler needs to know what the T is in Script<T>. By that same token, you can't resolve an open generic. That doesn't make sense. You have to resolve a closed generic.
scope.Resolve<IScript<TableScriptOptions>>();
If you really want to use reflection, you still have to make it a closed generic.
var script = typeof(IScript<>);
var options = typeof(TableScriptOptions);
var closed = script.MakeGenericType(new Type[] { options });
scope.Resolve(closed);

Simple Injector - Singleton with transient dependency design

The context
I know the purpose of SimpleInjector's LifestyleMismatch exception and why it throws it. But suppose to have:
Players.dll
public abstract class PlayerEqualizer { ... }
public abstract class Player : IPlayer, ISongAware
{
public Player(PlayerEqualizer eq)
{
Equalizer = eq;
}
public PlayerEqualizer Equalizer { get; }
public abstract void StartPlay();
}
Players.Rock.dll
public class RockPlayerEqualizer : PlayerEqualizer {}
public class RockPlayer : Player
{
public RockPlayer(RockPlayerEqualizer eq) : base(eq) {}
public override void StartPlay() { ... }
}
public class RnBPlayer : Player
{
public RnBPlayer(RockPlayerEqualizer eq) : base(eq) {}
public override void StartPlay() { ... }
}
Players.Pop.dll
public class PopPlayerEqualizer : PlayerEqualizer{}
public class PopPlayer : Player
{
public PopPlayer(PopPlayerEqualizer eq) : base(eq) {}
public override void StartPlay() { ... }
}
All the implementation of Player are registered as a collection of IPlayer and all the registrations are singleton:
var registrations = container
.GetTypesToRegister(typeof(IPlayer), assemblies)
.Select(t => Lifestyle.Singleton.CreateRegistration(t, container));
foreach (var registration in registrations)
{
container.AddRegistration(registration.ImplementationType, registration);
}
container.RegisterCollection<IPlayer>(registrations);
container.RegisterCollection<ISongAware>(container.GetCurrentRegistrations()
.Where(ip => typeof(ISongAware).IsAssignableFrom(ip.ServiceType))
.Select(ip => ip.Registration));
The problem
All
container.GetInstance<RockPlayer>
container.GetAllInstances<IPlayer>
container.GetAllInstances<ISongAware>
must return the same instance, so the IPlayer registrations must be singleton. Doing so, all the PlayerEqualizer must be singleton as well, since they are dependency of a singleton registration, but the PlayerEqualizer implementation aren't singleton (RockPlayer and RnBPlayer both depend on RockPlayerEqualizer but they need different instances).
What I tried
The only solution I could find is to set the SimpleInjector container.Options.SuppressLifestyleMismatchVerification flag to False but I don't want to lose that feature... Another option could be call the SuppressDiagnosticWarning method on the IPlayer's registrations but despite I couldn't get it to work, my real concern is that these solutions are just workaround...
Am I missing something?
What you want is not to register PlayerEqualizer instances as Transient but as Instance Per Dependency.
Technically, both lifestyles are the same, as they both return new instances on every request. The intend of Instance per Dependency is however, very different, because:
Each consumer will get a new instance of the given service type and that dependency is expected to get live as long as its consuming type.
While with Transient the intention is the dependency to be short-lived.
This lifestyle is deliberately left out of Simple Injector, because:
its usefulness is very limited compared to the Transient lifestyle. It ignores lifestyle mismatch checks and this can easily lead to errors, and it ignores the fact that application components should be immutable. In case a component is immutable, it’s very unlikely that each consumer requires its own instance of the injected dependency.
The project's Code Samples however contains the definition of a InstancePerDependencyLifestyle that does what you want it do do:
It gives every consumer its own instance
It ignores lifestyle mismatches on the registration, since the instance is expected to live as long as its consumer
You can use this lifestyle as follows:
container.Register<RockPlayerEqualizer>(new InstancePerDependencyLifestyle());
UPDATE:
Do note that your configuration can be simplified to the following:
var playerTypes = var registrations = container
.GetTypesToRegister(typeof(IPlayer), assemblies);
foreach (Type playerType in playerTypes)
{
container.Register(playerType, Lifestyle.Singleton);
}
container.RegisterCollection<IPlayer>(assemblies);
container.RegisterCollection<ISongAware>(assemblies);

Windows Service with Autofac Holds onto References

We are in the middle of attempting a drop-in replacement of Autofac for Ninject in our windows service (before potentially making more enhancement to take care of Autofac features), but are running into a memory issue.
Here's a contrived example that doesn't reproduce our issue, but demonstrates the current layout of the app:
class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
var ms = new MemoryStream(new byte[10000000]);
var ms2 = new MemoryStream(new byte[10000000]);
builder.RegisterType<BaseRepo>()
.WithParameter("ms", ms)
.As<IBaseRepo>();
builder.RegisterType<DerivedRepo>()
.WithParameter("ms", ms2)
.As<IDerivedRepo>();
builder.RegisterType<BaseFactory>().As<IBaseFactory>();
builder.RegisterType<Derived>().AsSelf();
builder.RegisterType<Derived>().Keyed<Base>(BaseEnum.Derived).As<Base>();
var container = builder.Build();
var factory = container.Resolve<IBaseFactory>();
while (true)
{
var instance = factory.Create(BaseEnum.Derived);
instance.DoSomething();
instance.Dispose();
Thread.Sleep(5000);
}
}
}
public interface IDerivedRepo : IDisposable {}
public class DerivedRepo : IDerivedRepo
{
private readonly MemoryStream _ms;
public DerivedRepo(MemoryStream ms)
{
_ms = ms;
}
public void Dispose()
{
_ms.Dispose();
}
}
public interface IBaseRepo : IDisposable {}
public class BaseRepo : IBaseRepo
{
private readonly MemoryStream _ms;
public BaseRepo(MemoryStream ms)
{
_ms = ms;
}
public void Dispose()
{
_ms.Dispose();
}
}
public enum BaseEnum
{
Derived = 1
}
public interface IBaseFactory
{
Base Create(BaseEnum baseEnum);
}
public class BaseFactory : IBaseFactory
{
private readonly IComponentContext _componentContext;
public BaseFactory(IComponentContext componentContext)
{
_componentContext = componentContext;
}
public Base Create(BaseEnum baseEnum)
{
return _componentContext.ResolveOptionalKeyed<Base>(baseEnum);
}
}
public interface IDisposableThing : IDisposable
{
void DoSomething();
}
public abstract class Base : IDisposableThing
{
protected readonly IBaseRepo BaseRepo;
protected Base(IBaseRepo baseRepo)
{
BaseRepo = baseRepo;
}
public void Dispose()
{
Console.WriteLine("Disposing base");
BaseRepo.Dispose();
}
public abstract void DisposeChildren();
public void DoSomething()
{
Console.WriteLine("Doing something");
}
}
public class Derived : Base
{
private readonly IDerivedRepo _derivedRepo;
public Derived(IBaseRepo baseRepo, IDerivedRepo derivedRepo) : base(baseRepo)
{
_derivedRepo = derivedRepo;
}
public override void DisposeChildren()
{
Console.WriteLine("Disposing derived");
_derivedRepo.Dispose();
}
}
Basically, we--at regular intervals--use a factory to instantiate an instance of an abstract class based on an enum value, do some work with that instance, then dispose of it. The problem is that those instances are not getting cleaned up by the garbage collector and the memory usage of the app increases steadily, with DebugDiag2 reporting that it is holding onto instances of the equivalent of our MemoryStream members in our repos (in our real app, these are wrappers over Entity Framework DBContext), with no other references to our code reported in its analysis so I have nothing else to go on.
I know there probably isn't enough here to give a definitive answer, what I'm more looking for is suggestions on where we are obviously doing something wrong (the whole team is new to Autofac and I know we are using the service locator anti-pattern, but I assume that isn't causing the problems we are seeing).
The behavior you experience is normal as Autofac keeps track, within a lifetime scope, of objects it resolves. These will be disposed when the associated lifetime scope is itself disposed. In your case, you only have one lifetime scope, the one created when you build the container from the builder.
I suggest that you have a good read of this documentation page which explains more in detail how lifetime scopes work.
A starting point would be to create an inner lifetime scope every time you start new work within the regular interval. It could look something like this:
var container = builder.Build();
while (true)
{
// Create an inner lifetime scope that will keep track of every
// object it creates
using (var lifetimeScope = container.BeginLifetimeScope())
{
// resolve objects from `lifetimeScope`
// do work with them
}
// At the end of the using directive, lifetimeScope will be disposed
// and will dispose with it any objects it kept track of
Thread.Sleep(5000);
}

Dispose for Unit Of Work

I have a code where controller calls service and service use Unit Of Work to handle DB. I have used Unity as dependency injection. I need to dispose unity(dbContext) automatically after request scope ends. I am not getting reference to PerRequestLifetimeManager in UnityCofig.cs. Any pointers?
Try creating new derived type of lifetime manager
public class PerHttpRequestLifetime : LifetimeManager
{
// This is very important part and the reason why I believe mentioned
// PerCallContext implementation is wrong.
private readonly Guid _key = Guid.NewGuid();
public override object GetValue()
{
return HttpContext.Current.Items[_key];
}
public override void SetValue(object newValue)
{
HttpContext.Current.Items[_key] = newValue;
}
public override void RemoveValue()
{
var obj = GetValue();
HttpContext.Current.Items.Remove(obj);
}
}
Source:
MVC, EF - DataContext singleton instance Per-Web-Request in Unity

Autofac factory of unit of work in a singleton

Plain and simple as the title suggests, is this a possible thing using Autofac dependency injection? I have been trying and searching everywhere.. I'm losing hope here.
My class has to be singleton - that can't change. I want it to take a factory of unit of works - for database transactions.
Please help me figure this one out, I'm deseperate.
Tried Func<> and registering my unit of work in every possible way (all sorts of lifetimes, externally owned or not) but failed because the DbContext within the unit of work is disposed and not created again after the first request
Edit:
Added code that will hopefully help understanding my problem:
public class SingletonDataService : IDataService
{
private _uowFactory;
public SingletonDataService(Func<IEFUnitOfWork> uowFactory)
{
_uowFactory = uowFactory
}
public List<Folder> GetAllFolders ()
{
using (uow = uowFactory())
{
return uow.FoldersRepository.GetAll();
}
}
}
public MyDbContext : DbContext
{
public DbSet<Folder> Folders {get; set;}
public DbSet<Letter> Letters {get; set;}
public MyDbContext() : base("myContext...")
}
public EFUnitOfWork : IEFUnitOfWork, IDisposable
{
public IRepository<Folder> FoldersRepository;
public IRepository<Letter> LettersRepository;
private DbContext _context;
public EFUnitOfWork(IRepository<Folder> folders, IRepository<Letter> letters, DbContext context)
{
_folders = folders;
_letters = letters;
_context = context;
}
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
_context.Dispose();
}
disposed = true;
}
}
}
public Repository<T> : IRepository<T> where T: BaseEntity
{
private DbContext _context;
private DbSet<T> _set
public Repository(DbContext context)
{
_context = context;
_set = _context.Set<T>();
}
}
public LettersController : ApiController
{
private IDataService _dataService;
public LettersController(IDataService dataService)
{
_dataService = dataService;
}
[HttpGet]
public IHttpActionResult GetAllLetters()
{
return Ok(_dataService.GetAllLetters());
}
}
// Must be singleton
builder.Register<SingletonDataService>().As(IDataService).SingleInstance();
builder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
builder.Register<EFUnitOfWork>().As(IEFUnitOfWork).InstancePerLifetimeScope();
builder.Register<DbContext>().As(AppDbContext).InstancePerLifetimeScope();
In the first request everything works fine, in the second third and so on I get this exception :
system.ObjectDisposedException: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
I clearly see it happens because the context in my repository is now null, but I don't how to to change that with the DI.
What I want to achieve is so easy without DI :
How can I achieve the following with Autofac??
public class UowFactory
{
public UowFactory()
{
}
public IEFUnitOfWork Create()
{
var context = new AppDbContext()
var uow = new EFUnitOfWork(new Repository<Folder>(context), new Repository<Letter>(context), context);
return uow;
}
}
Issue
You are registering the critial components with InstancePerLifetimeScope()
When the autofac container is built it also creates a root ILifetimeScope which lives until IContainer.Dispose() is called. Now unless you create nested ILifetimeScope somewhere in the chain to the SingletonDataService, the ILifetimeScope which is used your components is the root ILifetimeScope and InstancePerLifetimeScope() effectly becomes equivalent to SingleInstance().
Solution
One of the possible solutions is to create an ILifetimeScope per IEFUnitOfWork and its children. Autofac facilitates this by providing the Owned<T> type. We can use it in conjunction with a Func<> factory (also see documentation):
public class SingletonDataService : IDataService
{
private Func<Owned<IEFUnitOfWork>> _uowFactory;
public SingletonDataService(Func<Owned<IEFUnitOfWork>> uowFactory)
{
_uowFactory = uowFactory
}
public List<Folder> GetAllFolders ()
{
using (var uow = _uowFactory())
{
return uow.Value.FoldersRepository.GetAll();
}
}
}
This should play nicely with the following registrations:
// Must be singleton
builder.Register<SingletonDataService>().As(IDataService).SingleInstance();
builder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
builder.Register<EFUnitOfWork>().As(IEFUnitOfWork).InstancePerLifetimeScope();
builder.Register<DbContext>().As(AppDbContext).InstancePerLifetimeScope();
However, note, that DbContext being bound with InstancePerLifetimeScope basically makes the manual disposal in EFUnitOfWork redundant.
Sidenote on proper Disposal
Since IDisposable types should support graceful multi-disposal , one should be able to simplify EFUnitOfWork.Dispose() to
public void Dispose()
{
_context.Dispose();
}
Also note, that i left out the call GC.SuppressFinalize(this);. This call is only relevant in case the class implements a custom finalizer (~EFUnitOfWork method) - or a deriving class could do so, otherwise the object is not put on the finalizer queue anyway.
Your problem is that you have a singleton (SingletonDataService) depend on a service that has a shorter lifetime (EFUnitOfWork). When the SingletonDataService instance is created by autofac, it gets an instance of EFUnitOfWork, but this instance will always stay the same (its actual lifetime will be longer than you expect) and thus gets disposed and used again, giving errors.
You have two possible solutions:
One is to create a UowFactory class like the one you defined at the bottom (but with dependencies on IRepository<Folder>, IRepository<Letter>, DbContext), register that as anything (for example singleton, but it won't matter) and make the SingletonDataService depend on it. This will likely not be a viable solution to you though, since it will also extend the lifetime of the IRepository<Folder>, IRepository<Letter>, DbContext instances and create problems there.
The proper solution is to remove the reason why you would want the SingletonDataService to be a singleton, probably some cache. And move it to a new service (CacheService?) on which the SingletonDataService depends and make that new service a singleton.

Categories

Resources