StructureMap registry isn't working for generic interfaces - structuremap

public class RepositoryRegistry : Registry
{
public RepositoryRegistry()
{
Scan(x =>
{
x.Assembly("MyApp.Data");
x.TheCallingAssembly();
x.WithDefaultConventions();
x.AddAllTypesOf(typeof(ILookupRepo<>));
});
var tmp = ObjectFactory.GetInstance<ILookupRepo<User>>();
Debug.WriteLine(ObjectFactory.WhatDoIHave());
}
}
Getting this error:
{"StructureMap Exception Code: 202 No Default Instance defined for PluginFamily MyApp.Data.Repositories.Lookup.ILookupRepo`1[[MyApp.Data.Context.User, MyApp.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], TolMobile.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"}
StructureMap can't seem to resolve IAnything<T>. Is there any reason why this would stop working? I've used this in another project in the exact same way and it resolves ok. The only difference is that the version of StructureMap I am now using is newer...

This is not a StructureMap issue - no type inherits from ILookupRepo<>.
This is an open generic type, not a base type! If you want to find types closing on ILookupRepo<>, then you need to scan like this:
Scan(x =>
{
x.Assembly("MyApp.Data");
x.TheCallingAssembly();
x.WithDefaultConventions();
x.ConnectImplementationsToTypesClosing(typeof(ILookupRepo<>));
});
There's a blog post on the topic.

Related

StructureMap - Default constructor blues

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!

StructureMap, Web Api 2, and IUserStore error

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()));

Structuremap Using Profiles (version 2.6)

ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.Assembly("CloudAssembly"); // defines profile "Cloud"
scan.LookForRegistries();
});
x.Profile("Local", cfg =>
{
cfg.For<ICloudStorage>().
Use(() =>
new LocalStorage(HttpContext.Current.Server.MapPath("~")));
});
});
Then I try to set it to the "Local" profile so that ICloudStorage resolves to LocalStorage.
ObjectFactory.Container.SetDefaultsToProfile("Local");
ObjectFactory.Profile = "Local";
Then I get this exception when activating an object that depends on ICloudStorage:
StructureMap Exception Code: 202
No Default Instance defined for PluginFamily ICloudStorage, AssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Am I doing something wrong with the profiles? I looked at the output of whatDoIHave and everything looks like it is configured properly.
Here's the relevant section of "whatDoIHave":
ICloudStorage (MyLibrary.ICloudStorage) Default Instance for Profile Local Instance is created by Func<object> function: System.Func`2[StructureMap.IContext,MyLibrary.ICloudStorage]
Scoped as: Transient
Default Instance for Profile Local Instance is created by Func<object> function: System.Func`2[StructureMap.IContext,MyLibrary.ICloudStorage]
Default Instance for Profile Cloud Configured Instance of CloudProviders.CloudStorage, CloudProviders, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
I simply removed ObjectFactory.Container.SetDefaultsToProfile("Local") which I was calling directly after the Initialize method to use a config file instead...
<StructureMap DefaultProfile="Local">
</StructureMap>
And it is now working properly...

Dependency Injection from Multiple Assemblies using Structuremap

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.

Structuremap 2.6.1 bootstrapper

I'm using StructureMap 2.6.1
This is the code from Bootstrapper.cs:
ObjectFactory.Initialize(x => x.For<IFoo>().Use<Foo>());
When I run application, I get the following exception:
No Default Instance defined for
PluginFamily
IFoo,
Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null
I don't get an exception when I use this obsolete code:
ForRequestedType<IFoo>()
.TheDefault.Is.OfConcreteType<Foo>();
Can anyone tell me the latest syntax for ObjectFactory's initializer?
Thank you.
Each time you call Initialize, you're resetting the ObjectFactory. I.e. in the following scenario:
ObjectFactory.Initialize(x => x.For<IFoo>().Use<Foo>());
ObjectFactory.Initialize(x => x.For<IBaz>().Use<Baz>());
You've only actually mapped out IBaz to Baz.
You should use an ApplicationRegistry instead:
public class ApplicationRegistry : Registry
{
public ApplicationRegistry()
{
For<IFoo>().Use<Foo>();
For<IBaz>().Use<Baz>();
}
}
And use that in your Initialize method:
ObjectFactory.Initialize(x => x.AddRegistry(new ApplicationRegistry()));

Resources