问题描述
目前我正在试图从已永远不会正确摆在首位实现的旧版本(2.6)在升级后重新配置StructureMap在我们的应用程序。
我是新来使用DI容器,首先,和我为难以找到新的StructureMap版本查找文档。我卸载了旧的2.6版StructureMap和安装StructureMap.MVC5(因为我使用MVC5)。
我有是的AccountController的问题是什么。我已经StructureMap设置为使用参数的构造函数,但是当我的应用程序试图创建的UserManager,我得到一个出现InvalidOperationException
,不owin.Environment项目是在上下文中找到。
很显然,我需要StructureMap额外的配置,但我不知道什么/如何。我能找到这个错误一百万来源,所有的暗示在web.config中添加标签,但他们都不是DI容器具体 - 当我使用StructureMap VS让框架创建控制器我只有这个问题。
下面是相关的代码; AccountController中的那款只是股票模板代码。
AccountController.cs
私人ApplicationUserManager _userManager;
公众的AccountController()
{
}
公众的AccountController(ApplicationUserManager的UserManager)
{
的UserManager =的UserManager;
}
公共ApplicationUserManager的UserManager
{
得到
{
//这就是抛出异常
返回_userManager ??
HttpContext.GetOwinContext()GetUserManager< ApplicationUserManager>();
}
私定
{
_userManager =价值;
}
}
DefaultRegistry.cs
公共DefaultRegistry()
{
扫描(
扫描=>
{
扫描。 TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(新ControllerConvention());
});
。对于< IBasicRepository>()
。使用< EntityRepository>()
.LifecycleIs< HttpContextLifecycle>()
.Ctor<串>(的ConnectionString)
。是(ConfigurationManager.ConnectionStrings [MyContext]的ConnectionString);
。对于<的AccountController>()
。使用<的AccountController>()
.SelectConstructor(()=>新建的AccountController());
}
由于@Erik Funkenbusch指出,我是做竞争的事情。我最终作出的UserManager自动属性,去掉了参数的构造函数,并让StructureMap注入ApplicationUserManager。
公共ApplicationUserManager的UserManager {得到;私人集; }
公众的AccountController(ApplicationUserManager的UserManager)
{
的UserManager =的UserManager;
}
然后,我只是需要配置IUserStore和的DbContext的认同DefaultRegistry使用的.cs:
对于< IUserStore< ApplicationUser,INT>>()
。使用< UserStore< ApplicationUser, CustomRole,INT,CustomUserLogin,
CustomUserRole,CustomUserClaim>>()
.LifecycleIs< HttpContextLifecycle>();
。对于<的DbContext>()
。用(()=>新建ApplicationDbContext())
.LifecycleIs< HttpContextLifecycle>();
这是所有我需要做的就是StructureMap.MVC工作与身份。
我最初挂断的部分是,我没有意识到的方式StructureMap.MVC(和其他DI容器)的工作。 (请参见)。我希望它只是我的股票的AccountController它得到了由框架进行初始化(并认为这神奇的拦截对象的创建注入什么,我已经配置了工作),却没有意识到StructureMap必须初始化控制器本身为了使其构造进行注射。所以,当我遇到问题,我是A.奇怪,StructureMap有什么做与我摆在首位的AccountController(因为我没有明确的配置注射任何参数的 - 只为我的存储库中的其他控制器使用)和B我并没有考虑过改变我的股票代码,而是想着如何配置StructureMap。原来,我需要做两个。幸运的是,这是一个容易修改和我学到了一点更多关于DI容器是如何工作的。
I am currently trying to reconfigure StructureMap in our application after upgrading from an old version (2.6) that was never correctly implemented in the first place.I am new to using DI Containers to begin with, and am finding documentation for newer StructureMap versions hard to find. I uninstalled the old 2.6 version of StructureMap and installed StructureMap.MVC5 (since I am using MVC5).
What I am having issues with is the AccountController. I have StructureMap set up to use the parameterless constructor, but when my application tries to create the UserManager, I get an InvalidOperationException
, "No owin.Environment item was found in the context."
Obviously I need additional configuration for StructureMap, but I have no idea what/how. I can find a million sources for this error, all suggesting adding a tag in web.config, but none of them seem to be DI container specific - and I only have this issue when I use StructureMap vs letting the framework create the controller.
Below is the relevant code; that section of the AccountController is just stock template code.
AccountController.cs
private ApplicationUserManager _userManager;
public AccountController()
{
}
public AccountController(ApplicationUserManager userManager)
{
UserManager = userManager;
}
public ApplicationUserManager UserManager
{
get
{
// This is where the exception is thrown
return _userManager ??
HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
DefaultRegistry.cs
public DefaultRegistry()
{
Scan(
scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(new ControllerConvention());
});
For<IBasicRepository>()
.Use<EntityRepository>()
.LifecycleIs<HttpContextLifecycle>()
.Ctor<string>("ConnectionString")
.Is(ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString);
For<AccountController>()
.Use<AccountController>()
.SelectConstructor(() => new AccountController());
}
As @Erik Funkenbusch pointed out, I was doing competing things. I ended up making UserManager an auto-property, removed the parameterless constructor, and let StructureMap inject the ApplicationUserManager.
public ApplicationUserManager UserManager { get; private set; }
public AccountController(ApplicationUserManager userManager)
{
UserManager = userManager;
}
Then, I simply needed to configure the IUserStore and DbContext that Identity uses in DefaultRegistry.cs:
For<IUserStore<ApplicationUser, int>>()
.Use<UserStore<ApplicationUser, CustomRole, int, CustomUserLogin,
CustomUserRole, CustomUserClaim>>()
.LifecycleIs<HttpContextLifecycle>();
For<DbContext>()
.Use(() => new ApplicationDbContext())
.LifecycleIs<HttpContextLifecycle>();
This was all I needed to do to get StructureMap.MVC working with Identity.
Part of my initial hangup was that I didn't realize the way StructureMap.MVC (and other DI containers) worked. (See my related question.) I was expecting it to just work with my stock AccountController which got initialized by the framework (and thought it magically intercepted object creation to inject anything I had configured), not realizing that StructureMap must initialize the controllers itself in order for it to perform constructor injection. So when I ran into issues, I was A. Surprised that StructureMap had anything to do with my AccountController in the first place (since I wasn't explicitly configuring injection for any of its parameters - only for my Repository used in other controllers), and B. I wasn't thinking about changing my stock code but rather thinking about how to configure StructureMap. It turned out I needed to do both. Luckily, it was an easy modification and I learned a little more about how DI containers work.
这篇关于配置问题与StructureMap.MVC5身份工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!