MVC Web API 中的 Owin 给出 CancelationToken 异常

Owin in MVC Web API giving CancelationToken exception

环境:.NET 4.6.1,ASP.NET MVC 2,Microsoft.Owin

申请情况

代码库

启动

    public void Configuration(IAppBuilder app)
    {
        OAuthConfig oAuthConfig = new OAuthConfig(app, AppConfiguration);
        oAuthConfig.ConfigureOAuthTokenGeneration();
        oAuthConfig.ConfigureOAuthTokenConsumption();

        WebApiConfig.Register(AppConfiguration);
        app.UseWebApi(AppConfiguration);

        // No further configuration is now allowed. 
        AppConfiguration.EnsureInitialized();
    }

OAuthConfig

    public OAuthConfig(IAppBuilder app, HttpConfiguration HttpConfiguration)
    {
        this.app = app;
        if (OAuthConfig.HttpConfiguration == null)
            OAuthConfig.HttpConfiguration = HttpConfiguration;

        this.app.Use(async (ctx, next) =>
        {
            try
            {
                await next();
            }
            catch (OperationCanceledException)
            {
                // Eat this exception
            }
        });
    }

    public void ConfigureOAuthTokenGeneration()
    {
        var userStore = HttpConfiguration.DependencyResolver.GetService(typeof(IUserStore<ExtendedUser, string>)) as IUserStore<ExtendedUser, string>;
        UserService.UserStore = userStore;
        this.app.CreatePerOwinContext<UserService>(UserService.Create);
        this.app.CreatePerOwinContext<SignInService>(SignInService.Create);

        var issuer = ConfigurationManager.AppSettings["as:IssuerServer"];
        var tokenEndpoint = ConfigurationManager.AppSettings["as:OwinTokenEndpoint"];    // "/oauth/token"
        OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions()
        {
            ////For Dev enviroment only (on production should be AllowInsecureHttp = false)
            AllowInsecureHttp = true,
            TokenEndpointPath = new Microsoft.Owin.PathString(tokenEndpoint),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = new CustomOAuthProvider(),
            AccessTokenFormat = new CustomJwtFormat(issuer)
        };

        // OAuth 2.0 Bearer Access Token Generation
        this.app.UseOAuthAuthorizationServer(oAuthServerOptions);
    }

    public void ConfigureOAuthTokenConsumption()  {
        string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
        var issuer = ConfigurationManager.AppSettings["as:IssuerServer"]; // Should have the Url of the auth server http://localhost:53025/";
        byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["as:AudienceSecret"]);
        this.app.UseJwtBearerAuthentication(
            new JwtBearerAuthenticationOptions
            {
                AuthenticationMode = AuthenticationMode.Active,
                AllowedAudiences = new[] { audienceId },
                IssuerSecurityKeyProviders = new IIssuerSecurityKeyProvider[]
                {
                    new SymmetricKeyIssuerSecurityKeyProvider(issuer, audienceSecret)
                }
            });
    }

CancelledTaskHandler

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

        // Try to suppress response content when the cancellation token has fired; 
        //    ASP.NET will log to the Application event log if there's content in this case.
        if (cancellationToken.IsCancellationRequested)
        {
            return new HttpResponseMessage(HttpStatusCode.InternalServerError);
        }

        return response;
    }

WebApiConfig

    public static void Register(HttpConfiguration config)
    {
    // routes and other config
        // Handle CancellationToken which sometimes causes the app to hang due to orphaned responses
        config.MessageHandlers.Add(new CancelledTaskMessageHandler());
     }

面临的问题

问题

已尝试

Owin 管道中的 Eating out 异常(在 OAuthConfig 的构造函数中)

        this.app.Use(async (ctx, next) =>
        {
            try
            {
                await next();
            }
            catch (OperationCanceledException)
            {
                // Eat this exception
            }
        });

虽然我们现在没有启用授权,但想知道这是否可以暗示一些其他设计问题,这些问题可能会导致以后出现问题。

如果需要,可以包括任何其他特定工件。 谢谢

首先让我简要介绍一下 OWIN 的工作原理。值得您阅读更多相关内容,但这是一个很好的起点。

将 OWIN 视为请求与您的应用程序之间的管道,在本例中为 MVC Web Api。管道的每一部分都称为 "middleware",请求流经此管道,直到到达您的应用程序。当请求到达管道时,流程反转,数据通过管道回流。因此,此管道的每一部分("middleware")都会看到数据两次,分别是数据进入应用程序和数据离开应用程序时。中间件可以在请求进入时查看或修改请求,或者在它离开您的应用程序时查看或修改响应,或者两者兼而有之。

每个中间件组件都会收到一个字典,其中包含有关请求和响应的各种数据,以及一个调用下一​​段管道的委托。

现在输入您的代码:

您的应用程序是 WebApi,由这些行定义:

app.UseWebApi(AppConfiguration);

您有两个使用这些行初始化的中间件:

    var issuer = ConfigurationManager.AppSettings["as:IssuerServer"];
    var tokenEndpoint = ConfigurationManager.AppSettings["as:OwinTokenEndpoint"];    // "/oauth/token"
    OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions()
    {
        ////For Dev enviroment only (on production should be AllowInsecureHttp = false)
        AllowInsecureHttp = true,
        TokenEndpointPath = new Microsoft.Owin.PathString(tokenEndpoint),
        AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
        Provider = new CustomOAuthProvider(),
        AccessTokenFormat = new CustomJwtFormat(issuer)
    };

    // OAuth 2.0 Bearer Access Token Generation
    this.app.UseOAuthAuthorizationServer(oAuthServerOptions);

然后是这些行:

    string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
    var issuer = ConfigurationManager.AppSettings["as:IssuerServer"]; // Should have the Url of the auth server http://localhost:53025/";
    byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["as:AudienceSecret"]);
    this.app.UseJwtBearerAuthentication(
        new JwtBearerAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            AllowedAudiences = new[] { audienceId },
            IssuerSecurityKeyProviders = new IIssuerSecurityKeyProvider[]
            {
                new SymmetricKeyIssuerSecurityKeyProvider(issuer, audienceSecret)
            }
        });

此中间件将始终 运行。如果你在任何地方有任何属性都没有关系。

您说该错误不会发生在本地开发机器上,这意味着您很可能遇到了配置问题。您正在将设置传递到上面引用的行中的中间件。

基于此,我怀疑您的 issuertokenEndpoint 变量或(更有可能)audienceIdaudienceSecret 变量有问题。

希望对您有所帮助。