Tout d'abord, le message d'erreur que je reçois est le suivant: Le gestionnaire interne n'a pas été défini

J'écris un gestionnaire de messages personnalisé pour gérer les délais d'expiration des cookies d'authentification vers mon API. Par exemple, si ma base de code fait un appel à l'API et reçoit à son tour un 401, elle doit réessayer l'URL de connexion pour obtenir un cookie mis à jour. J'ai prévu d'accomplir cela comme suit:

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;
    }


}  

Je suis en train de convertir un ancien service qui permettait d'accéder directement à la base de données en un service qui accède à une API Web et j'essaye de le faire sans avoir à changer aucun des consommateurs de cette classe. D'où l'étrange gestionnaire. Voici un exemple de méthode de la classe de service.

 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);
    }  

Donc, si le code ci-dessus échoue avec un 401, le service se reconnectera automatiquement et réessayera le code d'origine sans que le consommateur du service n'ait à vérifier les demandes et à se reconnecter. Le consommateur ne doit pas savoir qu'il a affaire à une API Web .

Mon problème est que mon gestionnaire de messages s'attend à ce qu'un InnerHandler soit défini qui nécessite une instance de la classe HttpConfiguration. Quand je regarde les spécifications ici, il semble s'agir d'un type de classe utilisé pour configurer un service API Web. C'est très bien, sauf que ce code n'est pas exécuté dans une API. Il est exécuté sur une application Windows Forms. Le gestionnaire de délégation est utilisé dans une classe HttpClient comme ceci ...

_client = new HttpClient(new CKEnterprise.Common.CkApiMessageHandler(email, password));  

Ma question est donc : Comment puis-je amener ce DelegatingHandler à faire son travail en dehors du contexte d'un projet d'API Web?

Faire une mise à jour. Il semble que je puisse simplement utiliser la classe HttpClientHandler https: //blogs.msdn. microsoft.com/henrikn/2012/08/07/httpclient-httpclienthandler-and-webrequesthandler-explained/

16
Adrian 30 avril 2017 à 02:01

3 réponses

Meilleure réponse

J'aurais dû m'en rendre compte plus tôt mais il est logique de définir peut-être le gestionnaire interne sur le gestionnaire par défaut que HttpClient utilise. Donc, à l'intérieur de votre classe enfant de DelegatingHandler, vous devez définir votre gestionnaire interne sur le gestionnaire par défaut utilisé par HttpClient comme ceci:

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

    }
33
Adrian 30 avril 2017 à 22:03

La réponse d'Adrian est correcte. Vous devez définir un gestionnaire interne pour votre gestionnaire personnalisé, mais il existe un meilleur moyen de définir le gestionnaire interne.

public MyDelegatingHandler( ) : base( new HttpClientHandler( ) )
4
Lukáš Kmoch 9 août 2019 à 11:01

Ou vous pouvez utiliser HttpClientFactory

_client  = HttpClientFactory.Create(new CKEnterprise.Common.CkApiMessageHandler(email, password))

https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/httpclient-message-handlers#adding-message-handlers-to-the-client-pipeline

2
Raj Rao 26 juin 2019 à 18:43