Been struggling with this for quite a while now, so I'm starting to think I have created an anti-pattern. Nevertheless, here goes;
//Register self
container.Register(Component.For<IWindsorContainer>().Instance(container));
//Register all
container.Register(Component.For<IService1>().ImplementedBy<Service1>());
container.Register(Component.For<IService2>().ImplementedBy<Service2>());
//etc
IService1
{
//blabla
}
IService2 {IService1 Service1{get;}}
So IService1 and IService2 can be created without anything special.
Starting at IService3, an IProject is involved.
IProject{}
//Resolve a service that, amongst other things, relies on an IProject
IProjectGet
{
T Get<T>(IProject proj)
where T : class;
}
//Impl
ProjectGet : IProjectGet
{
IWindsorContainer _cont;
public ProjectGet(IWindsorContainer cont){_cont=cont}
public T Get<T>(IProject proj)
{
//Resolve using the main (and only) container and pass the IProject
return _cont.Resolve<T>(new {p = proj});
}
}
This does not work, only the main service is resolved with the
'p = proj' and any other dependencies the main service has, that also rely on the project,
cause an exception saying the project service was not found.
IService3
{
IService2 Service2{get;}
IProjectGet ProjectGet{get;}
IProjectLevelStuff SetActiveProject(IProject proj);
}
Service3 : IService3
{
IService2 Service2{get;private set;}
IProjectGet ProjectGet{get;private set;}
public Service3(IService2 s2, IProjectGet p)
{
ProjectGet = p;
Service2 = s2;
}
public IProjectLevelStuff SetActiveProject(IProject proj)
{
return ProjectGet.Get<IProjectLevelStuff>(proj);
}
}
ProjectLevelStuff : IProjectLevelStuff
{
IProject Project{get;private set;}
IService4 Service4 {get;private set;}
public ProjectLevelStuff(IProject p, IService4)//etc.
}
IService4
{
IService2 Service2{get;}
IService5 Service5{get;}
IService6 Service6{get;}
IProject Project{get;}
}
IService5{IProject Project{get;}}
IService6{IProject Project{get;}}
This fails because only ProjectLevelStuff gets the IProject passed to it, and since IService4 and it's dependencies also need it, an exception is thrown. Even if this did work, I don't like it, because each service with a dependency on IProject is forced to call that parameter 'p' which I want to avoid.
I just want to keep on using the services I already had but this time add the IProject instance that was passed to our generic Get method as a resolvable dependency. I have found no way to copy the container and creating a new one and then adding the main one as a child does not change anything (dependency still missing). How is this done?
Castle Windsor does have a TypeFactory built in but it essentially does the same thing as what I'm already doing and does not solve anything. The only 'solution' I found is creating a new container and registering the types all over again but this time resolve them via the main container (except for the IProject of course).. it's a maintenance nightmare in the works.
UPDATE: I added some unit tests to my answer below that hopefully clears up some things
please check if you could use the approach below using scopes:
[SetUp]
public void Setup()
{
int counter = 0;
_container = new WindsorContainer();
_container.AddFacility<TypedFactoryFacility>();
_container.Register(
Component.For<IService1>().ImplementedBy<Service1>().LifestyleScoped(),
Component.For<IService2>().ImplementedBy<Service2>().LifestyleScoped(),
Component.For<IService3>().ImplementedBy<Service3>().LifestyleScoped(),
Component.For<Class1>().LifestyleTransient(),
Component.For<Class2>().LifestyleTransient(),
Component.For<IProject>().ImplementedBy<Project>().LifestyleScoped().DynamicParameters((k, d) => d["name"] = "MyProjectName"+counter++)
);
}
[Test]
public void TestClass1()
{
using (_container.BeginScope())
{
Class1 object1 = _container.Resolve<Class1>();;
var object2 = _container.Resolve<Class1>();
Assert.AreNotSame(object1, object2);
Assert.AreSame(object1.Service1, object2.Service1);
}
}
[Test]
public void TestClass2()
{
Class2 object1;
using (_container.BeginScope())
{
object1 = _container.Resolve<Class2>();
var object2 = _container.Resolve<Class2>();
Assert.AreNotSame(object1, object2);
Assert.AreSame(object1.Project, object2.Project);
Assert.AreSame(object1.Service2.Project, object2.Service2.Project);
}
Class2 object3;
using (_container.BeginScope())
{
object3 = _container.Resolve<Class2>();
}
Assert.AreNotSame(object1.Project, object3.Project);
}
For some strange (but probably valid) reason Windsor child-containers can access their Parent containers but not the other way around. This means that in order to use services registered in the main container from the new container, we have to set the Parent of the main container rather than that of the new container.
This is painfully inconvenient because a container can only have one Parent.
internal class ProjServices : IProjServices
{
private readonly IKwProject _proj;
private readonly IWindsorContainer _mainCont;
public ProjServices(IKwProject proj, IWindsorContainer mainCont)
{
_mainCont = mainCont;
_proj = proj;
}
public T Resolve<T>()
{
T rett;
//Create new container
var projCont = new WindsorContainer();
//Register new service
projCont.Register(Component.For<IKwProject>().Instance(_proj));
//Set hierarchy
lock (_mainCont)
{
projCont.AddChildContainer(UiContainer); //ui needs project, set parent to projCont
UiContainer.AddChildContainer(_mainCont); //main needs ui, set parent to uiCont
//Resolve using main, which now has access to UI and Project services
try
{
rett = _mainCont.Resolve<T>();
}
finally
{
projCont.RemoveChildContainer(UiContainer);
UiContainer.RemoveChildContainer(_mainCont);
}
}
return rett;
}
private static readonly object UIContainerLock = new object();
private static volatile IWindsorContainer _uiContainer;
private static IWindsorContainer UiContainer
{
get
{
if(_uiContainer==null)
lock(UIContainerLock)
if (_uiContainer == null)
{
//Register the UI services
}
return _uiContainer;
}
}
}
And now if I wanted to use these new containers in even newer containers in the future I think I'd get stuck again due to the one-parent-only thing.... how do I properly do this, please?
UPDATE:
Unit Tests for VS 2010 and 2012:
ServiceTest.zip (798 KB)
https://mega.co.nz/#!z4JxUDoI!UEnt3TCoMFVg-vXKEAaJrhzjxfhcvirsW2hv1XBnZCc
Or to copy&paste:
using System;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ServiceTest
{
/// <summary>
/// A service that doesn't rely on anything else
/// </summary>
public interface IService1
{
}
class Service1 : IService1
{
}
/// <summary>
/// The Project
/// </summary>
public interface IProject
{
string Name { get; }
}
public class Project : IProject
{
public Project(string name)
{
Name = name;
}
public string Name { get; private set; }
}
/// <summary>
/// A Service that relies on a Project
/// </summary>
public interface IService2
{
IProject Project { get; }
string GetProjectName();
}
/// <summary>
/// The implementation shows it also relies on IService3
/// </summary>
public class Service2 : IService2
{
public Service2(IProject project, IService3 service3)
{
Project = project;
Service3 = service3;
}
public IProject Project { get; private set; }
public IService3 Service3 { get; private set; }
public string GetProjectName()
{
return Project.Name;
}
}
/// <summary>
/// IService3 is a Service that also relies on the Project
/// </summary>
public interface IService3
{
IProject Project { get; }
}
public class Service3 : IService3
{
public Service3(IProject project)
{
Project = project;
}
public IProject Project { get; private set; }
}
/// <summary>
/// Class1 uses the service without any dependencies so it will be easy to resolve
/// </summary>
public class Class1
{
public Class1(IService1 service1)
{
Service1 = service1;
}
public IService1 Service1 { get; private set; }
}
/// <summary>
/// Class2 also uses that service, but it also relies on a Project ánd IService2
/// which as you know also relies on the Project and IService3 which also relies on
/// the Project
/// </summary>
public class Class2
{
public Class2(IService1 service1, IProject project, IService2 service2)
{
Service1 = service1;
Project = project;
Service2 = service2;
}
public IProject Project { get; private set; }
public IService1 Service1 { get; private set; }
public IService2 Service2 { get; private set; }
}
/// <summary>
/// Set up the base services
/// </summary>
[TestClass]
public class UnitTestBase
{
protected WindsorContainer Cont;
[TestInitialize]
public void BaseSetup()
{
Cont = new WindsorContainer();
Cont.Register(Component.For<IService1>().ImplementedBy<Service1>().LifestyleTransient());
Cont.Register(Component.For<IService2>().ImplementedBy<Service2>().LifestyleTransient());
Cont.Register(Component.For<IService3>().ImplementedBy<Service3>().LifestyleTransient());
Cont.Register(Component.For<Class1>().LifestyleTransient());
Cont.Register(Component.For<Class2>().LifestyleTransient());
}
[TestMethod]
public void Class1_Resolves()
{
Cont.Resolve<Class1>();
}
}
/// <summary>
/// Set up the base unit tests
/// </summary>
[TestClass]
public class UnitTestClass2Base : UnitTestBase
{
protected void RunTest3Times(Func<string, IWindsorContainer> getContainer)
{
const string projNameBase = "MyProjectName";
Func<int, string> getProjectName = i => projNameBase + i;
for (var i = 0; i < 3; i++)
{
var pName = getProjectName(i);
GetClass2ForProject(getContainer(pName), pName);
}
}
protected void GetClass2ForProject(IWindsorContainer cont, string projName)
{
var c2 = cont.Resolve<Class2>();
Assert.IsTrue(c2.Project.Name == projName);
Assert.IsTrue(c2.Service2.Project.Name == projName);
Assert.IsTrue(c2.Service2.GetProjectName() == projName);
}
}
/// <summary>
/// This will fail on the second request because we cannot
/// overwrite the earlier registration. And iirc containers can't
/// be altered after the first resolve.
/// </summary>
[TestClass]
public class Attempt_1 : UnitTestClass2Base
{
[TestMethod]
public void Class2_Resolves_Project_Scoped_Requests()
{
RunTest3Times(s =>
{
Cont.Register(Component.For<IProject>().Instance(new Project(s)));
return Cont;
});
}
}
/// <summary>
/// It looks like we have to create a new container for every Project
/// So now the question remains; how do we get to keep using the base IService implementations
/// in the container that is scoped for the IProject?
/// </summary>
[TestClass]
public class Attempt_2 : UnitTestClass2Base
{
static IWindsorContainer CreateContainer(IProject p)
{
var ret = new WindsorContainer();
ret.Register(Component.For<IProject>().Instance(p));
return ret;
}
/// <summary>
/// This will fail because the services in the main
/// container can't access the IProject in the new container
/// </summary>
[TestMethod]
public void Class2_Resolves_Project_Scoped_Requests_1()
{
RunTest3Times(s =>
{
//Add the project container as a Child to the Main container
var projCont = CreateContainer(new Project(s));
Cont.AddChildContainer(projCont);
return Cont;
});
}
/// <summary>
/// Doing the previous approach the other way around works.
/// But now we can only resolve one thing at a time
/// </summary>
[TestMethod]
public void Class2_Resolves_Project_Scoped_Requests_2()
{
IWindsorContainer projCont = null;
//Add the Main container as a Child to the project container
// (in other words set the Parent of Main to Project)
// and then resolve using the main container.
//A container can only have one parent at a time so we can only
// resolve one scoped thing at a time.
RunTest3Times(s =>
{
if (projCont != null)
projCont.RemoveChildContainer(Cont);
projCont = CreateContainer(new Project(s));
projCont.AddChildContainer(Cont);
return Cont;
});
}
/// <summary>
/// The only way around that issue seems to be to register all project-dependent
/// services in the new container. Then re-register all original services
/// in the new container and pass the resolving on to the main container;
/// a maintenance nightmare and especially painful for named registrions.
/// </summary>
[TestMethod]
public void Class2_Resolves_Project_Scoped_Requests_3()
{
Func<IProject, IWindsorContainer> createContainer2 = p =>
{
var contNew = new WindsorContainer();
//Pass resolving of the non-dependent services on to the main container.
// this way it will respect it's lifestyle rules and not create new
// instances of services we wanted to use as a singleton etc.
contNew.Register(Component.For<IService1>().UsingFactoryMethod(() => Cont.Resolve<IService1>()).LifestyleTransient());
contNew.Register(Component.For<Class1>().UsingFactoryMethod(() => Cont.Resolve<Class1>()).LifestyleTransient());
//Register the dependent services directly in the new container so they can access the project
contNew.Register(Component.For<IService2>().ImplementedBy<Service2>().LifestyleTransient());
contNew.Register(Component.For<IService3>().ImplementedBy<Service3>().LifestyleTransient());
contNew.Register(Component.For<Class2>().LifestyleTransient());
contNew.Register(Component.For<IProject>().Instance(p));
return contNew;
};
RunTest3Times(s =>
{
var projCont = createContainer2(new Project(s));
return projCont;
});
}
}
}
Related
I'm attempting to use the latest version on Unity.Mvc but for some reason my controller never gets called. I have the following controller
public class AdminApiController : ApiController
{
private IUserRepository userRepository;
public AdminApiController(IUserRepository userRepository)
{
this.userRepository = userRepository;
}
[Route("api/AdminApi/{lastName}/{currentUserId}")]
public IEnumerable<UserDetail> GetUsers(string lastName, string currentUserId)
{
return userRepository.Search(lastName, currentUserId)
.Select(u => new UserDetail { Id = u.Id, Name = u.FirstName + " " + u.LastName });
}
}
and the latest version of Unity.Mvc appears to use a UnityWebActivator class to set up the container, i.e.,
public static class UnityWebActivator
{
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start()
{
var container = UnityConfig.GetConfiguredContainer();
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
// TODO: Uncomment if you want to use PerRequestLifetimeManager
// Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
}
/// <summary>Disposes the Unity container when the application is shut down.</summary>
public static void Shutdown()
{
var container = UnityConfig.GetConfiguredContainer();
container.Dispose();
}
}
and in my unity config I have the following
public class UnityConfig
{
#region Unity Container
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Gets the configured Unity container.
/// </summary>
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
#endregion
/// <summary>Registers the type mappings with the Unity container.</summary>
/// <param name="container">The unity container to configure.</param>
/// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to
/// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your types here
// container.RegisterType<IProductRepository, ProductRepository>();
container.RegisterType<IUserDatabase, UserDatabase>();
container.RegisterType<IUserRepository, UserRepository>();
}
}
which registers my in-memory repo, i.e.,
public class UserRepository : IUserRepository
{
IUserDatabase db;
public UserRepository(IUserDatabase db)
{
this.db = db;
}
public IEnumerable<User> Search(string lastName, string currentUserId)
{
if (Exists(currentUserId))
{
return GetByLastName(lastName);
}
return new List<User>();
}
private IEnumerable<User> GetByLastName(string lastName)
{
return db.Users.Where(u => u.LastName == lastName);
}
private bool Exists(string id)
{
return db.Users.Any(u => u.Id == id);
}
}
where
public class UserDatabase : IUserDatabase
{
private User[] users = new User[]
{
new User("1", "John", "Smith"),
new User("2", "Fred", "Smith"),
new User("3", "John", "Doe")
};
public IEnumerable<User> Users
{
get
{
return users;
}
}
}
When I start the application I can see that my types are being registered using breakpoints, but when I put a breakpoint in the constructor of AdminApiController it never gets called. Subsequently the controller is never created and I get an Internal Server error when I try to use the controller.
What am I missing with the setup to ensure AdminApiController is instantiated and being injected with objects from the container?
I have an MVC application that uses Entity Framework. I am using a repository, unit of work and unity as dependency injection.
The problem I have is that I have different authentication types, and each type I want a different class, so I decided to use the Strategy pattern
public interface IAuthStrategy
{
OperationResponse<AuthenticationMechanismDTO> GetAuthenticationMechanism(string userName);
}
public class AuthStrategy
{
readonly IAuthStrategy _authStrategy;
public AuthStrategy(IAuthStrategy authStrategy)
{
this._authStrategy = authStrategy;
}
public OperationResponse<AuthenticationMechanismDTO> GetAuthenticationMechanism(string userName)
{
return _authStrategy.GetAuthenticationMechanism(userName);
}
}
public class UserNamePasswordMechanism : IAuthStrategy
{
private IInstitutionRepository _institutionRepository;
public UserNamePasswordMechanism(IInstitutionRepository institutionRepository)
{
this._institutionRepository = institutionRepository;
}
public OperationResponse<AuthenticationMechanismDTO> GetAuthenticationMechanism(string userName)
{
throw new NotImplementedException();
}
}
My problem is that I am injecting IAuthStrategy into the controller, and it gives me an error, because instead of implementing IAuthStrategy, I am passing that to AuthStrategy constructor, as you can see that in my code.
How can I fix this error?
Here is my controller
public class EmployeeController : ApiController
{
private IAuthStrategy _auth;
public EmployeeController(IAuthStrategy auth)
{
this._employeeBL = employeeBL;
this._auth = auth;
}}
}
Here is unity config where i am registering my types
public class UnityConfig
{
#region Unity Container
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Gets the configured Unity container.
/// </summary>
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
#endregion
/// <summary>Registers the type mappings with the Unity container.</summary>
/// <param name="container">The unity container to configure.</param>
/// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to
/// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your types here
container.RegisterType<IInstitutionRepository, InstitutionRepository>();
container.RegisterType<IAuthStrategy, AuthStrategy>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
Your unit registrations and classes look a little off.
From what I can gather, this is what you really want to do.
Setup a factory that will determine at runtime which IAuthStrategy should be used:
public interface IAuthStrategyFactory
{
IAuthStrategy GetAuthStrategy();
}
public class AuthStrategyFactory : IAuthStrategyFactory
{
readonly IAuthStrategy _authStrategy;
public AuthStrategy(...)
{
//determine the concrete implementation of IAuthStrategy that you need
//This might be injected as well by passing
//in an IAuthStrategy and registering the correct one via unity at startup.
_authStrategy = SomeCallToDetermineWhichOne();
}
public IAuthStrategy GetAuthStrategy()
{
return _authStrategy;
}
}
This is your existing AuthStrategy:
public interface IAuthStrategy
{
OperationResponse<AuthenticationMechanismDTO> GetAuthenticationMechanism(string userName);
}
public class UserNamePasswordMechanism : IAuthStrategy
{
private IInstitutionRepository _institutionRepository;
public UserNamePasswordMechanism(IInstitutionRepository institutionRepository)
{
this._institutionRepository = institutionRepository;
}
public OperationResponse<AuthenticationMechanismDTO> GetAuthenticationMechanism(string userName)
{
throw new NotImplementedException();
}
}
Register the factory with unity:
container.RegisterType<IAuthStrategyFactory, AuthStrategyFactory>();
In your controller:
public class EmployeeController : ApiController
{
private IAuthStrategy _auth;
public EmployeeController(IAuthStrategyFactory authFactory)
{
this._employeeBL = employeeBL;
this._auth = authFactory.GetAuthStrategy();
}
}
Actually i missed implemented IAuthStrategyFactory on AuthStrategyFactory, once i implemented and register in unity container that worked.
Thanks
UnitOfWorkManager
public class UnitOfWorkManager : IUnitOfWorkManager
{
private bool _isDisposed;
private readonly BEMContext _context;
public UnitOfWorkManager(IBEMContext context)
{
// http://stackoverflow.com/questions/3552000/entity-framework-code-only-error-the-model-backing-the-context-has-changed-sinc
Database.SetInitializer<BEMContext>(null);
_context = context as BEMContext;
}
/// <summary>
/// Provides an instance of a unit of work. This wrapping in the manager
/// class helps keep concerns separated
/// </summary>
/// <returns></returns>
public IUnitOfWork NewUnitOfWork()
{
return new UnitOfWork(_context);
}
/// <summary>
/// Make sure there are no open sessions.
/// In the web app this will be called when the injected UnitOfWork manager
/// is disposed at the end of a request.
/// </summary>
public void Dispose()
{
if (!_isDisposed)
{
_context.Dispose();
_isDisposed = true;
}
}
}
UnitOfWork
public class UnitOfWork : IUnitOfWork
{
private readonly BEMContext _context;
private readonly IDbTransaction _transaction;
private readonly ObjectContext _objectContext;
/// <summary>
/// Constructor
/// </summary>
public UnitOfWork(BEMContext context)
{
_context = context;
// In order to make calls that are overidden in the caching ef-wrapper, we need to use
// transactions from the connection, rather than TransactionScope.
// This results in our call e.g. to commit() being intercepted
// by the wrapper so the cache can be adjusted.
// This won't work with the dbcontext because it handles the connection itself, so we must use the underlying ObjectContext.
// http://blogs.msdn.com/b/diego/archive/2012/01/26/exception-from-dbcontext-api-entityconnection-can-only-be-constructed-with-a-closed-dbconnection.aspx
_objectContext = ((IObjectContextAdapter)_context).ObjectContext;
if (_objectContext.Connection.State != ConnectionState.Open)
{
_objectContext.Connection.Open();
_transaction = _objectContext.Connection.BeginTransaction();
}
}
public void SaveChanges()
{
_context.SaveChanges();
}
public void Commit()
{
_context.SaveChanges();
_transaction.Commit();
}
public void Rollback()
{
_transaction.Rollback();
// http://blog.oneunicorn.com/2011/04/03/rejecting-changes-to-entities-in-ef-4-1/
foreach (var entry in _context.ChangeTracker.Entries())
{
switch (entry.State)
{
case EntityState.Modified:
entry.State = EntityState.Unchanged;
break;
case EntityState.Added:
entry.State = EntityState.Detached;
break;
case EntityState.Deleted:
// Note - problem with deleted entities:
// When an entity is deleted its relationships to other entities are severed.
// This includes setting FKs to null for nullable FKs or marking the FKs as conceptually null (don’t ask!)
// if the FK property is not nullable. You’ll need to reset the FK property values to
// the values that they had previously in order to re-form the relationships.
// This may include FK properties in other entities for relationships where the
// deleted entity is the principal of the relationship–e.g. has the PK
// rather than the FK. I know this is a pain–it would be great if it could be made easier in the future, but for now it is what it is.
entry.State = EntityState.Unchanged;
break;
}
}
}
public void Dispose()
{
if (_objectContext.Connection.State == ConnectionState.Open)
{
_objectContext.Connection.Close();
}
}
}
LanguageRepository
public class LanguageRepository : ILanguageRepository
{
private readonly BEMContext _context;
public LanguageRepository(IBEMContext context)
{
_context = context as BEMContext;
}
public Language Insert(Language language)
{
_context.Language.Add(language);
return language;
}
}
LocalizationService
public class LocalizationService : ILocalizationService
{
private readonly ILanguageRepository _languageRepository;
public LocalizationService(ILanguageRepository languageRepository)
{
_languageRepository = languageRepository;
}
public void CreateLanguage(Language language)
{
_languageRepository.Insert(language);
}
}
BaseController
public class BaseController : Controller
{
protected readonly IUnitOfWorkManager _unitOfWorkManager;
public BaseController(IUnitOfWorkManager unitOfWorkManager)
{
_unitOfWorkManager = unitOfWorkManager;
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
}
}
LocalizationController
public class LocalizationController : BaseController
{
private readonly ILocalizationService _localizationService;
public LocalizationController(ILocalizationService localizationService, IUnitOfWorkManager unitOfWorkManager)
: base(unitOfWorkManager)
{
_localizationService = localizationService;
}
public ActionResult AddLanguage()
{
return View();
}
[HttpPost]
public ActionResult AddLanguage(LanguageModel model)
{
try
{
if (ModelState.IsValid)
{
using (var UnitOfWork = _unitOfWorkManager.NewUnitOfWork())
{
try
{
var language = Mapper.Map<LanguageModel, Language>(model);
_localizationService.CreateLanguage(language);
UnitOfWork.Commit();
}
catch (Exception ex)
{
UnitOfWork.Rollback();
throw new Exception(ex.Message);
}
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return View(model);
}
}
I cant add language to DB. Because service and unitOfWork classes use different context. Service change the context, but UnitOfWork save changes on another context. I mean following:
context in _localizationService.CreateLanguage(language);
context in UnitOfWork
Of cource, change does not effect db(I cant add entity to db). Because there are two different DbContex. I hope, I can explain, but I dont know how can I ask this question. How Can I solve this problem.
EDIT
I use Unity.MVC4 for IOC like following
public static class Bootstrapper
{
public static IUnityContainer Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
RegisterTypes(container);
return container;
}
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IBEMContext, BEMContext>();
container.RegisterType<ILocalizationService, LocalizationService>();
container.RegisterType<ILanguageRepository, LanguageRepository>();
container.RegisterType<ILocaleResourceKeyRepository, LocaleResourceKeyRepository>();
container.RegisterType<ILocaleResourceValueRepository, LocaleResourceValueRepository>();
container.RegisterType<IUnitOfWorkManager, UnitOfWorkManager>();
}
}
Unity is creating new instances of the dependencies, which means that as both IUnitOfWorkManager and ILocalizationService are instantiated, their dependencies are instantiated separately. Find a way to share the dependency on the context; ideally only the unit of work should be really aware of it, and anything else should go through the unit of work to make changes to the context, I think.
My solution is:
/// <summary>
/// Bind the given interface in request scope
/// </summary>
public static class IOCExtensions
{
public static void BindInRequestScope<T1, T2>(this IUnityContainer container) where T2 : T1
{
container.RegisterType<T1, T2>(new HierarchicalLifetimeManager());
}
public static void BindInSingletonScope<T1, T2>(this IUnityContainer container) where T2 : T1
{
container.RegisterType<T1, T2>(new ContainerControlledLifetimeManager());
}
}
public static class Bootstrapper
{
public static IUnityContainer Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
RegisterTypes(container);
return container;
}
public static void RegisterTypes(IUnityContainer container)
{
container.BindInRequestScope<IBEMContext, BEMContext>();
container.BindInRequestScope<ILocalizationService, LocalizationService>();
container.BindInRequestScope<ILanguageRepository, LanguageRepository>();
container.BindInRequestScope<ILocaleResourceKeyRepository, LocaleResourceKeyRepository>();
container.BindInRequestScope<ILocaleResourceValueRepository, LocaleResourceValueRepository>();
container.BindInRequestScope<IUnitOfWorkManager, UnitOfWorkManager>();
}
}
I have this configuration in my project MVC4 Unity and a generic configucion for drivers.
Bootstrapper.cs
namespace MyProyect.Web
{
public static class Bootstrapper
{
public static void Initialise()
{
var container = BuildUnityContainer();
ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
container.RegisterType<MyProyect.Model.DataAccessContract.ICountryDao, MyProyect.DataAccess.CountryDao>();
container.RegisterType<MyProyect.Model.DataAccessContract.IContactDao, MyProyect.DataAccess.ContactDao>();
return container;
}
}
}
Global.asax:
protected void Application_Start()
{
...
Bootstrapper.Initialise();
...
}
GenericModelBinder.cs:
namespace MyProyect.Web.ModelBinder
{
public class GenericModelBinder : DefaultModelBinder//, IValueProvider
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var resolver = (Unity.Mvc4.UnityDependencyResolver)DependencyResolver.Current;
if (modelType == null)
{
return base.CreateModel(controllerContext, bindingContext, null);
}
return resolver.GetService(modelType);
}
}
}
Now that I need is to resolve a dependency in another project within the solution. My question is how I can do to that recognize the settings Unity in another project?. I currently I have this class but the current configuration does not bring in the MVC project.
namespace MyProyect.Model.ListData
{
public abstract class ListDataGenericResolver
{
protected T ResolverType<T>()
{
IUnityContainer container = new UnityContainer();
UnityServiceLocator locator = new UnityServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => locator);
//return unity.Resolve<T>();
return (T)container.Resolve(typeof(T));
}
}
}
this is a example how to use ListDataGenericResolver:
namespace MyProyect.Model.ListData.Types
{
public class CountryListData : ListDataGenericResolver, IGetListData
{
private readonly ICountryDao countryDao;
private string defaultValue;
public CountryListData(object defaultValue)
{
// Resolver
this.countryDao = this.ResolverType<ICountryDao>();
this.defaultValue = defaultValue == null ? string.Empty : defaultValue.ToString();
}
public IList<SelectData> GetData()
{
var data = this.countryDao.GetAllCountry(new Entity.Parameters.CountryGetAllParameters());
return data.Select(d => new SelectData
{
Value = d.CountryId.ToString(),
Text = d.Description,
Selected = this.defaultValue == d.CountryId.ToString()
}).ToList();
}
}
}
Thank you.
Here is how I do this.
In Application_Start, I create the unity container. I have a custom library that I use for all of my MVC projects that I import through NuGet, so I make the call to its configure method, then call the other project's Configure() methods. You could simply omit the custom library and add that code in here as well. All of that keeps my Application_Start nice and clean.
protected void Application_Start()
{
// Standard MVC setup
// <removed>
// Application configuration
var container = new UnityContainer();
new CompanyName.Mvc.UnityBootstrap().Configure(container);
new AppName.ProjectName1.UnityBootstrap().Configure(container);
new AppName.ProjectName2.UnityBootstrap().Configure(container);
// <removed>
}
This is the code for the custom MVC library's UnityBootstrap class
namespace CompanyName.Mvc
{
/// <summary>
/// Bootstraps <see cref="CompanyName.Mvc"/> into a Unity container.
/// </summary>
public class UnityBootstrap : IUnityBootstrap
{
/// <inheritdoc />
public IUnityContainer Configure(IUnityContainer container)
{
// Convenience registration for authentication
container.RegisterType<IPrincipal>(new InjectionFactory(c => HttpContext.Current.User));
// Integrate MVC with Unity
container.RegisterFilterProvider();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
}
}
Then, in the other projects, I have a UnityBootstrap there, that was called from Application_Start:
ProjectName1:
namespace AppName.ProjectName1
{
public class UnityBootstrap : IUnityBootstrap
{
public IUnityContainer Configure(IUnityContainer container)
{
return container.RegisterType<IDocumentRoutingConfiguration, DocumentRoutingConfiguration>();
}
}
}
ProjectName2: - and you can see in here, that this one depends on some other projects in another library and it is calling their Configure() methods to get them set up too...
namespace AppName.ProjectName2
{
public class UnityBootstrap : IUnityBootstrap
{
public IUnityContainer Configure(IUnityContainer container)
{
new CompanyName.Security.UnityBootstrap().Configure(container);
new CompanyName.Data.UnityBootstrap().Configure(container);
container.RegisterSecureServices<AuthorizationRulesEngine>(typeof(UnityBootstrap).Assembly);
return container
.RegisterType<IAuthorizationRulesEngine, AuthorizationRulesEngine>()
.RegisterType<IDateTimeFactory, DateTimeFactory>()
.RegisterType<IDirectoryInfoFactory, DirectoryInfoFactory>()
.RegisterType<IDirectoryWrapper, DirectoryWrapper>()
.RegisterType<IEmailService, EmailService>()
.RegisterType<IEntryPointService, EntryPointService>();
}
}
}
Here is the IUnityBootstrap interface that is used throughout the code above (for your reference)
/// <summary>
/// Defines a standard interface for bootstrapping an assembly into a Unity container.
/// </summary>
public interface IUnityBootstrap
{
/// <summary>
/// Registers all of the assembly's classes to their public interfaces and performs any other necessary configuration.
/// </summary>
/// <param name="container">The Unity container instance to configure.</param>
/// <returns>The same IUnityContainer object that this method was called on.</returns>
IUnityContainer Configure(IUnityContainer container);
}
I hope this helps you out.
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)));