OK I think there is maybe too much information about Castle Windsor because looking for these keywords gives me examples of everything, and frankly I don't understand enough about how it works to properly troubleshoot this. I have tried quite a few permutations with little luck at this point.
I have an IUnitOfWorkFactory that I want to instantiate as a singleton. So, I install Castle Windsor, write a bit of code like so:
iocContainer = new WindsorContainer()
.Install(FromAssembly.This());
var propInjector = iocContainer.Register(
Component.For<IUnitOfWorkFactory>()
.LifestyleSingleton()
.Instance(new NHUnitOfWorkFactory())
);
propInjector.Resolve<IUnitOfWorkFactory>();
This gets called from my Application_Start method.
I have an AccountController wired up like so:
public class AccountController : SecureController
{
public IUnitOfWorkFactory UnitOfWorkFactory { get; set; }
...
...as far as I can figure, this should just "work" (although don't ask me how). But my property is always null when I try to use it.
It seems like I'm missing something silly and simple, but I have no idea what it is.
I have also tried
var propInjector = iocContainer.Register(
Component.For<IUnitOfWorkFactory>()
.ImplementedBy<NHUnitOfWorkFactory>()
.LifestyleSingleton()
);
with no success.
What am I doing wrong?
CONCLUSION
I was missing several steps here. I had built an installer and a bootstrapper per the tutorial, but I registered my services at the wrong spot... before building the controller factory. Now my bootstrapper looks like this:
iocContainer = new WindsorContainer()
.Install(FromAssembly.This());
var controllerFactory = new WindsorControllerFactory(iocContainer.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
iocContainer.Register(
Component.For<IUnitOfWorkFactory>()
.ImplementedBy<NHUnitOfWorkFactory>()
.LifestyleSingleton()
);
... and my property injections were no longer null.... now I just have to debug the other 87 problems...
Both constructor and property injection work when the root object is resolved by the container. In this case, your AccountController would be the root object that Windsor would need to create.
In order to wire this up, you should use a controller factory. Once the controller is registered and resolved by the container, everything should work as you expect.
Related
I'm trying to register a service using Prism autofac. However, I cannot seem to figure out a way to make this work. Everything I find on the internet is for older versions of prism and does not really show me how to use it now.
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<NavigationPage>();
containerRegistry.RegisterForNavigation<CashRegister>();
containerRegistry.RegisterForNavigation<HamburgerMenu>("Index");
containerRegistry.RegisterForNavigation<Inventory>();
containerRegistry.RegisterForNavigation<Navigation>();
containerRegistry.RegisterForNavigation<Start>();
containerRegistry.RegisterForNavigation<InventoryItemDetail>();
containerRegistry.RegisterForNavigation<FolderCreate>();
//containerRegistry.Register<SQLiteService>().As<ISQLiteService>();
var builder = new ContainerBuilder();
builder.RegisterType<SQLiteService>().As<ISQLiteService>();
builder.Build();
}
As you can see I tried it with the register container itself, but that did not really work since it did not recognize the .As method. Trying it with a new builder also gave me errors.
public class StartViewModel : BindableBase
{
public StartViewModel(ISQLiteService sqliteService)
{
}
}
Here I try to use the registered type.
can someone tell me what i'm doing wrong?
I found that you can use the build in builder using the GetBuilder() method but still getting an error.
The stack trace tells us, that there is a NullReferenceException thrown in the constructor of SQLiteService. Without seeing your code I'd guess that there is some mandatory constructor parameter, but Autofac is passing null.
See the Autofac documentation about how to pass parameters to your registered dependencies. Say we'll have to pass the name of the database file, we'd register SQLiteService as follows
containerRegistry.RegisterType<SQLiteService>()
.As<ISQLiteService>()
.WithParameter("databaseFile", "database.sqlite");
I am writing some integration tests. I am using Dependency Injection with Windsor Castle.
I would like to resolve the test class using an inversion of control container. I do not think that resolve all my dependencies inside the test class is the solution for my case.
I would like to do what I have done inside the web api project. I implemented IHttpControllerActivator, which is an extension point to fully control controller's life-cycle. That is, we can define how a controller is instantiated.
I would like to do the same for the tests. But I do not understand which is the interface I have to implement. Can anyone help me?
I think I just need to know which is the corresponding IHttpControllerActivator for unit test.
EDIT
I have a web api project to test. The web api project resolves all the dependencies with WindsorCastle. Now I need to test the web api. This is what I am doing:
public voi MyTest_Ok()
{
//Arrange
var myController = new MyWebApiController();
var result = await myController.DoWork();
//Asserts
}
Obviously it does not work because I am not using castle windsor to resolve the controller and so I do not resolve any dependency from web api controller to bottom.
I think I could replace this line
var myController = new MyWebApiController();
with something like this
var myController = windsorContainer.Resolve<MyWebApiController>();
But this solution I think is wrong. I think it's better to resolve dependencies as happen inside the controller:
public class MyWebApiController : ApiController()
{
public InjectedDependency dep { get; set; }
public DoWork()
{
dep.DoWork();
}
}
I can do this because I have implemented a custom IHttpControllerActivator.
Answer is: your test framework does. As I know none of the common test frameworks allows you take control over creating your test classes.
More info about this here as well:
A .NET Unit Test without a parameterless constructor, to facilitate dependency injection
NUnit provide ParameterizedTestFixture -https://github.com/nunit/docs/wiki/TestFixtureData
So in theory as a dirty workaround you would be able to inject some dependencies trough constructor by this, but it wasn't designed for this purpose.
In general you have to go for service locator.
I have problem with Simple Injector in my Web Api project. I user default AccountController generated by VS.
public AccountController(ApplicationUserManager userManager,
ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
In my configuration file I register:
var container = new Container();
// This is an extension method from the integration package.
container.RegisterWebApiFilterProvider(config);
container.RegisterWebApiControllers(config);
container.Register<IInitializeService, InitializeService>();
container.Register<IFolderRepository, FolderRepository>();
container.Register<IUserRepository, UserRepository>();
container.Register<ILogger, Logger>();
//Authentication Wrap
container.Register<IUserStore<User, Guid>, ApplicationUserStore>();
container.Register<IDataSerializer<AuthenticationTicket>, TicketSerializer>();
container.Register<ISecureDataFormat<AuthenticationTicket>,
SecureDataFormat<AuthenticationTicket>>();
container.Register<IDataProtector>(
() => new DpapiDataProtectionProvider().Create("ASP.NET Identity"));
container.Verify();
// 4. Register the container as MVC3 IDependencyResolver.
DependencyResolver.SetResolver(new SimpleInjectorWebApiDependencyResolver(container));
config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
I though that Simple Injector will be smart enough to handle all build in dependences responsible for default identity and i wont need to register them manually, but I'm getting exceptions if I wont register them.
Still getting an exception:
The constructor of type SecureDataFormat contains the parameter of type ITextEncoder with name 'encoder' that is not registered. Please ensure ITextEncoder is registered in the container, or change the constructor of SecureDataFormat.
Is there any way to handle that automatically?
I implemented a Web Api and I wrote this code.
This works for me
container.RegisterWebApiRequest<ISecureDataFormat<AuthenticationTicket>, SecureDataFormat<AuthenticationTicket>>();
container.RegisterWebApiRequest<ITextEncoder, Base64UrlTextEncoder>();
container.RegisterWebApiRequest<IDataSerializer<AuthenticationTicket>, TicketSerializer>();
container.RegisterWebApiRequest<IDataProtector>(() => new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider().Create("ASP.NET Identity"));
How is the container supposed to know which implementation of ITextEncoder you want to use in the constructor of SecureDataFormat?
You have to tell it which one to use. I think the rules basically go something like this:
if an interface is required (by a constructor) then it needs to know which implementation to use. If a concrete class is required it will automatically build an instance of that class (assuming it can resolve all the types that class needs).
As your SecureDataForms needs an interface you have to register one, otherwise its only option would be to 'guess' at which implementation you want and this could then go wrong silently if more than one implementation existed.
I just came up against this issue. I'm using ninject but you'll get the idea. Here is my binding:
kernel.Bind<ITextEncoder>().To<Base64UrlTextEncoder>();
According to the source, the only thing I ever see being used to new up an instance of SecureDataFormat is Base64UrlTextEncoder. So it seemed like a safe bet to use, but it's certainly not clear to me at first glance how to appropriately use this constructor overload.
I'm using Mvc3 and Unity.Mvc3 to build a testable and decoupled site, but I'm obviously doing something wrong.
In my Application_Start() i register a dependency:
// container is a property of the MvcApplication
// and the HierarchicalLifetimeManager should make sure that the registrations
// only last for this request (or should it?)
_container.Register<Interface, Class>(new HierarchicalLifetimeManager())
Then in the Session_Start() i try to resolve my dependency to save some data into the session:
var obj = _container.Resolve<Interface>();
At this point I get an exception saying that Unity can't resolve an interface, but I thought I registered a class for that interface???
I'm at a loss, and it's getting harder and harder to find a solution.
EDIT:
Here's my whole code, with some unnecessary parts left out:
public class MvcApplication : System.Web.HttpApplication
{
// as EDIT 2 says, this is wrong...
//private IUnityContainer _container = new UnityContainer();
protected void Application_Start()
{
// mvc stuff, routes, areas and whatnot
// create container here and it works, almost
var container = new UnityContainer();
// register dependencies
string connectionString = "String from config";
container.RegisterInstance<DbContext>(new CustomContext(connectionString), new HierarchicalLifetimeManager())
.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager())
.RegisterType(typeof(IRepository<>), typeof(Repository<>), new HierarchicalLifetimeManager());
// register controller resolver
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
// if i try to resolve repos here, it works and they all have the same context
// just like the unit of work
}
protected void Session_Start()
{
// here the container complains that it can't resolve the interface
// wrong
//var userRepo = _container.Resolve<IRepository<User>>();
// right, but still failes, because it is resolving DbContext
// instead of using the CustomContext instance
var userRepo = DependencyResolver.Current.GetService<IRepository<User>>();
// save some user data to session
}
}
public class SampleController : Controller {
// here the container tries to resolve the System.Data.Entity.DbContext
// instead of just giving the repo that instance that I registered
public SampleController(IRepository<Entity> repo) {
}
}
I'm obviously failing miserably at this Unit-of-work, dependency injection stuff, and the worst part is that I don't know why...
So please help before I start pulling my teeth out.
EDIT 2:
Partly there. If i create the container as above, it fails in the Session_Start(). If i create it in the Application_Start() as a local variable, and use the DependencyResolver, it works. How and why, beats me?
But it's still trying to resolve the DbContext instead of the CustomContext instance.
SOLUTION:
Ok, so here's the deal:
Problem 1) accessing the container in Session_Start():
As described in the EDIT 2, using a local container variable solves that, and accessing the container via the DependencyResolver works.
Problem 2) resolving the registered db context instance:
It turns out that registering an instance does not work.
This does though:
container.RegisterType<DbContext, CustomContext>(null, new HierarchicalLifetimeManager(), new InjectionConstructor(connectionString))
But I don't really feel satisfied, because I still didn't figure out why this works like this. Looks like I need to read a book or something for once in a long time.
Many thanks in advance.
The problem is you're using RegisterInstance with the HierarchecalLifetimeManager. I'm guessing you're trying to get a new instance per request, because the Unity.Mvc3 project uses that LifetimeManager to work that magic (as well as HttpModules to manage the creation and destruction of child containers).
The problem is, as a new request comes in, it will want to construct a new object, but doesn't know how to; you just registered an instance once, at the app start, and not a way to make an object. So you need to use RegisterType() for that to work.
You have two choices:
Specify the injected value using an InjectionConstructor: RegisterType<DbContext, CustomContext>(new HierarchecalLifetimeManager(), new InjectionConstructor(connectionString))
Use a factory: Container.RegisterType<DbContext>(new InjectionFactory(c => new CustomContext(connectionString)), new HierarcicalLifetimeManager()) (inspired by this)
*Note: parameter order may be wrong.
If you want a true singleton instance for your entire application, use the ContainerControlledLifetimeManager() (which is actually the default for RegisterInstance, so you don't even need to specify it). But then your DbContext will get rather huge as the site gets used.
Additionally, on your initial problem with the items not being registered in Session_Start():
ASP.NET maintains a pool of HttpApplication classes. That means if you make the Unity container a member variable, you'll have several instances which all have their own registrations. Application_Start() is called only once, and Session_Start() could be called using a different instance with no registrations. You'd need to use a static variable to solve that (which is what you ended up doing with the DependencyResolver).
Instead of accessing the container directly (it's not clear from your Q where you got the reference to the container?), why not let the MVC dependency resolver resolve it?
Set the Dependency resolver (Application_Start()):
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Resolve your interface (Session_Start()):
var obj = DependencyResolver.Current.GetService<IMyInterface>();
Im trying to seperate my Model,View and ViewModel in different assemblys and instantiate them with Castle Windsor.
I have my app.config
<components>
<component id="ViewModel.SomeViewModel" service="TEST.Business.IViewModel, TEST.Business" type="TEST.ViewModel.SomeViewModel, Test.ViewModel" />
<component id="ViewModel.SomeView" service="TEST.Business.IView, TEST.Business" type="TEST.View.SomeView, Test.View" />
</components>
and resolve it by
IoC.Configure();
var viewModel = IoC.Resolve<IViewModel>();
var view = IoC.Resolve<IView>();
view.ShowDialog();
my static IoC class
public static class IoC
{
private static IWindsorContainer container;
public static void Configure()
{
IResource resource = new ConfigResource("castle");
container = new WindsorContainer(new XmlInterpreter(resource));
}
public static TService Resolve<TService>()
{
return container.Resolve<TService>();
}
}
really simple until yet.
But i would love to do it like this:
naming have to be like this: I[someName]ViewModel and I[someName]View
and then resolve every component in my app.config thus for each pair of View and ViewModel resolve and associate them.
I guess there are many solutions for my problem but i dont know which keywords to use.
btw: I[someName]ViewModel and View are ofc IViewModels and IViews
I think you're doing it wrong.
Do not abstract your views and view models. It gives you no benefit. Therefore the problem is an architectural one, not a technical one.
Use reflection to iterate over the types in the assemblies you want to resolve. You can use Classes for registrations.
var assembly = Assembly.GetExecutingAssembly(); // Replace with the assembly you want to resolve for.
var exports = assembly.ExportedTypes;
var viewTypes = exports.Where(t => t.GetInterface(typeof(IView).FullName) != null);
foreach (var viewType in viewTypes)
{
var viewModelType = assembly.GetType(viewType.FullName.Replace("View", "ViewModel"));
var viewModel = container.Resolve(viewModelType);
var view = container.Resolve(viewType);
view.ShowDialog();
}
In your example, I can't see any dependency between IViewModel and IView so your code doesn't make sense. If the view model is injected as a parameter of the constructor it will be automatically resolved.
I would not recommend doing this technique. It is probably more complicated than it needs to be. Are you sure you really understand how to use an IoC container/Castle Windsor?
Ioc containers are great once you get used to them. In general you only want to use your container from your main/bootstrapping code of your application. To me it seems you try to make the resolve function for the container static to allow resolving compoents anywhere. This should not be required.
If you are looking for a method to bind views and view models in nice way, take a look at caliburn micro. You can combine this with most Ioc containers, including windsor
Kind regards,
Marwijn.