首页 文章

Autofac无法在Web API和OWIN中拾取

提问于
浏览
0

我正在尝试通过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区域配置如下所示 . (旁注:我知道这不是"proper"配置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();

    }
}

1 回答

  • 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 . 此冲突直接与依赖性解析程序尝试创建控制器实例时引发的异常有关(异常消息可能会产生误导) .

    可能会发生什么:

    首先执行

    • MVC,并尝试映射您的路径 api/authentication/login . 此URI与 AreaRegistration 匹配,因此它会尝试将请求路由到 Api 区域内的 AuthenticationController .

    • MVC要求Dependency Resolver创建上述控制器的实例,该实例必须从 Controller 继承(这是因为我们在MVC上下文中) .

    • 解析器没有注册名为 AuthenticationController 的MVC控制器( AuthenticationController 继承自 ApiController ),并且它返回null(因为这是 IServiceProvider.GetService 方法的预期行为) .

    • MVC然后恢复为其创建控制器的默认实现,但发现 AuthenticationController 类没有无参数构造函数 . 抛出异常 .

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

    参考:
    ASP.Net WebAPI area support

相关问题