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...
Related
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()));
I wanted to try and use area (just trying out). I added a area foo to my project: right click on the project then add area.
That folder contains sub folders where I can add controllers, view, models etc. It also has a cs file fooAreaRegistration.cs where routing for the area is done.
using System.Web.Mvc;
namespace AreasExample.Areas.foo
{
public class fooAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "foo";
}
}
public override void RegisterArea(AreaRegistrationContext context )
{
context.MapRoute(
"foo_default",
"foo/{controller}/{action}/{id}",
new {controller = "Foo", action = "Index", id = UrlParameter.Optional }
);
}
}
}
Global.asax already has a function for registering area in app start
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
}
}
I also then created a controller Foo which already has a default Index action, after that I added a view to the action. Based on the context.MapRoute in fooAreaRegistration.cs, if I run the program and go to this link http://localhost:54421/foo/Foo shouldn't it be working?
It shows some error when I go to my area foo and controller Foo.
Error says
Server Error in '/' Application.
[A]System.Web.WebPages.Razor.Configuration.HostSection cannot be cast to
[B]System.Web.WebPages.Razor.Configuration.HostSection. Type A originates from 'System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' in the context 'Default' at location 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Web.WebPages.Razor\v4.0_1.0.0.0__31bf3856ad364e35\System.Web.WebPages.Razor.dll'. Type B originates from 'System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' in the context 'Default' at location 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Web.WebPages.Razor\v4.0_2.0.0.0__31bf3856ad364e35\System.Web.WebPages.Razor.dll'.
Is there something I'm missing? Do I need to add something?
Edit: I'm not sure if I should delete this post as I found the answer which is mentioned as answer below. But then it may be helpful for those who are following the same book(ASP.NET MVC4 in action).
Suggestions?
That was probably because I downloaded the project of the book from internet which had older version of razor, and after I created an area in that project it couldn't cast it to the latest version of razor(i'm guessing) as the warning as in visual studio says:
Warning 1 D:\Tutorial\mvc4ia-2012-06-
13\src4\Chapter13\AreasExample\Areas\foo\Views\Foo\Index.cshtml: ASP.NET runtime error:
[A]System.Web.WebPages.Razor.Configuration.HostSection cannot be cast to
[B]System.Web.WebPages.Razor.Configuration.HostSection. Type A originates from
'System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35' in the context 'Default' at location
'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Web.WebPages.Razor\v4.0_1.0.0.0__31bf385
6ad364e35\System.Web.WebPages.Razor.dll'.
Type B originates from 'System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' in the context 'Default' at location 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Web.WebPages.Razor\v4.0_2.0.0.0__31bf385
6ad364e35\System.Web.WebPages.Razor.dll'. D:\Tutorial\mvc4ia-2012-06-
13\src4\Chapter13\AreasExample\Areas\foo\Views\Foo\Index.cshtml AreasExample
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.
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.
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()));