我们有一个与Autofac DI配合使用的MVC 5.1应用程序。我已经实现了一些基本的web api功能来提取和发布有效的数据。我们现在想在web api控制器上添加身份验证。为了做到这一点,我们将使用我们写给Mvc的一些相同的Autofac配置。所以,我们打电话如:
builder.RegisterControllers(assembly).InstancePerHttpRequest();
builder.RegisterApiControllers(assembly);
builder.RegisterModelBinders(assembly).InstancePerHttpRequest();
builder.RegisterType<LogAttribute>().PropertiesAutowired();
builder.RegisterFilterProvider();
// Needed to allow property injection in custom action filters.
builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>();
if (modules != null)
{
foreach (var module in modules)
{
builder.RegisterModule(module);
}
}
我们还有一个Api模块,其中包含以下代码并已注册(我们知道因为我们已调试并看到了所调用的代码):
public class MvcModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterModule(new AutofacWebTypesModule());
builder.Register(ctx => HttpContext.Current.GetOwinContext()).As<IOwinContext>();
builder.Register(ctx => HttpContext.Current.User.Identity).As<IIdentity>().InstancePerLifetimeScope();
builder.Register(ctx => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>()).As<ApplicationUserManager>().InstancePerLifetimeScope();
builder.Register(c => BundleTable.Bundles).As<BundleCollection>().InstancePerLifetimeScope();
builder.Register(c => RouteTable.Routes).As<RouteCollection>().InstancePerLifetimeScope();
builder.RegisterType<CurrentUser>().As<ICurrentUser>().InstancePerLifetimeScope();
builder.RegisterType<ApplicationUser>().As<IApplicationUser>().InstancePerLifetimeScope();
builder.RegisterType<UserManager<ApplicationUser, Guid>>();
builder.Register(c=>new appContext()).InstancePerHttpRequest();
base.Load(builder);
}
}
public class ApiModule: Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(t => !t.IsAbstract && typeof(ApiController).IsAssignableFrom(t))
.InstancePerMatchingLifetimeScope(AutofacWebApiDependencyResolver.ApiRequestTag);
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).PropertiesAutowired();
builder.RegisterModule<AutofacWebTypesModule>();
}
}
然后我们有这两个语句应该为mvc和web api设置解析器(我认为):
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
DependencyResolver.SetResolver(new Autofac.Integration.Mvc.AutofacDependencyResolver(container));
我们有一个Mvc AccountController,看起来类似于以下内容(为清晰起见,删除了一些方法):
public class AccountController : BaseController
{
public AccountController(IOwinContext owinContext, IDataManager itemsManager)
: base(owinContext, itemsManager)
{
}
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindAsync(model.Email, model.Password);
if (user != null)
{
return await LoginCommon(user, model.RememberMe, returnUrl);
}
ModelState.AddModelError("", "Invalid username or password.");
}
// If we got this far, something failed, redisplay form
return View(model);
}
}
当应用程序启动时,用户可以登录。正如所料,IOofContext由Autofac注入控制器。换句话说,Mvc模块中的这一行正确地注册了OwinContext:
builder.Register(ctx => HttpContext.Current.GetOwinContext()).As<IOwinContext>();
如果用户以前注册过,则可以找到该用户。
在我们的Api帐户控制器中,我们会执行以下操作:
[Route("{email}")]
public async Task<HttpResponseMessage> GetUser(string email)
{
var user = await UserManager.FindByEmailAsync(email);
if (user != null)
{
return Request.CreateResponse(HttpStatusCode.OK, user);
}
return Request.CreateResponse(HttpStatusCode.NotFound);
}
但是,UserManager不起作用 - 引发异常:
System.InvalidOperationException occurred
HResult=-2146233079
Message=No owin.Environment item was found in the context.
Source=Microsoft.Owin.Host.SystemWeb
StackTrace:
at System.Web.HttpContextExtensions.GetOwinContext(HttpContext context)
at application1.UI.Infrastructure.Modules.MvcModule.<Load>b__0(IComponentContext ctx) in c:\tfs\application1\MAIN\Source\.NET\application1.UI\Infrastructure\Modules\MvcModule.cs:line 25
InnerException:
Autofac调用的模块是Mvc模块,而不是web api模块。发生此异常的行是这一行:
builder.Register(ctx => HttpContext.Current.GetOwinContext()).As<IOwinContext>();
换句话说,HttpContext对象似乎没有正确配置。但是,如前所述,它是设置的,因为它在Mvc的相同应用程序中工作。
所以问题是,如果在同一个应用程序中使用Mvc和web api,应该在哪里设置应用程序的owin配置?
我之前已经看过一些有关此主题的问题,但无济于事。
Is it possible to configure Autofac to work with ASP.NET MVC and ASP.NET Web Api
和
MVC Web API not working with Autofac Integration
在搜索此特定异常的解决方案时,我发现了一些关于缺少owin配置的讨论:
No owin.Environment item was found in the context
和
No owin.Environment item was found in the context - only on server
但是,当Owin适用于应用程序的Mvc部分时,我无法理解配置是如何丢失的。
我们正在使用VS 2013,.Net 4.5.1,Mvc 5.1和Autofac与web.api集成。
答案 0 :(得分:0)
我们在项目中做了非常相似的事情,我使用Autofac工作。我将UserManager注入UserService(目前只是一个域层类而不是实际服务),但可以从Api和MVC控制器方法成功访问UserManager。这是我如何设置,这可能会有所帮助。我没有为API和MVC创建单独的模块,只是将它们全部放在一起(顺便说一句,你的解析器设置正确)。
首先,网络模块:
public class WebModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterFilterProvider();
builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>();
builder.RegisterControllers(Assembly.GetExecutingAssembly())
.InjectActionInvoker();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// OWIN
builder.Register(c => HttpContext.Current.GetOwinContext())
.As<IOwinContext>().InstancePerLifetimeScope();
// Module chaining
builder.RegisterModule<DataModule>();
}
}
接下来,数据模块(还有其他模块,但它们不相关):
public class DataModule : Module
{
protected override void Load(ContainerBuilder builder)
{
var context = new EntityContext();
builder.RegisterInstance(context).As<IEntityContext>().SingleInstance();
builder.Register(x => new UserStore<ApplicationUser>(context))
.As<IUserStore<ApplicationUser>>().InstancePerLifetimeScope();
builder.Register(x =>
{
var userStore = x.Resolve<IUserStore<ApplicationUser>>();
var userManager = new UserManager<ApplicationUser>(userStore);
return userManager;
});
}
}
我的EntityContext
是一个IdentityDbContext<ApplicationUser>
,我也在一个界面中包装,所以我可以设置一个虚假的用户商店和类似的东西。
我能看到的唯一不同之处在于,当你注册时,你似乎没有将IdentityContext
传递给UserManager
。
答案 1 :(得分:0)
似乎我的设置没有标准。我再次从Mvc模板重新创建了项目,并添加了一个web api控制器。然后我可以按照预期通过web api登录和检索用户数据。
所以,问题已经解决,但我仍然不知道我们做了什么来打破它。