【问题标题】:Autofac failing to pickup in Web API and OWINAutofac 无法在 Web API 和 OWIN 中获取
【发布时间】:2016-05-12 17:24:31
【问题描述】:

我正在尝试通过 OWIN 设置一个同时使用 MVC 和 Web API 的项目,但我无法让 Autofac 生效。

这是我初始化 Web API 的方式:

public partial class Startup
{
    public static void ConfigureWebApi(IAppBuilder app)
    {
        var config = BuildHttpConfiguration();

        var container = AutoFacConfig.BuildContainer();
        config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

        app.UseAutofacMiddleware(container);
        app.UseAutofacWebApi(config);
        app.UseWebApi(config);
    }

    private static HttpConfiguration BuildHttpConfiguration()
    {
        var config = new HttpConfiguration();

        // Response formatter config
        config.Formatters.Remove(
            GlobalConfiguration.Configuration.Formatters.XmlFormatter);
        config.Formatters.JsonFormatter.SerializerSettings.ContractResolver =
            new CamelCasePropertyNamesContractResolver();

        // Setup Web API error reporting
        var customErrors = (CustomErrorsSection)ConfigurationManager.GetSection("system.web/customErrors");

        IncludeErrorDetailPolicy errorDetailPolicy;

        switch (customErrors.Mode)
        {
            case CustomErrorsMode.RemoteOnly:
                errorDetailPolicy
                    = IncludeErrorDetailPolicy.LocalOnly;
                break;
            case CustomErrorsMode.On:
                errorDetailPolicy
                    = IncludeErrorDetailPolicy.Never;
                break;
            case CustomErrorsMode.Off:
                errorDetailPolicy
                    = IncludeErrorDetailPolicy.Always;
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }

        config.IncludeErrorDetailPolicy = errorDetailPolicy;

        config.MapHttpAttributeRoutes();

        SwaggerConfig.ConfigureSwagger(config);

        return config;
    }
}

BuildContainer() 方法如下所示。此方法用于为 MVC 和 Web API 构建容器:

public static IContainer BuildContainer()
{
    var builder = new ContainerBuilder();

    // Register your MVC controllers.
    builder.RegisterControllers(typeof(MvcApplication).Assembly)
        .PropertiesAutowired();

    builder.RegisterApiControllers(typeof(MvcApplication).Assembly);

    // OPTIONAL: Register model binders that require DI.
    builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
    builder.RegisterModelBinderProvider();

    // OPTIONAL: Register web abstractions like HttpContextBase.
    builder.RegisterModule<AutofacWebTypesModule>();

    // OPTIONAL: Enable property injection in view pages.
    builder.RegisterSource(new ViewRegistrationSource());

    // OPTIONAL: Enable property injection into action filters.
    builder.RegisterFilterProvider();

    // Bind the core types
    Core.Infrastructure.AutoFacConfig.BuildContainer(builder);

    builder.RegisterType<Postal.EmailService>().As<Postal.IEmailService>();

    // Effectively auto-wires the anything with an interface within Web assembly infrastructure folder
    builder.RegisterAssemblyTypes(typeof(IJwtHelper).Assembly)
        .Where(t => t.Namespace != null && t.Namespace.StartsWith("MyApp.Web.Infrastructure") && t.GetInterfaces().Any())
        .AsImplementedInterfaces()
        .InstancePerLifetimeScope();

    // Set the dependency resolver to be Autofac.
    return builder.Build();
}

我在某个区域设置了 Web API 控制器,并且所有东西都可以使用标准 MVC 控制器。我想在合适的地方使用 Web API 控制器,但每次我尝试基于 ApiController 请求控制器时,我都会收到错误消息:

An error occurred when trying to create a controller of type 'XxxController'. Make sure that the controller has a parameterless public constructor.

-- 编辑--

API 区域配置如下所示。 (旁注:我知道这不是配置 Web API 的“正确”方式。我包括 {action} 因为我觉得控制器文件太多。)

public class ApiAreaRegistration : AreaRegistration
{
    public override string AreaName
    {
        get { return "Api"; }
    }

    public override void RegisterArea(AreaRegistrationContext context)
    {
        context.Routes.MapHttpRoute(
            "Api_default",
            "Api/{controller}/{action}/{id}",
            new { action = "Index", id = UrlParameter.Optional }
        );

    }

}

身份验证控制器如下所示:

public class AuthenticationController : MyAppApiJwtController
{
    private readonly IUserRepository _userRepository;
    private readonly IAppSettingsHelper _appSettingsHelper;
    private readonly IJwtHelper _jwtHelper;
    private readonly IDeviceRepository _deviceRepository;
    private readonly IINLDataService _inlDataService;

