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>();
Related
The issue was noticed with the call to the extension method container.RegisterWebApiControllers(GlobalConfiguration.Configuration) on the container that's supposed to register the web api controller with the container but didn't. Please note that the web api controllers are defined in a different class library project and plugged at application start up using a custom IAssembliesResolver type.
public static class SimpleInjectorWebApiInitializer
{
public static void Initialize()
{
var container = new Container();
GlobalConfiguration.Configuration.Services.Replace(typeof(IAssembliesResolver),
new ApiAssemblyResolver());
InitializeContainer(container);
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
}
I even tried to call to get the ControllerTypes manually to see what was going on using the code below but it never triggered the GetAssemblies method neither did it return any ControllerTypes.
var controllerTypes = httpConfigServicesContainer.GetHttpControllerTypeResolver()
.GetControllerTypes(
GlobalConfiguration.Configuration.Services.GetAssembliesResolver());
I am almost pulling out all my hair as I can't seem to see what I am doing wrong. Thanks for your help in advance.
It's hard to be very specific, but here's a list of things that might be causing your controllers to not be registered:
Your ApiAssemblyResolver does not return the assembly that holds the controllers.
That assembly is a dynamic assembly (meaning that Assembly.IsDynamic returns true). Web API will skip dynamic assemblies.
The controller types are internal. Web API only uses public types.
The controller types are not classes (but structs).
Their type name does not end with "Controller"
They don't implement IHttpController.
Your IAssembliesResolver isn't registerd correctly (perhaps you are missing a binding redirect, causing your application to reference two versions of Web API). Tip: Check what for type GlobalConfiguration.Configuration.Services.GetAssembliesResolver() actually resolves.
Also try the following:
var controllerTypes = httpConfigServicesContainer.GetHttpControllerTypeResolver()
.GetControllerTypes(new ApiAssemblyResolver());
Does this result in any controllers? In that case, there is probably something miss with the call to Replace(typeof(IAssembliesResolver).
The solution lay in the order in which configuration calls were made. I moved every call for configuration involving the IOC container into the Application_Start method of Global.asax file.
Before making the call to GlobalConfiguration.Configure(WebApiConfig.Register),
I had already called
GlobalConfiguration.Configuration.Services.Replace(typeof(IAssembliesResolver), new ApiAssemblyResolver())
to replace the default assemblies resolver. I finally placed the other container web api configuration settings after every other configuration call and it started working like a charm! I.e
var apiIOCContainer = new Container();
SimpleInjectorWebApiInitializer.InitializeContainer(apiIOCContainer);
apiIOCContainer.RegisterWebApiControllers(GlobalConfiguration.Configuration);
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(apiIOCContainer);
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.
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.
The problem:
When I'm loading my application is trying to initialize the main controller many times and I would like to know why... that's making me crazy, If one of us had a similar error and want to give me trips about what I have to check, I'll be agreed!!.
MVC3 C# Using Unity as IoC
Controller:
public ValorationController(IServiceProxy serviceProxy,
IHvmService hvmService,
IFamilyGroupService familyGroupService,
IClientService clientService,
IUserService userService,
IOfficeService delegationService,
ISocietyService societyService,
IFamilyService familyService,
IArticleService articleService,
IArticleFinishedService articleFinishedService,
IOrderService orderService)
: base(serviceProxy)
{
FamilyService = familyService;
ArticleService = articleService;
HvmService = hvmService;
FamilyGroupService = familyGroupService;
ClientService = clientService;
UserService = userService;
DelegationService = delegationService;
SocietyService = societyService;
ArticleFinishedService = articleFinishedService;
OrderService = orderService;
}
Your controller will be initialized on every request that involves it.
This is normal and how IIS works.
Also good to know that every Unity Resolve will create by default a new instance. If you do not want that, you should provide a LifeTimeManager
Read Microsoft's articles about Understanding Lifetime Managers and Using Lifetime Managers.
Maybe you want to use something like this:
// Register a default (un-named) type mapping with a singleton lifetime
myContainer.RegisterType<IMyObject, MySingletonObject>(new ContainerControlledLifetimeManager());
// Following code will return a singleton instance of MySingletonObject// Container will take over lifetime management of the object
myContainer.Resolve<IMyObject>();
I did my configuration like this:
var container = new Container(x =>
{
x.For<IEngine>().Use<V6Engine>();
x.For<ICar>().Use<HondaCar>();
}
);
Then in my mvc controller action I did:
ICar car = ObjectFactory.GetInstance<ICar>();
Should I be setting up my container using Container or ObjectFactory somehow? It didn't resolve, so I tested things out in a c# console application and it worked if I did:
ICar car = container.GetInstance<ICar>();
But this only works if container is in local scope, and in a web app it isn't obviously since things are wired up in global.asax.cs
ObjectFactory is a static gateway for an instance of container. If you only ever want one instance of a container, and want a simple static way to get at it, use ObjectFactory. You must Initialize the ObjectFactory, and then retrieve your instances via ObjectFactory.
Alternatively, if you want to manage the lifetime of the container yourself, you can create an instance of Container, passing an initialization expression to the constructor. You then retrieve instances from the variable you declared to store the Container.
In your example, you are mixing the two approaches, which doesn't work.
I have got mine configured as below
global.asax
ObjectFactory.Initialize(action =>
{
action.For<ISomething>().Use<Something>;
});
Then everywhere else.
ObjectFactory.GetInstance<ISomething>();
This may not be the only way though. Also I think what you might be looking for is the
Scan(scanner =>
{
scanner.AssemblyContainingType(....);
scanner.AddAllTypesOf(....);
}