I ran Code Analysis on my Web API project, in which I'm trying to implement IoC and DI using Castle Windsor, and it found four problems. The four things it found were all in WindsorDependencyResolver, and all four are "Implement IDisposable correctly" namely:
0)
CA1063 Implement IDisposable correctly Provide an overridable implementation of Dispose(bool) on 'WindsorDependencyResolver' or mark the type as sealed. A call to Dispose(false) should only clean up native resources. A call to Dispose(true) should clean up both managed and native resources.
That points to this line of code:
public class WindsorDependencyResolver : System.Web.Http.Dependencies.IDependencyResolver
1)
CA1063 Implement IDisposable correctly Modify 'WindsorDependencyResolver.Dispose()' so that it calls Dispose(true), then calls GC.SuppressFinalize on the current object instance ('this' or 'Me' in Visual Basic), and then returns.
That points to this line of code:
public void Dispose()
2) Same as O, but for the WindsorDependencyScope : IDependencyScope class.
3) Same as 1, but ""
I got the code I'm trying from Castle Windsor articles online, mainly from from this post. The entire code for this file is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http.Dependencies;
using Castle.Windsor;
using Castle.MicroKernel.Registration;
using System.Web.Http;
using Castle.MicroKernel.Lifestyle;
using Castle.MicroKernel.SubSystems.Configuration;
using HandheldServer.Models;
namespace HandheldServer
{
public class WindsorDependencyResolver : System.Web.Http.Dependencies.IDependencyResolver
{
private readonly IWindsorContainer _container;
public WindsorDependencyResolver(IWindsorContainer container)
{
_container = container;
}
public IDependencyScope BeginScope()
{
return new WindsorDependencyScope(_container);
}
public object GetService(Type serviceType)
{
return _container.Kernel.HasComponent(serviceType) ? _container.Resolve(serviceType) : null;
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (!_container.Kernel.HasComponent(serviceType))
{
return new object[0];
}
return _container.ResolveAll(serviceType).Cast<object>();
}
public void Dispose()
{
_container.Dispose();
}
}
public class WindsorDependencyScope : IDependencyScope
{
private readonly IWindsorContainer _container;
private readonly IDisposable _scope;
public WindsorDependencyScope(IWindsorContainer container)
{
this._container = container;
this._scope = container.BeginScope();
}
public object GetService(Type serviceType)
{
if (_container.Kernel.HasComponent(serviceType))
{
return _container.Resolve(serviceType);
}
else
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this._container.ResolveAll(serviceType).Cast<object>();
}
public void Dispose()
{
this._scope.Dispose();
}
}
public class ApiControllersInstaller : IWindsorInstaller
{
public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly() // should it be Types instead of Classes?
.BasedOn<ApiController>()
.LifestylePerWebRequest());
}
}
// This idea from https://github.com/argeset/set-locale/blob/master/src/client/SetLocale.Client.Web/Configurations/IocConfig.cs
public class ServiceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IDeliveryItemRepository>().ImplementedBy<DeliveryItemRepository>().LifestylePerWebRequest(),
Component.For<IDeliveryRepository>().ImplementedBy<DeliveryRepository>().LifestylePerWebRequest(),
Component.For<IDepartmentRepository>().ImplementedBy<DepartmentRepository>().LifestylePerWebRequest(),
Component.For<IExpenseRepository>().ImplementedBy<ExpenseRepository>().LifestylePerWebRequest(),
Component.For<IInventoryItemRepository>().ImplementedBy<InventoryItemRepository>().LifestylePerWebRequest(),
Component.For<IInventoryRepository>().ImplementedBy<InventoryRepository>().LifestylePerWebRequest(),
Component.For<IItemGroupRepository>().ImplementedBy<ItemGroupRepository>().LifestylePerWebRequest());
}
}
}
What is the best way to mollify the Code Analysis tool?
Before answering your question please note that you should be very careful calling Dispose() on an object you didn't create and therefore are probably not responsible for. By this I mean the line
_container.Dispose();
the container was passed in so strictly speaking it is not yours to dispose of.
The easiest way to mollify the Code Analysis tool is to implement IDisposable as recommended
public class WindsorDependencyResolver
{
public WindsorDependencyResolver()
{
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private bool disposed;
protected virtual void Dispose(bool disposing)
{
if (this.disposed) return;
if (disposing)
{
// call dispose on managed resources
// set to null
}
this.disposed = true;
}
}
See here for a thorough explanation of why, followed by many reasoned arguments as to why not! I would suggest that at the end of the day you should stick to your chosen standards and if that includes the code analysis tool then so be it.
Related
I'm trying to implement IoC in my windows form application. My choice fell on Simple Injector, because it's fast and lightweight. I also implement unit of work and repository pattern in my apps. Here is the structure:
DbContext:
public class MemberContext : DbContext
{
public MemberContext()
: base("Name=MemberContext")
{ }
public DbSet<Member> Members { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();\
}
}
Model:
public class Member
{
public int MemberID { get; set; }
public string Name { get; set; }
}
GenericRepository:
public abstract class GenericRepository<TEntity> : IGenericRepository<TEntity>
where TEntity : class
{
internal DbContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(DbContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
}
MemberRepository:
public class MemberRepository : GenericRepository<Member>, IMemberRepository
{
public MemberRepository(DbContext context)
: base(context)
{ }
}
UnitOfWork:
public class UnitOfWork : IUnitOfWork
{
public DbContext context;
public UnitOfWork(DbContext context)
{
this.context = context;
}
public void SaveChanges()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
MemberService:
public class MemberService : IMemberService
{
private readonly IUnitOfWork unitOfWork;
private readonly IMemberRepository memberRepository;
public MemberService(IUnitOfWork unitOfWork, IMemberRepository memberRepository)
{
this.unitOfWork = unitOfWork;
this.memberRepository = memberRepository;
}
public void Save(Member member)
{
Save(new List<Member> { member });
}
public void Save(List<Member> members)
{
members.ForEach(m =>
{
if (m.MemberID == default(int))
{
memberRepository.Insert(m);
}
});
unitOfWork.SaveChanges();
}
}
In Member Form I only add a textbox to input member name and a button to save to database. This is the code in member form:
frmMember:
public partial class frmMember : Form
{
private readonly IMemberService memberService;
public frmMember(IMemberService memberService)
{
InitializeComponent();
this.memberService = memberService;
}
private void btnSave_Click(object sender, EventArgs e)
{
Member member = new Member();
member.Name = txtName.Text;
memberService.Save(member);
}
}
I implement the SimpleInjector (refer to http://simpleinjector.readthedocs.org/en/latest/windowsformsintegration.html) in Program.cs as seen in the code below:
static class Program
{
private static Container container;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
Application.Run(new frmMember((MemberService)container.GetInstance(typeof(IMemberService))));
}
private static void Bootstrap()
{
container = new Container();
container.RegisterSingle<IMemberRepository, MemberRepository>();
container.Register<IMemberService, MemberService>();
container.Register<DbContext, MemberContext>();
container.Register<IUnitOfWork, UnitOfWork>();
container.Verify();
}
}
When I run the program and add a member, it doesn't save to database. If I changed container.Register to container.RegisterSingle, it will save to database. From the documentation, RegisterSingle will make my class to be a Singleton. I can't using RegisterLifeTimeScope because it will generate an error
"The registered delegate for type IMemberService threw an exception. The IUnitOfWork is registered as 'Lifetime Scope' lifestyle, but the instance is requested outside the context of a Lifetime Scope"
1) How to use SimpleInjector in Windows Form with UnitOfWork & Repository pattern?
2) Do I implement the patterns correctly?
The problem you have is the difference in lifestyles between your service, repository, unitofwork and dbcontext.
Because the MemberRepository has a Singleton lifestyle, Simple Injector will create one instance which will be reused for the duration of the application, which could be days, even weeks or months with a WinForms application. The direct consequence from registering the MemberRepository as Singleton is that all dependencies of this class will become Singletons as well, no matter what lifestyle is used in the registration. This is a common problem called Captive Dependency.
As a side note: The diagnostic services of Simple Injector are able to spot this configuration mistake and will show/throw a Potential Lifestyle Mismatch warning.
So the MemberRepository is Singleton and has one and the same DbContext throughout the application lifetime. But the UnitOfWork, which has a dependency also on DbContext will receive a different instance of the DbContext, because the registration for DbContext is Transient. This context will, in your example, never save the newly created Member because this DbContext does not have any newly created Member, the member is created in a different DbContext.
When you change the registration of DbContext to RegisterSingleton it will start working, because now every service, class or whatever depending on DbContext will get the same instance.
But this is certainly not the solution because having one DbContext for the lifetime of the application will get you into trouble, as you probably already know. This is explained in great detail in this post.
The solution you need is using a Scoped instance of the DbContext, which you already tried. You are missing some information on how to use the lifetime scope feature of Simple Injector (and most of the other containers out there). When using a Scoped lifestyle there must be an active scope as the exception message clearly states. Starting a lifetime scope is pretty simple:
using (ThreadScopedLifestyle.BeginScope(container))
{
// all instances resolved within this scope
// with a ThreadScopedLifestyleLifestyle
// will be the same instance
}
You can read in detail here.
Changing the registrations to:
var container = new Container();
container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();
container.Register<IMemberRepository, MemberRepository>(Lifestyle.Scoped);
container.Register<IMemberService, MemberService>(Lifestyle.Scoped);
container.Register<DbContext, MemberContext>(Lifestyle.Scoped);
container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);
and changing the code from btnSaveClick() to:
private void btnSave_Click(object sender, EventArgs e)
{
Member member = new Member();
member.Name = txtName.Text;
using (ThreadScopedLifestyle.BeginScope(container))
{
var memberService = container.GetInstance<IMemberService>();
memberService.Save(member);
}
}
is basically what you need.
But we have now introduced a new problem. We are now using the Service Locator anti pattern to get a Scoped instance of the IMemberService implementation. Therefore we need some infrastructural object which will handle this for us as a Cross-Cutting Concern in the application. A Decorator is a perfect way to implement this. See also here. This will look like:
public class ThreadScopedMemberServiceDecorator : IMemberService
{
private readonly Func<IMemberService> decorateeFactory;
private readonly Container container;
public ThreadScopedMemberServiceDecorator(Func<IMemberService> decorateeFactory,
Container container)
{
this.decorateeFactory = decorateeFactory;
this.container = container;
}
public void Save(List<Member> members)
{
using (ThreadScopedLifestyle.BeginScope(container))
{
IMemberService service = this.decorateeFactory.Invoke();
service.Save(members);
}
}
}
You now register this as a (Singleton) Decorator in the Simple Injector Container like this:
container.RegisterDecorator(
typeof(IMemberService),
typeof(ThreadScopedMemberServiceDecorator),
Lifestyle.Singleton);
The container will provide a class which depends on IMemberService with this ThreadScopedMemberServiceDecorator. In this the container will inject a Func<IMemberService> which, when invoked, will return an instance from the container using the configured lifestyle.
Adding this Decorator (and its registration) and changing the lifestyles will fix the issue from your example.
I expect however that your application will in the end have an IMemberService, IUserService, ICustomerService, etc... So you need a decorator for each and every IXXXService, not very DRY if you ask me. If all services will implement Save(List<T> items) you could consider creating an open generic interface:
public interface IService<T>
{
void Save(List<T> items);
}
public class MemberService : IService<Member>
{
// same code as before
}
You register all implementations in one line using Batch-Registration:
container.Register(typeof(IService<>),
new[] { Assembly.GetExecutingAssembly() },
Lifestyle.Scoped);
And you can wrap all these instances into a single open generic implementation of the above mentioned ThreadScopedServiceDecorator.
It would IMO even be better to use the command / handler pattern (you should really read the link!) for this type of work. In very short: In this pattern every use case is translated to a message object (a command) which is handled by a single command handler, which can be decorated by e.g. a SaveChangesCommandHandlerDecorator and a ThreadScopedCommandHandlerDecorator and LoggingDecorator and so on.
Your example would then look like:
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
public class CreateMemberCommand
{
public string MemberName { get; set; }
}
With the following handlers:
public class CreateMemberCommandHandler : ICommandHandler<CreateMemberCommand>
{
//notice that the need for MemberRepository is zero IMO
private readonly IGenericRepository<Member> memberRepository;
public CreateMemberCommandHandler(IGenericRepository<Member> memberRepository)
{
this.memberRepository = memberRepository;
}
public void Handle(CreateMemberCommand command)
{
var member = new Member { Name = command.MemberName };
this.memberRepository.Insert(member);
}
}
public class SaveChangesCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
private ICommandHandler<TCommand> decoratee;
private DbContext db;
public SaveChangesCommandHandlerDecorator(
ICommandHandler<TCommand> decoratee, DbContext db)
{
this.decoratee = decoratee;
this.db = db;
}
public void Handle(TCommand command)
{
this.decoratee.Handle(command);
this.db.SaveChanges();
}
}
And the form can now depend on ICommandHandler<T>:
public partial class frmMember : Form
{
private readonly ICommandHandler<CreateMemberCommand> commandHandler;
public frmMember(ICommandHandler<CreateMemberCommand> commandHandler)
{
InitializeComponent();
this.commandHandler = commandHandler;
}
private void btnSave_Click(object sender, EventArgs e)
{
this.commandHandler.Handle(
new CreateMemberCommand { MemberName = txtName.Text });
}
}
This can all be registered as follows:
container.Register(typeof(IGenericRepository<>),
typeof(GenericRepository<>));
container.Register(typeof(ICommandHandler<>),
new[] { Assembly.GetExecutingAssembly() });
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(SaveChangesCommandHandlerDecorator<>));
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(ThreadScopedCommandHandlerDecorator<>),
Lifestyle.Singleton);
This design will remove the need for UnitOfWork and a (specific) service completely.
I have below code which will work without any issue
MAUserController.cs
public class MAUserController : ApiController
{
ILogService loggerService;
IMAUserService _service;
public MAUserController(ILogService loggerService, IMAUserService Service)
{
this.loggerService = loggerService;
this._service = Service;
}
}
DependencyInstaller.cs
public class DependencyInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<ILogService>().ImplementedBy<LogService>().LifeStyle.PerWebRequest,
Component.For<IDatabaseFactory>().ImplementedBy<DatabaseFactory>().LifeStyle.PerWebRequest,
Component.For<IUnitOfWork>().ImplementedBy<UnitOfWork>().LifeStyle.PerWebRequest,
AllTypes.FromThisAssembly().BasedOn<IHttpController>().LifestyleTransient(),
AllTypes.FromAssemblyNamed("ISOS.Health.Service").Where(type => type.Name.EndsWith("Service")).WithServiceAllInterfaces().LifestylePerWebRequest(),
AllTypes.FromAssemblyNamed("ISOS.Health.Repository").Where(type => type.Name.EndsWith("Repository")).WithServiceAllInterfaces().LifestylePerWebRequest()
);
}
}
If I am using normal Controller instead ApiController then it gives me an error
UserController.cs
public class UserController : Controller
{
ILogService loggerService;
IMAUserService _service;
public UserController(ILogService loggerService, IMAUserService Service)
{
this.loggerService = loggerService;
this._service = Service;
}
}
This will give an error:
No parameterless constructor defined for this object
I am using CastleDI Windsor for Dependency injection.
Do I need to do anything or register something?
FIRST APPROACH
Advice: Use with caution, because it may cause memory leaks for Castle Windsor.
You have to create a controller activator, which should implement the IControllerActivator interface, in order to use your DI container to create the controller instances:
public class MyWindsorControllerActivator : IControllerActivator
{
public MyWindsorControllerActivator(IWindsorContainer container)
{
_container = container;
}
private IWindsorContainer _container;
public IController Create(RequestContext requestContext, Type controllerType)
{
return _container.Resolve(controllerType) as IController;
}
}
Then, add this class to your DependencyInstaller:
public class DependencyInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
// Current code...
Component.For<IControllerActivator>()
.ImplementedBy<MyWindsorControllerActivator>()
.DependsOn(Dependency.OnValue("container", container))
.LifestyleSingleton();
);
}
}
Also, create your own dependency resolver based on the Windsor container:
public class MyWindsorDependencyResolver : IDependencyResolver
{
public MyWindsorDependencyResolver(IWindsorContainer container)
{
_container = container;
}
private IWindsorContainer _container;
public object GetService(Type serviceType)
{
return _container.Resolve(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.ResolveAll(serviceType).Cast<object>();
}
}
Then, finally, register your dependency resolver in the Application_Start method in Global.asax.cs:
DependencyResolver.SetResolver(new MyWindsorDependencyResolver(windsorContainer));
This way, when MVC requires the controller activator through it's dependency resolver, it will get ours, which will use our Windsor container to create the controllers with all it's dependencies.
In order to avoid memory leaks using IControllerActivator, the easiest solution will be to use lifestyles like per thread or per web request, rather than the default (Singleton), transient and pooled, for the registered components. Check this link for more info about how to avoid memory leaks using Castle Windsor Container.
SECOND APPROACH
However, as pointed out by #PhilDegenhardt, a much better and correct approach will be to implement a custom controller factory, in order to be able to release the controller component created by the Castle Windsor DI Container. Here you can find an example (see the section about Dependency Injection).
Taken from that example, the implementation could be:
Global.asax.cs:
public class MvcApplication : System.Web.HttpApplication
{
private WindsorContainer _windsorContainer;
protected void Application_Start()
{
var _windsorContainer = new WindsorContainer();
_windsorContainer.Install(
new DependencyInstaller(),
// Other installers...
);
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(_windsorContainer.Kernel));
}
protected void Application_End()
{
if (_windsorContainer != null)
{
_windsorContainer.Dispose();
}
}
}
WindsorControllerFactory.cs:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
public override void ReleaseController(IController controller)
{
_kernel.ReleaseComponent(controller); // The important part: release the component
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
}
return (IController)_kernel.Resolve(controllerType);
}
}
Look at the following project link https://github.com/rarous/Castle.Windsor.Web.Mvc
Add this reference via NuGet to your MVC project, it will do the registering job for you.
Do not forget to catch your errors in global.asax.cs!
Registration :
container.Register(Component.For<IControllerFactory>().ImplementedBy<WindsorControllerFactory>());
Implementation of MVC controller factory :
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Castle.MicroKernel;
namespace Installer.Mvc
{
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
}
if (_kernel.GetHandler(controllerType) != null)
{
return (IController)_kernel.Resolve(controllerType);
}
return base.GetControllerInstance(requestContext, controllerType);
}
public override void ReleaseController(IController controller)
{
_kernel.ReleaseComponent(controller);
}
}
}
I need to find a way to use Ninject in my classes (models) and also in my controllers of my MVC application.
How can I do to use the same bindings in both sides?
Right now I use my generated NinjectWebCommon.cs create my kernel and initialize the bootstrap:
private static void RegisterServices(IKernel kernel)
{
System.Web.Mvc.DependencyResolver.SetResolver(
new WebApplication1.Models.NinjectDependencyResolver(kernel)
);
}
My NinjectDependencyResolver looks like:
public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel k;
public NinjectDependencyResolver(IKernel kp)
{
this.k= kp;
AddBindings();
}
public object GetService(Type serviceType)
{
return k.Get(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return k.GetAll(serviceType);
}
private void AddBindings()
{
k.Bind<ISerializer>().To<MySerializer>();
}
}
MySerializer is my serialization class.
For my controllers, this part works fine.
But let's say I have the following model:
public class MyButton
{
ISerializer serializer;
public MyButton(ISerializer weapon)
{
serializer = weapon;
}
public string ToSString()
{
return serializer.serialize("my string - ");
}
}
How can I make Ninject work also for my model?
Thank you!
You may inject the model as well and add the following binding
private void AddBindings()
{
k.Bind<IMySerializer>().To<MySerializer>();
k.Bind<IModel>().To<Model>();
}
or if you are not injecting your model then you could do something like this thread says
using ninject to inject dependency to The Model classes or non-controller classes
I'm using MVC4 and Unity 2.1. My services require a service key based on credentials retrieved from session state.
I register my service(s) like so:
container.RegisterType<IInventoryService, InventoryService>();
The constructor for InventoryService is equally simple:
public InventoryService(ServiceKey serviceKey) { ... }
In my website when I've needed a service I use a service locator that automatically composes the service key using credentials from session.
public static T Resolve<T>(ServiceKey serviceKey = null)
{
if (serviceKey == null)
{
serviceKey = SessionManager.ServiceKey;
}
var parameterOverride = new ParameterOverride(SERVICEKEY_PARAMETERNAME, serviceKey);
return Resolve<T>(null, parameterOverride);
}
This has worked well. The problem is that I'm now converting my site to MVC and attempting to inject services into controllers using a simple dependency resolver that uses my exiting service locator (dependency factory):
public class CustomDependencyResolver : IDependencyResolver
{
public object GetService(Type serviceType)
{
return MvcDependencyFactory.Resolve(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return MvcDependencyFactory.ResolveAll(serviceType);
}
}
My controller looks like:
public InventoryController(IInventoryService inventoryService) { ... }
The problem is that MVC still complains about not finding a parameterless constructor when trying to instantiate the inventory controller. I think this is because I haven't registered a service key in Unity. But if I try doing so, I find that MVC is trying to resolve the controllers, and subsequently the services, before session has even been constructed.
Am I not thinking about this correctly? Each step feels pretty reasonable -- using session credentials in a service, using a service in a controller, using a resolver to help build the controller -- but I've been beating my head against the wall getting this to work.
You can use the InjectionFactory in Unity (Microsoft.Practices.Unity.InjectionFactory) to specify a function to handle the resolution of your dependency. This function will only be executed when the dependency is resolved. In the below example, "c" is your Unity container passed as a argument so that you can do additional resolves within your function.
replace:
container.RegisterType<IInventoryService, InventoryService>();
with:
container.RegisterType<IInventoryService>(new InjectionFactory(c =>
new InventoryService(SessionManager.ServiceKey)));
Using the Unity.Mvc4 package seemed to fix the problem, though it's not clear to me why. But rather than use yet another package and hide away my questions, I decided to add a parameterless constructor that manually resolves itself as necessary:
public InventoryController() : this (MvcDependencyFactory.Resolve<IInventoryService>(SessionManger.ServiceKey) { }
It still allows for unit testing of the controllers (via injection) while being transparent about where the resolution is happening when the parameterless constructor is called.
Below is a custom IDependencyResolver, which was fairly straight forward once I started to dig into how it worked and differed from IoC container resolution. You need the try/catches to capture MVC's attempted resolution of IControllerActivator (source: http://www.devtrends.co.uk/blog/do-not-implement-icontrolleractivator-in-asp.net-mvc-3). If IControllerActivator cannot be resolved, your custom IDependencyResolver will be queried for your controller instead (which will use your IoC container of choice).
I added the below class to my basic MVC4's App_Start folder:
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using Microsoft.Practices.Unity;
using Sample.Web.Controllers;
namespace Sample.Web.App_Start
{
public static class UnityConfig
{
public static void ConfigureContainer()
{
IUnityContainer container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
container.RegisterType<IHomeService>(new InjectionFactory( c =>
new HomeService("this string is a dependency.")));
container.RegisterType<IController, HomeController>("Home");
return container;
}
}
public class UnityDependencyResolver : IDependencyResolver
{
private readonly IUnityContainer _container;
public UnityDependencyResolver(IUnityContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
try
{
return _container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
}
}
Here is my simple controller:
using System.Web.Mvc;
namespace Sample.Web.Controllers
{
public class HomeController : Controller
{
private readonly IHomeService _service;
public HomeController(IHomeService service)
{
_service = service;
}
public ActionResult Index()
{
ViewBag.SomeData = _service.GetSomeData();
return View();
}
}
public interface IHomeService
{
string GetSomeData();
}
public class HomeService : IHomeService
{
private readonly string _data;
public HomeService(string data)
{
_data = data;
}
public string GetSomeData()
{
return _data;
}
}
}
Here is my epically huge view:
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>#ViewBag.SomeData</p>
I am getting started with SignalR, and it works great once everything is configured. However, almost all the applications that I work on use Castle Windsor, so it would be great to be able to use them together. The reason that I want to do this is so that I can use Castle dependencies/services inside of a persistent connection.
I dug around in the source code, and it looks like I could either replace DependencyResolver with a Castle based one (i.e., Castle implementing IDependencyResolver), or I could change the usage of DependencyResolver to Castle.
Which one of these is a better idea? Is there another approach that I could use to combine Castle and SignalR?
Thanks,
Erick
August 2016 update
Following from a comment I no longer use the approach below but now use the GlobalHost.DependencyResolver
So in Global.asax.cs I initialise things
public static void Init(IWindsorContainer container)
{
var conn = configurationManager.ConnectionStrings["SRSQL"].ConnectionString;
GlobalHost.DependencyResolver.Register(typeof(IHubActivator),
() => new SignalHubActivator(container));
GlobalHost.DependencyResolver.Register(typeof(ILoggingService),
container.Resolve<ILoggingService>);
//etc or you could just pass your existing container to the resolver
GlobalHost.DependencyResolver.UseSqlServer(conn);
}
and then in the hub
private ILoggingService LoggingService{ get; set; }
public NotificationHub()
{
LoggingService = GlobalHost.DependencyResolver.Resolve<ILoggingService>();
}
and for completeness
public class SignalHubActivator: IHubActivator
{
private readonly IWindsorContainer _container;
public SignalHubActivator(IWindsorContainer container)
{
_container = container;
}
public IHub Create(HubDescriptor descriptor)
{
var result= _container.Resolve(descriptor.HubType) as IHub;
if (result is Hub)
{
_container.Release(result);
}
return result;
}
}
OLD ANSWER from 2012
I went with the first option of setting our own DependencyResolver
AspNetHost.SetResolver(new SignalResolver(_container));
I can provide SignalResolver if desired but leaving out for readability for now.
Another important note is that the hubs must have an empty constructor so our castle container injects through properties, e.g.
public class NotificationHub : Hub, INotificationHub
{
public INotificationService NotificationService { get; set; }
and the resolver requested
public class SignalResolver : DefaultDependencyResolver
{
private readonly IWindsorContainer _container;
public SignalResolver(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
}
public override object GetService(Type serviceType)
{
return TryGet(serviceType) ?? base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
return TryGetAll(serviceType).Concat(base.GetServices(serviceType));
}
private object TryGet(Type serviceType)
{
try
{
return _container.Resolve(serviceType);
}
catch (Exception)
{
return null;
}
}
private IEnumerable<object> TryGetAll(Type serviceType)
{
try
{
var array = _container.ResolveAll(serviceType);
return array.Cast<object>().ToList();
}
catch (Exception)
{
return null;
}
}
}
Here's what I ended up doing. First I followed along with the Windsor wiki to get my ASP.NET MVC3 setup. My Global.asax.cs:
private static IWindsorContainer _container;
protected void Application_Start()
{
BootstrapContainer();
RegisterRoutes(RouteTable.Routes);
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
}
protected void Application_End()
{
_container.Dispose();
}
private static void BootstrapContainer()
{
_container = new WindsorContainer().Install(FromAssembly.This());
RouteTable.Routes.MapHubs(new CastleWindsorDependencyResolver(_container));
var controllerFactory = new WindsorControllerFactory(_container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}
...
CastleWindsorDependencyResolver came from here
Copied:
public class CastleWindsorDependencyResolver : DefaultDependencyResolver
{
private readonly IWindsorContainer _container;
public CastleWindsorDependencyResolver(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
// perform the lazy registrations
foreach (var c in _lazyRegistrations)
_container.Register(c);
_lazyRegistrations.Clear();
}
public override object GetService(Type serviceType)
{
if (_container.Kernel.HasComponent(serviceType))
return _container.Resolve(serviceType);
return base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
IEnumerable<object> objects;
if (_container.Kernel.HasComponent(serviceType))
objects = _container.ResolveAll(serviceType).Cast<object>();
else
objects = new object[] { };
var originalContainerServices = base.GetServices(serviceType);
if (originalContainerServices != null)
return objects.Concat(originalContainerServices);
return objects;
}
public override void Register(Type serviceType, Func<object> activator)
{
if (_container != null)
// cannot unregister components in windsor, so we use a trick
_container.Register(Component.For(serviceType).UsingFactoryMethod<object>(activator, true).OverridesExistingRegistration());
else
// lazy registration for when the container is up
_lazyRegistrations.Add(Component.For(serviceType).UsingFactoryMethod<object>(activator));
// register the factory method in the default container too
//base.Register(serviceType, activator);
}
// a form of laxy initialization is actually needed because the DefaultDependencyResolver starts initializing itself immediately
// while we now want to store everything inside CastleWindsor, so the actual registration step have to be postponed until the
// container is available
private List<ComponentRegistration<object>> _lazyRegistrations = new List<ComponentRegistration<object>>();
}
public static class WindsorTrickyExtensions
{
/// <summary>
/// Overrideses the existing registration:
/// to overide an existiong component registration you need to do two things:
/// 1- give it a name.
/// 2- set it as default.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="componentRegistration">The component registration.</param>
/// <returns></returns>
public static ComponentRegistration<T> OverridesExistingRegistration<T>(this ComponentRegistration<T> componentRegistration) where T : class
{
return componentRegistration
.Named(Guid.NewGuid().ToString())
.IsDefault();
}
}
I wasn't sure WTF the HubsInstaller was trying to do from that same project but I made my own which seems to work fine (I am of course open to any suggestions why this could suck):
public class HubsInstallers : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.BasedOn<IHub>()
.LifestyleTransient());
}
}
Also this is for the newer SignalR versions 0.5+
dove answer is fine but it is a bit confusing, adding another more specific answer.
My main goal is this to work:
[HubName("MyHub")]
public class MyHub : Hub
{
public IJobRepository JobRepository { get; }
public MyHub(IJobRepository jobRepository)
{
JobRepository = jobRepository ?? throw new ArgumentNullException(nameof(jobRepository));
}
...
}
Of course what you want is your Hubs to be created for you, they are usually created by SignalR but now that they have some dependencies SignalR cannot create them.
SignalR itself has a Dependency Resolver (in SignalR namespace) which uses to get its own dependencies, you can add stuff to it, but we want Windsor remember?
So we are going to change just how the IHubActivator creates hubs, we are not going to use SignalR's but this one:
public class SignalRHubActivator : IHubActivator
{
private readonly IWindsorContainer _container;
public SignalRHubActivator(IWindsorContainer container)
{
_container = container;
}
public IHub Create(HubDescriptor descriptor)
{
var result = _container.Resolve(descriptor.HubType) as IHub;
if (result is Hub)
{
_container.Release(result);
}
return result;
}
}
To replace this in SignalR container you have to do something like:
// Get an instance of the hub creator (see note below)
var _hubActivator = new SignalRHubActivator(container);
// Get the SignalR's Default Dependency Resolver
var signalRResolver = new Microsoft.AspNet.SignalR.DefaultDependencyResolver();
// Override the IHubActivator service
signalRResolver.Register(typeof(IHubActivator), () => _hubActivator);
// now map SignalR with this configuration
appBuilder.MapSignalR(new HubConfiguration { Resolver = signalRResolver });
And that's it, you should also register all your Hubs with Windsor
container.Register(Classes.FromThisAssembly()
.BasedOn(typeof(Microsoft.AspNet.SignalR.Hub)));
...
container.Register(Component.For<IJobRepository>()).ImplementedBy<JobRepository>());
Note: I registered the SignalRHubActivator as a component too, this is because the Startup class I use receives the activator as a dependency:
container.Register(Component.For<SignalRHubActivator>().
DependsOn(Dependency.OnValue("container", container)));