    public AuthenticationController(IUserRepository userRepository, IAppSettingsHelper appSettingsHelper, IJwtHelper jwtHelper, IDeviceRepository deviceRepository, IINLDataService inlDataService)
    {
        _userRepository = userRepository;
        _appSettingsHelper = appSettingsHelper;
        _jwtHelper = jwtHelper;
        _deviceRepository = deviceRepository;
        _inlDataService = inlDataService;
    }

    [HttpPost]
    [AllowAnonymous]
    public LoginResponseModel Login(LoginModel model)
    {
        ...
    }
}

MyAppApiJwtController 看起来像这样:

public class MyAppApiJwtController : ApiController
{
    internal IAuthenticationManager AuthenticationManager
    {
        get { return Request.GetOwinContext().Authentication; }
    }

    private JwtUserIdentity _currentJwtUser;
    public JwtUserIdentity CurrentJwtUser
    {
        get
        {
            if (_currentJwtUser != null)
                return _currentJwtUser;

            if (User == null)
                return null;

            _currentJwtUser = new JwtUserIdentity((ClaimsIdentity)User.Identity);

            return _currentJwtUser;
        }

    }
}

-- 编辑2--

我尝试使用的 URL 是 http://localhost:20630/api/authentication/login

-- 编辑 3--

MVC 配置如下所示。这是在 Web API 配置之前调用的:

public partial class Startup
{
    public static void ConfigureMvc()
    {
        AreaRegistration.RegisterAllAreas();

        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

        MvcConfig.RegisterRoutes(RouteTable.Routes);

        MvcConfig.ValueConfig();

        BundleConfig.RegisterBundles(BundleTable.Bundles);

        AutomapperConfig.Configure();
        JsonConfig.Configure();

        AutoFacConfig.ConfigureContainer();

    }
}

【问题讨论】:

  • 什么版本的MVC?因为 OWIN 和 MVC 相处得不好。适用于 Web API,但已知会导致路由问题
  • 虽然 MVC 方面似乎工作得很好
  • 好的。凉爽的。太好了。
  • 显示控制器和路由配置。我看到您在设置中使用了属性路由。什么路径给出了错误
  • 你去。我正在覆盖 ApiController 类,尽管我怀疑这是问题所在。我在 MVC 方面做类似的事情没有问题

标签: asp.net-mvc asp.net-web-api2 owin autofac


【解决方案1】:

ASP.NET Web API 默认不支持 MVC 区域。
这段代码:

public class ApiAreaRegistration : AreaRegistration
{
    public override string AreaName
    {
        get { return "Api"; }
    }

    public override void RegisterArea(AreaRegistrationContext context)
    {
        context.Routes.MapHttpRoute(
            "Api_default",
            "Api/{controller}/{action}/{id}",
            new { action = "Index", id = UrlParameter.Optional }
        );
    }
}

将指示框架将任何以Api 开头的路由映射到 MVC 控制器,但同时,此类控制器仅适用于 Web API。此冲突与 Dependency Resolver 尝试创建控制器实例时引发的异常直接相关(异常消息可能具有误导性)。

会发生什么:

  1. 首先执行MVC,并尝试映射您的路线api/authentication/login。此 URI 与您的 AreaRegistration 匹配,因此它会尝试将请求路由到您的 Api 区域内的 AuthenticationController
  2. MVC 要求 Dependency Resolver 创建上述控制器的实例,该实例必须继承自 Controller(这是因为我们处于 MVC 上下文中)。
  3. 解析器没有注册名为 AuthenticationController 的 MVC 控制器(AuthenticationController 继承自 ApiController),它返回 null(因为这是 IServiceProvider.GetService 方法的预期行为)。
  4. 然后,MVC 恢复为创建控制器的默认实现,但发现AuthenticationController 类没有无参数构造函数。抛出异常。

请尝试删除此区域声明:它没有用(在控制器/操作的 RoutePrefixRoute 属性中添加 api 前缀)并且仅适用于 MVC,而您将 Web API 定义为OWIN 中间件。

参考:
ASP.Net WebAPI area support

【讨论】:

  • 感谢弗雷德里科。我将尝试简单地删除我的区域声明,看看是否能解决我的问题。我只是还不能切换回项目的那一部分。我会告诉你进展如何
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-08
  • 1970-01-01
  • 2019-11-23
  • 1970-01-01
  • 1970-01-01
  • 2014-12-18
相关资源
最近更新 更多