web-dev-qa-db-fra.com

Comment ajouter un en-tête HTTP personnalisé pour un client de service Web C # utilisant le service Web Axis 1.4

J'essaie d'écrire un client de service Web en c # dont le service Web est Java Axis 1.4 . Le service Axis requiert la valeur Authorization: Basic Base64EncodedToken dans les en-têtes HTTP. Je ne trouve pas le moyen de définir cet en-tête de manière standard pour consommer des services Web dans Visual Studio.net, comme le refernce généré par WSDL ni avec WSE3.0.

Je ne peux pas utiliser WCF car le projet est développé avec .net 2.0.

Y a-t-il un moyen de faire ça ?

43
UmutKa

Il semble que l’auteur original ait trouvé sa solution, mais pour quiconque cherche ici à ajouter des en-têtes personnalisés, si vous avez accès au code de protocole généré, vous pouvez remplacer GetWebRequest:

protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
  System.Net.WebRequest request = base.GetWebRequest(uri);
  request.Headers.Add("myheader", "myheader_value");
  return request;
}

Assurez-vous de supprimer l'attribut DebuggerStepThroughAttribute si vous souhaitez y accéder.

45
user334291

Parlons-nous de la WCF ici? J'ai eu des problèmes où les appels de service n'ajoutaient pas les en-têtes d'autorisation http, encapsulant tous les appels dans cette déclaration a résolu mon problème.

  using (OperationContextScope scope = new OperationContextScope(RefundClient.InnerChannel))
  {
            var httpRequestProperty = new HttpRequestMessageProperty();
            httpRequestProperty.Headers[System.Net.HttpRequestHeader.Authorization] = "Basic " +
            Convert.ToBase64String(Encoding.ASCII.GetBytes(RefundClient.ClientCredentials.UserName.UserName + ":" +
            RefundClient.ClientCredentials.UserName.Password));
            OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;

            PaymentResponse = RefundClient.Payment(PaymentRequest);
   }

Ceci exécutait des appels SOAP à IBM ESB via .NET avec une autorisation de base via http ou https.

J'espère que cela aidera quelqu'un parce que j'ai eu de gros problèmes pour trouver une solution en ligne.

25
Simon RC

Si vous souhaitez envoyer un en-tête HTTP personnalisé (et non un en-tête SOAP), vous devez utiliser la classe HttpWebRequest, le code devrait ressembler à ceci:

HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Headers.Add("Authorization", token);

Vous ne pouvez pas ajouter d’en-têtes HTTP à l’aide du proxy généré par Visual Studio, ce qui peut être très pénible.

7
John Hunter

Au lieu de modifier le code généré automatiquement ou d'encapsuler chaque appel dans un code dupliqué, vous pouvez injecter vos en-têtes HTTP personnalisés en ajoutant un inspecteur de messages personnalisé.

public class CustomMessageInspector : IClientMessageInspector
{
    readonly string _authToken;

    public CustomMessageInspector(string authToken)
    {
        _authToken = authToken;
    }

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        var reqMsgProperty = new HttpRequestMessageProperty();
        reqMsgProperty.Headers.Add("Auth-Token", _authToken);
        request.Properties[HttpRequestMessageProperty.Name] = reqMsgProperty;
        return null;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState)
    { }
}


public class CustomAuthenticationBehaviour : IEndpointBehavior
{
    readonly string _authToken;

    public CustomAuthenticationBehaviour (string authToken)
    {
        _authToken = authToken;
    }
    public void Validate(ServiceEndpoint endpoint)
    { }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    { }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    { }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.ClientMessageInspectors.Add(new CustomMessageInspector(_authToken));
    }
}

Et lors de l'instanciation de votre classe client, vous pouvez simplement l'ajouter en tant que comportement:

this.Endpoint.EndpointBehaviors.Add(new CustomAuthenticationBehaviour("Auth Token"));

Cela fera que chaque appel de service sortant aura votre en-tête HTTP personnalisé.

6
Saeb Amini

Je trouve ce code et résout mon problème.

http://arcware.net/setting-http-header-authorization-for-web-services/

protected override WebRequest GetWebRequest(Uri uri)
{
    // Assuming authValue is set from somewhere, such as the config file
    HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(uri);
    request.Headers.Add("Authorization", string.Format("Basic {0}", authValue));
    return request;
}
5
Valdemar Carneiro

la réponse de user334291 a été une bouée de sauvetage pour moi. Je veux juste ajouter comment vous pouvez ajouter ce que le PO avait initialement l'intention de faire (ce que j'ai fini par utiliser):

Remplacement de la fonction GetWebRequest sur le code de service Web généré:

protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
    System.Net.WebRequest request = base.GetWebRequest(uri);          
    string auth = "Basic " + Convert.ToBase64String(System.Text.Encoding.Default.GetBytes(this.Credentials.GetCredential(uri, "Basic").UserName + ":" + this.Credentials.GetCredential(uri, "Basic").Password));
    request.Headers.Add("Authorization", auth);
    return request;
}

et définir les informations d'identification avant d'appeler le service Web:

  client.Credentials = new NetworkCredential(user, password);       
1
Tiago Martins

Voici ce qui a fonctionné pour moi: 

protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
        HttpWebRequest request;
        request = (HttpWebRequest)base.GetWebRequest(uri);
        NetworkCredential networkCredentials =
        Credentials.GetCredential(uri, "Basic");
        if (networkCredentials != null)
        {
            byte[] credentialBuffer = new UTF8Encoding().GetBytes(
            networkCredentials.UserName + ":" +
            networkCredentials.Password);
            request.Headers["Authorization"] =
            "Basic " + Convert.ToBase64String(credentialBuffer);
            request.Headers["Cookie"] = "BCSI-CS-2rtyueru7546356=1";
            request.Headers["Cookie2"] = "$Version=1";
        }
        else
        {
            throw new ApplicationException("No network credentials");
        }
        return request;
}

N'oubliez pas de définir cette propriété: 

service.Credentials = new NetworkCredential("username", "password");  

Cookie et Cookie2 sont définis dans l'en-tête parce que le service Java n'acceptait pas la demande et que j'obtenais une erreur non autorisée.

0
Attiq Rehman