I have a a completed (and broken) C# app below that generates a stack overflow exception. If you review the source code, you'll see why there's a stack overflow exception, so I'm not really looking at diagnosing WHY it happens, I want to know what the best way of handling it is.
1) All references to unity are encapsulated inside a Class named Registry so I can upgrade without difficulty. I don't want unitycontainer littering other classes where possible. In theory, I should be able to upgrade to 5 if/when it comes out, or even swap it out with ninject or other DI framework if I were to have a drastic change of disposition.
2) I want the Registry to be controlled by the unity container so that it can be used in the constructors for the container controlled classes. (eg FirstSingleInstance)
3) Both IRegistry and Registry inherit from IDisposable because I assume it's good practice to dispose the unity containers.
4) Registry constructs the Unity Container in it's own constructor, so I assume I should also dispose the unity container when registry.dispose is called.
5) all other classes that are controlled by Registry are expected to be single instance classes, so I register them with a ContainerControlledLifetimeManager. I expect those instances will be disposed when the container gets disposed.
What is the best practice for dealing with this situation?
a) do not call dispose on Registry -- let it live for the life of the process thread?
b) Don't try to have Registry (and by extension, UnityContainer) controlled by the unity container. That way calling dispose on Registry won't cause a stackoverflow exception. How I would then have unity construct the FirstSingleInstance class is something I'd have to review.
d) other?
Here's the app that I wrote that has all the relevant pieces
using System;
using Microsoft.Practices.Unity;
namespace DIProblem.Console
{
class Program
{
static void Main(string[] args)
{
IRegistry registry = CreateRegistry();
IFirstSingleInstance theInstance = registry.Resolve<IFirstSingleInstance>();
theInstance.DoThis();
registry.Dispose(); // stack overflow here because of infinite dispose loop
}
static IRegistry CreateRegistry() => new Registry();
}
public class FirstSingleInstance : IFirstSingleInstance
{
private IRegistry _registry;
public FirstSingleInstance(IRegistry reg)
{
_registry = reg;
}
public void DoThis()
{
System.Console.WriteLine("This Was Done.");
_registry.Resolve<ISecondSingleInstance>().DoThisToo();
}
}
public class SecondSingleInstance : ISecondSingleInstance
{
private IRegistry _registry;
public SecondSingleInstance(IRegistry reg)
{
_registry = reg;
}
public void DoThisToo()
{
System.Console.WriteLine("This Was Done too.");
}
}
public interface ISecondSingleInstance
{
void DoThisToo();
}
public interface IFirstSingleInstance
{
void DoThis();
}
public class Registry : IRegistry, IDisposable
{
public Registry()
{
_container = new UnityContainer();
RegisterInstance<IFirstSingleInstance, FirstSingleInstance>();
RegisterInstance<ISecondSingleInstance, SecondSingleInstance>();
_container.RegisterInstance<IRegistry>(this);
}
private UnityContainer _container;
public void RegisterInstance<T1, T2>() where T2 : class, T1 => _container.RegisterType<T1, T2>(new ContainerControlledLifetimeManager());
public T Resolve<T>() => _container.Resolve<T>();
public void Dispose()
{
Dispose(true);
System.GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
_container?.Dispose();
_container = null;
}
}
public interface IRegistry : IDisposable
{
T Resolve<T>();
void RegisterInstance<T1, T2>() where T2 : class, T1;
}
}
Thank you for helping out in whatever way seems reasonable.
The following code refrains from using the Service Locator anti-pattern and instead relies solely on Constructor Injection as pattern for applying Inversion of Control. The result is a simpler, more maintainable and more testable application that doesn't cause any stackoverflow exceptions.
class Program
{
static void Main(string[] args)
{
using (var container = Registry.BuildContainer())
{
var theInstance = registry.Resolve<IFirstSingleInstance>();
theInstance.DoThis();
}
}
}
public static class Registry
{
public static UnityContainer BuildContainer()
{
var container = new UnityContainer();
container.RegisterType<IFirstSingleInstance, FirstSingleInstance>(Singleton);
container.RegisterType<ISecondSingleInstance, SecondSingleInstance>(Singleton);
return container;
}
private static ContainerControlledLifetimeManager Singleton =>
new ContainerControlledLifetimeManager();
}
public interface ISecondSingleInstance
{
void DoThisToo();
}
public interface IFirstSingleInstance
{
void DoThis();
}
public class FirstSingleInstance : IFirstSingleInstance
{
private ISecondSingleInstance _second;
public FirstSingleInstance(ISecondSingleInstance second)
{
_second = second;
}
public void DoThis()
{
System.Console.WriteLine("This Was Done.");
_second.DoThisToo();
}
}
public class SecondSingleInstance : ISecondSingleInstance
{
public SecondSingleInstance(/* other dependencies here */)
{
}
public void DoThisToo()
{
System.Console.WriteLine("This Was Done too.");
}
}
Related
I have the following situation.
SomeClass has a dependency on IDiagram and Diagram implements that interface. The lifetime of SomeClass is the lifetime of the Application, however the lifetime a Diagram is shorter. Say it could change when a certain button is pressed.
Since I could not find anything satisfying on this problem I came up with the pattern depicted in the Diagram below.
The Observer of the Diagram would be aware that the Diagram can change and set the correct instance when it changes.
The Observer would implement the IDiagram interface by delegating the methods of the current Diagram instance.
SomeFactory would create new Diagrams and RaiseChanged.
SomeClass would not be aware of any of this.
Is enforcing this pattern a good idea, which downsides are there? Is there a better solution to this problem?
Example code with IDependency instead of IDiagram below:
private static void Main(string[] args)
{
var transientDependency = new TransientDependency();
var dependencyObserver = new DependecyObserver(transientDependency);
var dependencyFactory = new Factory(transientDependency);
var someClass = new SomeClass(dependencyObserver);
var someOtherClass = new SomeClass(dependencyObserver);
// Note that someClass can only be used after the dependency has been created, because the Changed event has to be invoked
dependencyFactory.CreateDependency();
}
public class DependecyObserver : IDependency
{
public DependecyObserver(TransientDependency transient)
{
transient.Changed += (s, dependency) => Dependency = dependency;
}
private Dependency Dependency { get; set; }
public void SomeMethod()
{
Dependency.SomeMethod();
}
}
public class Factory
{
private TransientDependency TransientDependency { get; }
public Factory(TransientDependency transientDependency)
{
TransientDependency = transientDependency;
}
public void CreateDependency()
{
TransientDependency.RaiseChanged(new Dependency());
}
}
public class SomeClass
{
public SomeClass(IDependency dependency)
{
dependency.SomeMethod();
}
}
public class TransientDependency : TransientInstance<Dependency> { }
public abstract class TransientInstance<T>
{
public EventHandler<T> Changed;
public void RaiseChanged(T instance)
{
Changed?.Invoke(this, instance);
}
}
public class Dependency : IDependency
{
public void SomeMethod()
{
throw new NotImplementedException();
}
}
public interface IDependency
{
void SomeMethod();
}
i wrote a little example to learn IoC and DI on my own.
I have one simple question:
How would you instantiate the unskilled worker in my example /
How can I swich between the following 2 inject candidates?:
kernal.Bind<IRepair>().To<Employee>();
kernal.Bind<IRepair>().To<UnskilledWorker>()
I'm a little bit confused at the moment...
class Program
{
static void Main(string[] args)
{
IWorkShop instance = GetWorkShop();
instance.StartToRepair();
Console.ReadLine();
}
private static IWorkShop GetWorkShop()
{
Ninject.IKernel kernal = new StandardKernel();
kernal.Bind<IWorkShop>().To<WorkShop>();
kernal.Bind<IRepair>().To<Employee>();
var instance = kernal.Get<IWorkShop>();
return instance;
}
}
public class WorkShop : IWorkShop
{
private IRepair _repair;
public WorkShop(IRepair repair)
{
_repair = repair;
}
public void StartToRepair()
{
_repair.RepairItNow();
}
}
interface IWorkShop
{
void StartToRepair();
}
public class Employee : IRepair
{
public void RepairItNow()
{
Console.WriteLine("Employee starts working.");
}
}
public class UnskilledWorker : IRepair
{
public void RepairItNow()
{
Console.WriteLine("Unskilled worker starts working.");
}
}
public interface IRepair
{
void RepairItNow();
}
}
If you know at compile time then you can use Ninject's contextual bindings: https://github.com/ninject/ninject/wiki/Contextual-Binding.
IKernel kernal = new StandardKernel();
kernal.Bind<IWorkShop>().To<WorkShop>();
kernal.Bind<IRepair>().To<Employee>();
kernal.Bind<IRepair>().To<UnskilledWorker>().WhenInjectedInto(typeof(IWorkShop));
var instance = kernal.Get<IWorkShop>();
return instance;
If you need to decide at runtime which dependency to instantiate you are going to have to use a factory pattern.
I have created a WinForms MVC application using Dependency Injection (DI) and Ninject as the DI Container. The basic architecture is as follows
Program.cs (the main entry point of the WinForms application):
static class Program
{
[STAThread]
static void Main()
{
...
CompositionRoot.Initialize(new DependencyModule());
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(CompositionRoot.Resolve<ApplicationShellView>());
}
}
DependencyModule.cs
public class DependencyModule : NinjectModule
{
public override void Load()
{
Bind<IApplicationShellView>().To<ApplicationShellView>();
Bind<IDocumentController>().To<SpreadsheetController>();
Bind<ISpreadsheetView>().To<SpreadsheetView>();
}
}
CompositionRoot.cs
public class CompositionRoot
{
private static IKernel ninjectKernel;
public static void Initialize(INinjectModule module)
{
ninjectKernel = new StandardKernel(module);
}
public static T Resolve<T>()
{
return ninjectKernel.Get<T>();
}
public static IEnumerable<T> ResolveAll<T>()
{
return ninjectKernel.GetAll<T>();
}
}
ApplicationShellView.cs (the main form of the application)
public partial class ApplicationShellView : C1RibbonForm, IApplicationShellView
{
private ApplicationShellController controller;
public ApplicationShellView()
{
this.controller = new ApplicationShellController(this);
InitializeComponent();
}
public void InitializeView()
{
dockPanel.Extender.FloatWindowFactory = new CustomFloatWindowFactory();
dockPanel.Theme = vS2012LightTheme;
}
private void ribbonButtonTest_Click(object sender, EventArgs e)
{
controller.OpenNewSpreadsheet();
}
public DockPanel DockPanel
{
get { return dockPanel; }
}
}
where
public interface IApplicationShellView
{
void InitializeView();
DockPanel DockPanel { get; }
}
ApplicationShellController.cs
public class ApplicationShellController
{
private IApplicationShellView shellView;
public ApplicationShellController(IApplicationShellView view)
{
this.shellView = view;
}
public void OpenNewSpreadsheet(DockState dockState = DockState.Document)
{
SpreadsheetController controller = (SpreadsheetController)GetDocumentController("new.xlsx");
SpreadsheetView view = (SpreadsheetView)controller.New("new.xlsx");
view.Show(shellView.DockPanel, dockState);
}
private IDocumentController GetDocumentController(string path)
{
return CompositionRoot.ResolveAll<IDocumentController>()
.SingleOrDefault(provider => provider.Handles(path));
}
public IApplicationShellView ShellView { get { return shellView; } }
}
SpreadsheetController.cs
public class SpreadsheetController : IDocumentController
{
private ISpreadsheetView view;
public SpreadsheetController(ISpreadsheetView view)
{
this.view = view;
this.view.SetController(this);
}
public bool Handles(string path)
{
string extension = Path.GetExtension(path);
if (!String.IsNullOrEmpty(extension))
{
if (FileTypes.Any(ft => ft.FileExtension.CompareNoCase(extension)))
return true;
}
return false;
}
public void SetViewActive(bool isActive)
{
((SpreadsheetView)view).ShowIcon = isActive;
}
public IDocumentView New(string fileName)
{
// Opens a new file correctly.
}
public IDocumentView Open(string path)
{
// Opens an Excel file correctly.
}
public IEnumerable<DocumentFileType> FileTypes
{
get
{
return new List<DocumentFileType>()
{
new DocumentFileType("CSV", ".csv" ),
new DocumentFileType("Excel", ".xls"),
new DocumentFileType("Excel10", ".xlsx")
};
}
}
}
where the implemented interface is
public interface IDocumentController
{
bool Handles(string path);
void SetViewActive(bool isActive);
IDocumentView New(string fileName);
IDocumentView Open(string path);
IEnumerable<DocumentFileType> FileTypes { get; }
}
Now the view ascociated with this controller is
public partial class SpreadsheetView : DockContent, ISpreadsheetView
{
private IDocumentController controller;
public SpreadsheetView()
{
InitializeComponent();
}
private void SpreadsheetView_Activated(object sender, EventArgs e)
{
controller.SetViewActive(true);
}
private void SpreadsheetView_Deactivate(object sender, EventArgs e)
{
controller.SetViewActive(false);
}
public void SetController(IDocumentController controller)
{
this.controller = controller;
Log.Trace("SpreadsheetView.SetController(): Controller set successfully");
}
public string DisplayName
{
get { return Text; }
set { Text = value; }
}
public WorkbookView WorkbookView
{
get { return workbookView; }
set { workbookView = value; }
}
...
}
Finally the view interfaces are
public interface ISpreadsheetView : IDocumentView
{
WorkbookView WorkbookView { get; set; }
}
and
public interface IDocumentView
{
void SetController(IDocumentController controller);
string DisplayName { get; set; }
bool StatusBarVisible { get; set; }
}
Now for my questions. In Seemann's book "Dependency Injection in .NET" he talks about the "Three Calls Pattern" and this is what I have attempted to implement in the above. The code works, the shell view displays and via the MVC pattern my controllers correctly open views etc. However, I am confused as the above definately has the flavour of the "Service Locator Anti-Pattern". In chapter 3 of Seemann's book he states
The COMPOSITION ROOT pattern describes where you should use a DI CONTAINER. However,
it doesn’t state how to use it. The REGISTER RESOLVE RELEASE pattern addresses
this question [...] A DI CONTAINER should be used in three successive
phases called Register, Resolve, and Release.
In its pure form, the REGISTER RESOLVE RELEASE pattern states that you should only
make a single method call in each phase. Krzysztof Kozimic calls this the Three Calls Pattern.
Configuring a DI CONTAINER in a single method call requires more explanation. The
reason that registration of components should happen in a single method call is
because you should regard configuration of a DI CONTAINER as a single, atomic action.
Once configuration is completed, the container should be regarded as read-only.
This sounds like the dredded "Service locator", why is this not deemed service location?
In order to adjust my code to instead use Contstructor Injection, I changed my entry code to
[STAThread]
static void Main()
{
var kernel = new StandardKernel();
kernel.Bind(t => t.FromThisAssembly()
.SelectAllClasses()
.BindAllInterfaces());
FileLogHandler fileLogHandler = new FileLogHandler(Utils.GetLogFilePath());
Log.LogHandler = fileLogHandler;
Log.Trace("Program.Main(): Logging initialized");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(kernel.Get<ApplicationShellView>());
}
using Ninject.Extensions.Conventions, I then changed ApplicationShellController in order to correct my code to inject the IDocumentControllers via ctor injection:
public class ApplicationShellController
{
private IApplicationShellView shellView;
private IEnumerable<IDocumentController> controllers;
public ApplicationShellController(IApplicationShellView shellView, IEnumerable<IDocumentController> controllers)
{
this.shellView = shellView;
this.controllers = controllers;
Log.Trace("ApplicationShellController.Ctor(): Shell initialized successfully");
}
...
}
where
public class SpreadsheetController : IDocumentController
{
private ISpreadsheetView view;
public SpreadsheetController(ISpreadsheetView view)
{
this.view = view;
this.view.SetController(this);
}
...
}
but this leads to a circular dependency, how do I handle this?
Question Summary:
Why is my initial use of Ninject using "Thee Calls Pattern" and CompositionRoot.Resolve<T>() bad or different to the Service Locator Anti-Pattern?
How can I resolve the circular dependency issue above if I want to switch to pure ctor injection?
Thanks very much for your time.
At some point in the process, you have to use service location. However, the difference between DI and SL is that in SL, you are resolving your services at the point they are requested, whereas in DI you resolve them in some kind of factory (such as a controller factory) and then construct your objects and pass the reference in.
You should create some kind of infrastructure that dispatches your commands and uses a factory of some kind to locate the dependencies used by the created objects.
In this way, the rest of your code doesn't have dependency resolution, and you are following a DI pattern except at the construction point.
I have a console app that uses kernel.Get<SomeClass>(); However, SomeClass has a dependency on SomeDisposableClass. How can I set up my binding to dispose of SomeDisposableClass when SomeClass is garbage collected? My MVC app uses InRequestScope and that works great, but there doesn't seem to be an analogous scope for console apps.
Example here:
public class SomeClass {
public SomeClass(SomeDisposableClass c) {
this.C = c;
}
private SomeDisposableClass C { get; set; }
// ... Business Methods ... //
}
My module
kernel.Bind<ISomeClass>().To<SomeClass>().In???Scope()
My console app
public static void Main() {
SomeFunc();
SomeFunc();
Console.ReadLine();
}
public static void SomeFunc() {
ISomeClass someClass = kernel.Get<ISomeClass>();
// work
}
I'd like for SomeDisposableClass to be disposed when SomeFunc is finished (or when the garbage collector is called). But I'm not sure of which binding scope to use. InTransientScope doesn't ever call dispose. Do I just have to make SomeClass disposable and implement Dispose() and wrap all my usages in the console app with a using statement?
In Ninject2, you can do this by:
Bind<IService>().To<ServiceImpl>().InScope(ctx => ...);
For example, the callback used for InRequestScope() is:
ctx => HttpContext.Current
Since HttpContext.Current is set to a new instance of HttpContext on each web request, only a single instance of the service will be activated for each request, and when the request ends and the HttpContext is (eventually) collected, the instances will be deactivated.
You can have a static variable within your console to reference an object that will control lifetime.
public static object LifetimeController = new object();
You can register this as your lifetime control object
Bind<IService>().To<ServiceImpl>().InScope(ctx => LifetimeController);
And each time you want to refresh the objects you can have a method like this
public static void StartNewLifetime()
{
LifetimeController = new object();
}
See here and here for more information
Use InTransientScope -- then the Ninject container will not hold any reference to the object. That way SomeClass will be GC'd when it goes out of scope at the end of SomeFunc. All you need to do is have its finalizer dispose of the SomeDisposableClass instance:
public class SomeClass : IDisposable {
~SomeClass() {
if (this.C != null) this.C.Dispose();
}
}
Here's how I was testing:
class Program
{
private static IKernel _kernel;
static void Main(string[] args)
{
_kernel = new StandardKernel();
_kernel.Bind<ISomeClass>().To<SomeClass>().InTransientScope();
while (true)
{
LifetimeController = new object();
SomeFunc();
Thread.Sleep(10);
}
}
public static void SomeFunc()
{
_kernel.Get<ISomeClass>();
}
public interface ISomeClass { }
public class SomeClass : ISomeClass
{
public SomeDisposableClass C = new SomeDisposableClass();
~SomeClass()
{
Console.WriteLine("{0} finalized", this);
C.Dispose();
}
}
public class SomeDisposableClass : IDisposable
{
private byte[] bytes = new byte[1000000];
public void Dispose()
{
Console.WriteLine("{0} disposed", this);
}
}
}
Consider this code:
public class IocConfig
{
protected static StandardKernel Kernel { get; set; }
public static void RegisterIoc(HttpConfiguration config)
{
using (IKernel kernel = new StandardKernel())
{
RegisterDependency();
config.DependencyResolver = new NinjectDependencyResolver(kernel);
}
}
public static void RegisterIoc()
{
RegisterDependency();
}
private static void RegisterDependency()
{
if (Kernel == null)
{
Kernel = new StandardKernel();
}
Kernel.Bind<CallCenterLogger>().ToSelf().Intercept().With(new TimingInterceptor());
}
public static T GetType<T>()
{
RegisterDependency();
return Kernel.Get<T>();
}
}
in this line:
Kernel.Bind<CallCenterLogger>().ToSelf().Intercept().With(new TimingInterceptor());
I get this error:
Error loading Ninject component IAdviceFactory
No such component has been registered in the kernel's component container.
Suggestions:
1) If you have created a custom subclass for KernelBase, ensure that you have properly
implemented the AddComponents() method.
2) Ensure that you have not removed the component from the container via a call to RemoveAll().
3) Ensure you have not accidentally created more than one kernel.
How can solve it?
Most likely you have added Ninject.Extensions.Interception but not any of the concrete implementations Ninject.Extensions.Interception,DynamicProxy or Ninject.Extensions.Interception,LinFu