在Windows窗体中使用HttpClient类中的DelegatingHandler - 尚未设置内部处理程序

Adr*_*ian 15 c# asp.net-web-api

首先,我收到的错误消息如下: 尚未设置内部处理程序

我正在编写一个自定义消息处理程序来处理我的API的身份验证cookie超时.例如,如果我的代码库调用API然后接收401,那么它应该重试登录URL以获取更新的cookie.我打算按如下方式完成此任务:

public class CkApiMessageHandler : DelegatingHandler
{
    private readonly string _email;
    private readonly string _password;
    private const string _loginPath = "Account/Login";

    public CkApiMessageHandler(string email, string password)
    {
        _email = email;
        _password = password;

        //InnerHandler = new HttpControllerDispatcher(null);
    }

    protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {

        var response = await base.SendAsync(request, cancellationToken);

        if(response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
        {
            Logging.Logger.LogInformation("Authentication cookie timed out");
            var baseAddress = request.RequestUri.Host;
            var loginPath = baseAddress + _loginPath;

            var originalRequest = request;

            var loginRequest = new HttpRequestMessage(new HttpMethod("POST"), loginPath);
            var dict = new Dictionary<string, string>();
            dict.Add("Email", _email);
            dict.Add("Password", _password);

            var form = new FormUrlEncodedContent(dict);
            loginRequest.Content = form;
            loginRequest.Headers.Clear();

            foreach(var header in originalRequest.Headers)
            {
                loginRequest.Headers.Add(header.Key, header.Value);
            }

            var loginResponse = await base.SendAsync(loginRequest, cancellationToken);

            if (loginResponse.IsSuccessStatusCode)
            {
                Logging.Logger.LogInformation("Successfully logged back in");
                return await base.SendAsync(originalRequest, cancellationToken);
            }
            else
            {
                Logging.Logger.LogException(new Exception("Failed to log back in"), "Could not log back in");
            }
        }

        return response;
    }


}  
Run Code Online (Sandbox Code Playgroud)

我正在将一个用于直接访问数据库的旧服务转换为访问web api的服务,而我正在尝试这样做,而不必更改此类的任何使用者.因此,奇怪的处理程序.这是服务类的示例方法.

 public void UpdateClientInstallDatabaseAndServiceData(string dbAcronym, string clientVersion, string clientEnginePort, Guid installationId, string sqlserver)
    {
        var dict = new Dictionary<string, string>();
        dict.Add("dbAcronym", dbAcronym);
        dict.Add("clientVersion", clientVersion);
        dict.Add("clientEnginePort", clientEnginePort);
        dict.Add("desktopClientId", installationId.ToString());
        dict.Add("sqlServerIp", sqlserver);

        var form = new FormUrlEncodedContent(dict);

        _client.PostAsync(_apiPath + "/UpdateClientInstallDatabaseAndServiceData", form);
    }  
Run Code Online (Sandbox Code Playgroud)

因此,如果上面的代码失败了401,服务将自动重新登录并重试原始代码,而服务的消费者不必检查请求并重新登录.消费者不应该知道它正在处理web api .

我的问题是我的消息处理程序期望InnerHandler设置一个需要HttpConfiguration类实例的消息处理程序.当我看一下这里的规范时,它似乎是用于设置web api服务的某种类.这很好,除了这个代码没有在api中执行..它正在Windows窗体应用程序上执行.委托处理程序正在HttpClient类中使用...

_client = new HttpClient(new CKEnterprise.Common.CkApiMessageHandler(email, password));  
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:如何让这个DelegatingHandler在web api项目的上下文之外完成它的工作?

进行更新.看起来我可能只能使用HttpClientHandler类 https://blogs.msdn.microsoft.com/henrikn/2012/08/07/httpclient-httpclienthandler-and-webrequesthandler-explained/

Adr*_*ian 30

我应该早点意识到这一点,但是将内部处理程序设置为使用的默认处理程序是有意义的HttpClient.因此,在你的子类中,DelegatingHandler你应该将内部处理程序设置为使用的默认处理程序,HttpClient如下所示:

    public CkApiMessageHandler(string email, string password, Guid moduleId)
    {
        _email = email;
        _password = password;
        _moduleId = moduleId;
        InnerHandler = new HttpClientHandler();

    }
Run Code Online (Sandbox Code Playgroud)

  • 这根本不直观.好找:) (6认同)

Luk*_*och 13

阿德里安的答案是正确的。您必须为自定义处理程序设置一个内部处理程序,但有一种更好的方法来设置内部处理程序。

public MyDelegatingHandler( ) : base( new HttpClientHandler( ) )
Run Code Online (Sandbox Code Playgroud)

  • 但是这里的HttpClientHandler是手动创建的吗?它将由框架管理(池化、生存时间等)吗? (2认同)