I have just started experimenting with Web Api 2 and StructureMap, having installed StructureMap.MVC4 Nuget package. Everything seems to work fine until I tried to register a user. I got this error when this implementation of IHttpControllerActivator tried to instantiate a controller:
public class ServiceActivator : IHttpControllerActivator
{
public ServiceActivator(HttpConfiguration configuration) { }
public IHttpController Create(HttpRequestMessage request
, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var controller = ObjectFactory.GetInstance(controllerType) as IHttpController;
return controller;
}
}
The error I got was:
StructureMap Exception Code: 202
No Default Instance defined for PluginFamily Microsoft.AspNet.Identity.IUserStore`1[[Microsoft.AspNet.Identity.EntityFramework.IdentityUser, Microsoft.AspNet.Identity.EntityFramework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], Microsoft.AspNet.Identity.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
I understand what the error is, but not entirely sure how to solve it. Is it correct to assume the default scanner in StructureMap could not find a default implementation of IUserStore? Here's the initialisation code I used:
ObjectFactory.Initialize(x => x.Scan(scan =>
{
scan.AssembliesFromApplicationBaseDirectory();
scan.WithDefaultConventions();
}));
Any ideas please? Thanks.
EDIT:
I think I may have solved the initial issue using this:
x.For<Microsoft.AspNet.Identity.IUserStore<IdentityUser>>()
.Use<UserStore<IdentityUser>>();
But now there's another default instance StructureMap couldn't work out - the dbcontext. Here's the next error message I'm getting:
ExceptionMessage=StructureMap Exception Code: 202
No Default Instance defined for PluginFamily System.Data.Entity.DbContext, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Now I'm really lost...
The WithDefaultConventions() call won't pick up your DbContext and AspNet Identity implementations. You'll want to look at some of the other methods like SingleImplementationsOfInterface() and ConnectImplementationsToTypesClosing.
By default when I setup my StructureMap container, I will do the following configuration in order to ensure that StructureMap will always resolve the interfaces and base classes of my preferred class to my actual preferred class:
ioc.For<MyDbContext>().HybridHttpOrThreadLocalScoped().Use<MyDbContext>();
ioc.For<DbContext>().HybridHttpOrThreadLocalScoped().Use<MyDbContext>();
For the new AspNet Identity classes, just subclass the generic classes they give you out of the box:
public class MyUserManager : UserManager<MyUser> { }
public class MyUserStore : UserStore<MyUser> { }
And then again, make sure StructureMap knows about these:
ioc.For<IUserStore<MyUser>>().Use<MyUserStore>();
ioc.For<UserStore<MyUser>>().Use<MyUserStore>();
ioc.For<UserManager<MyUser>>().Use<MyUserManager>();
Generally, you don't have to explicitly register every class with StructureMap, but with my DbContext and Identity classes, I prefer to have those explicity registered for maintenance purposes.
ericb: I can see the purpose of what you've posted but I can't quite get it to work. The MyUserManager class declaration "public class MyUserManager : UserManager { }" is complaining that the UserManager interface does not contain a constructor that takes 0 arguments?
Any help would be greatly appreciated!
Ps. This is by no means an answer but I'm not qualified enough to simply comment on your answer unfortunately!
Update: Found a solution here: Dependency Injection Structuremap ASP.NET Identity MVC 5
For clarity we replaced any of the above with the following in the IoC file:
x.For<Microsoft.AspNet.Identity.IUserStore<ApplicationUser>>()
.Use<Microsoft.AspNet.Identity.EntityFramework.UserStore<ApplicationUser>>();
x.For<System.Data.Entity.DbContext>().Use(() => new ApplicationDbContext());
I'm sure we're missing out on some extra benefits that ericb gets with his solution but we're not utilising anything that would take advantage of them.
There is a quick and easy workaround to this problem as well, and in many cases may be sufficient. Go to AccountController.cs and above the default constructor (the one with no params or code in it) add [DefaultConstructor] and resolve using structuremap.
[DefaultConstructor]
public AccountController()
{
}
Though the proper IoC solution is this...
For<IUserStore<ApplicationUser>>().Use<UserStore<ApplicationUser>>();
For<DbContext>().Use<ApplicationDbContext>(new ApplicationDbContext());
For<IAuthenticationManager>().Use(() => HttpContext.Current.GetOwinContext().Authentication);
Or you can try constructor injection method:
x.For<IUserStore<ApplicationUser>>().Use<UserStore<ApplicationUser>>()
.SelectConstructor(() => new UserStore<ApplicationUser>(new MyContext()));
Related
Short question. Exists some diference between registry.AddType(pluginType, type); and registry.For(pluginType).Use(type); ?
Code:
public class BasicConvention : ConfigurableRegistrationConvention
{
public override void Process(Type type, Registry registry)
{
if (something)
registry.For(pluginType).Use(type).Singleton();
}
}
}
and
public class BasicConvention : ConfigurableRegistrationConvention
{
public override void Process(Type type, Registry registry)
{
if (something)
registry.AddType(pluginType, type);
}
}
}
Using WhatDoIHave() I can see the same:
Using AddType:
===============================================================================================================================================================================================================================================================================
PluginType Namespace Lifecycle Description Name
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ISession Paf.Application.Session Transient Paf.Application.Session ('Paf.Application.Session, Paf.Modules.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null') Paf.Application.Session,... (Default)
===============================================================================================================================================================================================================================================================================
Using For().Use():
===============================================================================================================================================================================================================================================================================
PluginType Namespace Lifecycle Description Name
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ISession Paf.Application.Session Singleton Paf.Application.Session (Default)
===============================================================================================================================================================================================================================================================================
The only difference is in the description ...
Somebody?
The call to registry.AddType(pluginType, type) is basically shorthand for chaining together For and Use as in registry.For(pluginType).Use(type).
Calling registry.AddType(pluginType, type) causes a direct call to Registry.alter.set with the plugin type and the concrete type specified together.
Calling registry.For(pluginType).Use(type) chains together For and Use. The call to For returns a new GenericFamilyExpression (the constructor calls Registry.alter.set for the interface type), and the call to Use ends up calling Registry.alter.set to make the concrete type the default for the plugin family.
See the source code for Registry.cs and GenericFamilyExpression.cs, and other classes in the StructureMap source.
The accepted answer is not entirely correct. They are not the same. Which is surprisingly is indicated at the end of an answer. Use will set default instance for plugin (type) and AddType will not. So you will not be able to use Structure map as service locator with AddType. You can have this error No default Instance is registered and cannot be automatically determined for type <type>
I want to create instance of PerRequestResourceProvider using ninject InRequestScope:
public class PerRequestResourceProvider: IPerRequestResourceProvider
{
priavte readonly _perRequestResorceInstance;
public PerRequestResourceProvider()
{
_perRequestResorceInstance = new PerRequestResource();
}
public PerRequestResource GetResource()
{
return _perRequestResorceInstance;
}
}
public interface IPerRequestResourceProvider
{
PerRequestResource GetResource();
}
In my NinjectDependencyResolver:
.....
kernel.Bind<IPerRequestResourceProvider>.To<PerRequestResourceProvider>().InRequestScope();
I inject IPerRequestResourceProvider in few classes. But when I add breakpoint to PerRequestResourceProvider constructor I see that PerRequestResourceProvider is created three times during one request and not single per request. What's wrong?
Update: source code ttps://bitbucket.org/maximtkachenko/ninjectinrequestscope/src
There are two issues with your code:
Ninject is not getting initialized correctly.
You need one of the Ninject.MVCx packages (according to the MVC version you are using). To configure it correctly, see: http://github.com/ninject/ninject.web.mvc
You are injecting PerRequestResourceProvider (the class type), and not IPerRequestResourceProvider (the interface type) into HomeController, thus the .InRequestScope() defined on the IPerRequestResourceProvider binding is not taking any effect. Change the HomeController constructor to get the inteface type injected and you're good.
Ninject does not require bindings for instantiatable (non-abstract,..) classes. This is why it is not obvious when the wrong binding is used.
I'm going crazy so I got this
public class FrameworkDbTestBase : IDisposable
{
protected readonly FrameworkDb Db;
public FrameworkDbTestBase()
{
var connection = Effort.DbConnectionFactory.CreateTransient();
Db = new FrameworkDb(connection);
}
public void Dispose()
{
Db.Dispose();
}
}
This is mocking the ef6 with effort .. love it so I can continuously perform tests in the background while all the changes are happening against my codebase ... its great but unfortunately I need to this
public partial class FrameworkDb : DbContext
{
public FrameworkDb() : base("DefaultConnection"){}
public FrameworkDb(DbConnection connection): base(connection, true)
{
Configuration.LazyLoadingEnabled = false;
}
public DbSet<Site> Sites { get; set; }
...
in order to get the mocking of ef6 with effort going however structuremap insists on creating me a FrameworkDb instance with the long constructor the one with the DbConnection injection parameter so I get this:
StructureMap.StructureMapException was unhandled by user code
HResult=-2146232832
Message=StructureMap Exception Code: 202
No Default Instance defined for PluginFamily System.Data.Common.DbConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Source=StructureMap
ErrorCode=202
Sigh! I roll my eyes up ... I want structuremap to use me the other shorter constructor so after some digging according to this post: Structure Map - I dont want to use the greediest constructor! I should change this:
For<FrameworkDb>().Use <FrameworkDb>();
to this
For<FrameworkDb>().Use(() => new FrameworkDb());
No such luck still same error ... and I dont want to remove the connection constructor else my integration test wont work anymore... So maybe it uses the connection only the construct the mapping and not actually use it in the injection itself ... no such luck ... adding this:
For<DbConnection>().Use(() => new EntityConnection("DefaultConnection"));
gives me that:
StructureMap.StructureMapException was unhandled by user code
HResult=-2146232832
Message=StructureMap Exception Code: 207
Internal exception while creating Instance '00fbcc4f-c5f0-4eb3-b814-9d0ba1bb8e19' of PluginType System.Data.Common.DbConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089. Check the inner exception for more details.
Source=StructureMap
ErrorCode=207
Well so much for that theory... ahum... solution anyone? Hellooo anyone? Sigh ...
Come on people no one? The answer is so simple ... well
var framework = new Framework();
For<FrameworkDb>().Use(() => framework);
So simple yet so elegant and something you just have to know!
I have following;
interface IRepository
--interface IRepositoryEF: IRepository
--interface IRepositoryNH: IRepository
----interface ICategoryRepositoryEF: IRepositoryEF
----interface ICategoryRepositoryNH: IRepositoryNH
I want to use CategoryRepositoryEF and CategoryRepositoryNH classes in the service. How can I inject them into CategoryService?
CategoryService(IRepository repository)
{
}
What is the best practice about this? Could I use a RepositoryFactory and inject it into service and then create repositories in the services?
I mean something like following;
CategoryService(CategoryRepositoryFactory factory)
{
var CategoryRepositoryEF = factory.Create("EF");
var CategoryRepositoryNH = factory.Create("NH");
}
Is this good idea? Or I m completely wrong?
The idea is a bit off.
the purpose of repository interfaces is to abstract away the data source. the goal is to allow all using classes to fetch information without knowing where the data comes from. But in your case you force the classes to know wether NHibernate or EntityFramework is used. Why?
I also wouldn't have a IRepository interface, as you create specific interfaces.
Now the question is rather "How do I map a nhibernate or entity framework repository to one of my interfaces".
That should be done when the application starts. You typically do something like this:
container.Register<ICategoryRepostitory, NHCategoryRepository>();
container.Register<IUserRepostitory, EFUserRepository>();
If you don't do that you have effectivly coupled the using code with a specific implementation. There is really no need for any interfaces at all then.
Update
Which repository is used if I inject like CategoryService(ICategoryRepository repository)?
The repository that you registered in your inversion of control container. My point is that you should not register both implementations but just one of them for every repository.
A simple example would be below.
First manage the repository type with your web.config:
<configuration>
<appSettings>
<add key="RepositoryType" value="NHibernate" />
</appSettings>
</configuration>
And then do this when you configure your inversion of control container:
if (ConfigurationManager.AppSettings["RepositoryType"] == "NHibernate"))
{
_autofac.RegisterType<NHCategoryRepository>.As<ICategoryRepository>();
_autofac.RegisterType<NHUserRepository>.As<IUserRepository>();
}
else
{
_autofac.RegisterType<EFCategoryRepository>.As<ICategoryRepository>();
_autofac.RegisterType<EFUserRepository>.As<IUserRepository>();
}
You could use a dependency injector as Ninject and inject parameter trough contructor
Your NinjectModule
public class NinjectModule : NinjectModule
{
public override void Load()
{
this.Bind<ICategoryRepositoryEF>().To<CategoryRepositoryEF>();
this.Bind<ICategoryRepositoryNH >().To<CategoryRepositoryNH>();
this.Bind<ICategoryService >().To<CategoryService>();
}
}
Inject dependencies
var kernel = new StandardKernel(new NinjectModule());
var categoryService = kernel.Get<ICategoryService>();
This is just an example but take into account that dependencies should be injected on the composition root (entry point) of the application.
I am new to DI concept and new to structuremap. I am trying to full fill a scenario where all my interfaces are in AssemblyA and all my implementations are in AssemblyB. I want to use Structuremap to inject instance of AssemblyB class in constructor which has dependency on interface from AssemblyA
public class Customer(ICustomerService)
{
}
ICustomerService is in AssemblyA and CustomerService class is in assemblyB. I want Structuremap to inject CustomerService instance in this constructor. I am assuming that if the name of class is same as the name of interface prefixed with and I. Structuremap will recognize it automatically.
I have written the following configuration.
x =>
{
x.Scan(scan =>
{
scan.Assembly("AssemblyA");
scan.Assembly("AssemblyB");
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
but it gives me error
StructureMap Exception Code: 202
No Default Instance defined for PluginFamily AssemblyA.ICustomerService, AssemblyA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
I want to use the default conventions and avoid registering each interface to a class.
Ok, I got it to work but I am even more confused now.
This code seems to work
IContainer container = new Container(c =>
{
c.Scan(x =>
{
x.Assembly("AssemblyA");
x.Assembly("AssemblyB");
x.IncludeNamespace("AssemblyA");
x.TheCallingAssembly();
x.WithDefaultConventions();
});
});
Here I have simple added x.IncludeNamespace("AssemblyA"); after the AssemblyB scan thinking that it needs this namespace and it has started working.
My problem is solved but I don't know what was wrong or if this is the right way to go. Any help will still be greatly appreciated.