为 ASP.Net WebAPI 应用程序配置 ASP.Net 身份

Configuring ASP.Net Identity for an ASP.Net WebAPI application

我有一个 SPA ASP.NET WebAPI 应用程序,它以前允许匿名访问。我现在已经为它配置了 ASP.Net Identity,但是我无法让与 Identity 相关的控制器和我的应用程序的其他控制器同时工作:-( 非此即彼!

我已将启动 class 添加到我的项目中:

using Test.MyProject;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.DataHandler.Encoder;
using Microsoft.Owin.Security.OAuth;
using Newtonsoft.Json.Serialization;
using Owin;
using System;
using System.Configuration;
using System.Linq;
using System.Net.Http.Formatting;
using System.Web.Http;

[assembly: OwinStartup(typeof(Test.Client.Startup))]
namespace Test.Client
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration httpConfig = new HttpConfiguration();

            ConfigureOAuthTokenGeneration(app);

            ConfigureWebApi(httpConfig);

            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

            //app.UseWebApi(httpConfig);  // If this line is commented out my application's controllers work. But then my Account Controller does't work. It if is included, my application's controllers don't work, whilst the Account Controller work

            GlobalConfiguration.Configure(WebApiConfig.Register);
        }

        private void ConfigureOAuthTokenGeneration(IAppBuilder app)
        {
            // Configure the db context and user manager to use a single instance per request
            app.CreatePerOwinContext(ApplicationDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        }

        private void ConfigureWebApi(HttpConfiguration config)
        {
            config.MapHttpAttributeRoutes();

            var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
            jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        }
    }
}

我还添加了用于管理用户和角色的控制器。 语句 GlobalConfiguration.Configure(WebApiConfig.Register) 以前在 global.aspx.cs 的应用程序启动事件中,但现在移至启动 class 以将所有内容都放在同一个地方。

WebApiConfig.Register 方法如下所示:

public static void Register(HttpConfiguration config)
{
    var container = new UnityContainer();
    // Web API configuration and services

    string appStorageProvider = ConfigurationManager.AppSettings["StorageProvider"];
    var provider =(TestComposition.StorageProvider) Enum.Parse(typeof (TestComposition.StorageProvider), appStorageProvider, true);

    TestComposition.Setup(container, provider);
    container.RegisterType<GeneralLogger, GeneralLogger>();

    container.RegisterType<IExceptionLogger, ExceptionLogger>();

    config.EnableCors();

    config.DependencyResolver = new UnityResolver(container);
    config.Services.Add(typeof (IExceptionLogger), container.Resolve<GeneralLogger>());

    // Web API routes
    config.MapHttpAttributeRoutes();
}

在我的新 AccountController 中,我有代码允许我从启动 class 中设置的 OwinContext 中检索 ApplicationUserManager

protected ApplicationUserManager AppUserManager
{
    get
    {
        return _AppUserManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
    }
}

app.UseWebApi(httpConfig) 如上所示注释掉后,我的应用程序像以前一样工作。但是如果我对我的新 AccountController 调用任何操作,我会得到这个:

Request.GetOwinContext() error CS1061: 'HttpRequestMessage' does not contain a definition for 'GetOwinContext' and no extension method 'GetOwinContext' accepting a first argument of type 'HttpRequestMessage' could be found (are you missing a using directive or an assembly reference?)

如果我在 app.UseWebApi(httpConfig) 语句中发表评论,AccountController 可以正常工作,但我的其他控制器无法正常工作。在这里我得到这样的错误:

{ "message": "An error has occurred.", "exceptionMessage": "An error occurred when trying to create a controller of type 'TestController'. Make sure that the controller has a parameterless public constructor.", "exceptionType": "System.InvalidOperationException", "stackTrace": " at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()", "innerException": { "message": "An error has occurred.", "exceptionMessage": "Type 'MyProject.Api.TestController' does not have a default constructor", "exceptionType": "System.ArgumentException", "stackTrace": " at System.Linq.Expressions.Expression.New(Type type)\r\n at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)" } }

知道这里发生了什么吗?

问题是您在启动期间使用 OWIN 配置 WebApi 时没有使用相同的 HttpConfiguration 实例。

这样您的 OWIN Web API 中间件就不知道 UnityContainer,并将使用其默认实现。因此,您的控制器创建失败。

请对 Web Api 配置和 UnityContainer 注册使用相同的 HttpConfiguration

public class Startup {
    public void Configuration(IAppBuilder app) { 
        ConfigureOAuthTokenGeneration(app);

        ConfigureWebApi(app);

        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);            
    }

    private void ConfigureOAuthTokenGeneration(IAppBuilder app) {
        // Configure the db context and user manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
    }

    private void ConfigureWebApi(IAppBuilder app) {
        // configure Web Api
        GlobalConfiguration.Configure(WebApiConfig.Register);
        // Manually assign httpConfig from GlobalConfiguration
        HttpConfiguration httpConfig = GlobalConfiguration.Configuration;
        // Use same config with OWIN app
        app.UseWebApi(httpConfig);
    }
}

您正在多个地方配置网络 api。 WebApiConfig.Register 方法应该合并您想要为 HttpConfiguration:

配置的所有内容
public static void Register(HttpConfiguration config) {
    var container = new UnityContainer();
    // Web API configuration and services

    string appStorageProvider = ConfigurationManager.AppSettings["StorageProvider"];
    var provider =(TestComposition.StorageProvider) Enum.Parse(typeof (TestComposition.StorageProvider), appStorageProvider, true);

    TestComposition.Setup(container, provider);
    container.RegisterType<GeneralLogger, GeneralLogger>();

    container.RegisterType<IExceptionLogger, ExceptionLogger>();

    config.EnableCors();

    config.DependencyResolver = new UnityResolver(container);
    config.Services.Add(typeof (IExceptionLogger), container.Resolve<GeneralLogger>());

    // Web API routes
    config.MapHttpAttributeRoutes();

    // configure formatter
    var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
    jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}