web-dev-qa-db-fra.com

Comment ajouter un en-tête HTTP personnalisé à chaque appel WCF?

J'ai un service WCF hébergé dans un service Windows. Les clients qui utilisent ce service doivent transmettre un identifiant chaque fois qu'ils appellent des méthodes de service (car cet identifiant est important pour ce que la méthode appelée doit faire). J'ai pensé que c'était une bonne idée de mettre en quelque sorte cet identifiant dans les informations d'en-tête WCF.

Si c'est une bonne idée, comment puis-je ajouter l'identifiant automatiquement aux informations d'en-tête? En d'autres termes, chaque fois que l'utilisateur appelle la méthode WCF, l'identificateur doit être automatiquement ajouté à l'en-tête.

PDATE: Les clients qui utilisent le service WCF sont à la fois des applications Windows et des applications Windows Mobile (à l'aide de Compact Framework).

152
mrtaikandi

L'avantage, c'est qu'il est appliqué à chaque appel.

Créez une classe qui implémente IClientMessageInspector . Dans la méthode BeforeSendRequest, ajoutez votre en-tête personnalisé au message sortant. Cela pourrait ressembler à quelque chose comme ça:

    public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request,  System.ServiceModel.IClientChannel channel)
{
    HttpRequestMessageProperty httpRequestMessage;
    object httpRequestMessageObject;
    if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))
    {
        httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
        if (string.IsNullOrEmpty(httpRequestMessage.Headers[USER_AGENT_HTTP_HEADER]))
        {
            httpRequestMessage.Headers[USER_AGENT_HTTP_HEADER] = this.m_userAgent;
        }
    }
    else
    {
        httpRequestMessage = new HttpRequestMessageProperty();
        httpRequestMessage.Headers.Add(USER_AGENT_HTTP_HEADER, this.m_userAgent);
        request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
    }
    return null;
}

Créez ensuite un comportement de noeud final qui applique l'inspecteur de message au runtime du client. Vous pouvez appliquer le comportement via un attribut ou via une configuration à l'aide d'un élément d'extension behavior.

Voici un excellent exemple expliquant comment ajouter un en-tête d'utilisateur-agent HTTP à tous les messages de requête. J'utilise cela dans quelques-uns de mes clients. Vous pouvez également faire la même chose du côté du service en implémentant le IDispatchMessageInspector .

Est-ce ce que vous aviez en tête?

Mise à jour: J'ai trouvé cette liste de fonctionnalités WCF prises en charge par le cadre compact. Je crois que les inspecteurs de messages classés dans la catégorie "Extensibilité de canal" qui, selon ce message, sont pris en charge par le cadre compact.

174
Mark Good

Vous l'ajoutez à l'appel en utilisant:

using (OperationContextScope scope = new OperationContextScope((IContextChannel)channel))
{
    MessageHeader<string> header = new MessageHeader<string>("secret message");
    var untyped = header.GetUntypedHeader("Identity", "http://www.my-website.com");
    OperationContext.Current.OutgoingMessageHeaders.Add(untyped);

    // now make the WCF call within this using block
}

Et puis, côté serveur, vous le récupérez avec:

MessageHeaders headers = OperationContext.Current.IncomingMessageHeaders;
string identity = headers.GetHeader<string>("Identity", "http://www.my-website.com");
79
AgileJon

Si vous souhaitez simplement ajouter le même en-tête à toutes les demandes adressées au service, vous pouvez le faire sans codage!
Ajoutez simplement le nœud des en-têtes avec les en-têtes requis sous le nœud du noeud final dans votre fichier de configuration client.

<client>  
  <endpoint address="http://localhost/..." >  
    <headers>  
      <HeaderName>Value</HeaderName>  
    </headers>   
 </endpoint>  
32
Nimesh Madhavan

Voici une autre solution utile pour ajouter manuellement des en-têtes HTTP personnalisés à votre demande WCF client à l'aide de ChannelFactory comme proxy. Cela devrait être fait pour chaque demande, mais cela suffit comme démonstration simple si vous avez juste besoin de tester votre proxy de manière unitaire afin de vous préparer aux plates-formes non.NET.

// create channel factory / proxy ...
using (OperationContextScope scope = new OperationContextScope(proxy))
{
    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = new HttpRequestMessageProperty()
    {
        Headers = 
        { 
            { "MyCustomHeader", Environment.UserName },
            { HttpRequestHeader.UserAgent, "My Custom Agent"}
        }
    };    
    // perform proxy operations... 
}
13
SliverNinja - MSFT

Ceci est similaire à la réponse NimsDotNet mais montre comment procéder par programme.

Ajoutez simplement l'en-tête à la reliure

var cl = new MyServiceClient();

var eab = new EndpointAddressBuilder(cl.Endpoint.Address);

eab.Headers.Add( 
      AddressHeader.CreateAddressHeader("ClientIdentification",  // Header Name
                                         string.Empty,           // Namespace
                                         "JabberwockyClient"));  // Header Value

cl.Endpoint.Address = eab.ToEndpointAddress();
10
ΩmegaMan
var endpoint = new EndpointAddress(new Uri(RemoteAddress),
                                               new[]
                                                   {
                                                       AddressHeader.CreateAddressHeader("APIKey", "",
                                                                                         "bda11d91-7ade-4da1-855d-24adfe39d174")
                                                   });
5
shepcom

Vous pouvez spécifier des en-têtes personnalisés dans MessageContract .

Vous pouvez également utiliser les en-têtes <endpoint> qui sont stockés dans le fichier de configuration et seront copiés dans l'en-tête de tous les messages envoyés par le client/service. Ceci est utile pour ajouter facilement un en-tête statique.

2
Philippe

Ça marche pour moi

TestService.ReconstitutionClient _serv = new TestService.TestClient ();

 using (OperationContextScope contextScope = new OperationContextScope(_serv.InnerChannel))
                {
                    HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();

                    requestMessage.Headers["apiKey"] = ConfigurationManager.AppSettings["apikey"]; 
                    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
                    _serv.Method(Testarg);
                }
2
Taran

Le contexte liaisons dans .NET 3.5 pourrait bien être ce que vous cherchez. Trois types sont disponibles: BasicHttpContextBinding, NetTcpContextBinding et WSHttpContextBinding. Le protocole de contexte transmet essentiellement les paires clé-valeur dans l'en-tête du message. Consultez l'article Gestion de l'état avec des services durables dans le magazine MSDN.

2
Mehmet Aras

Si je comprends bien votre besoin, la réponse simple est: vous ne pouvez pas.

En effet, le client du service WCF peut être généré par tout tiers utilisant votre service.

SI vous avez le contrôle des clients de votre service, vous pouvez créer une classe client de base qui ajoute l'en-tête souhaité et hérite du comportement des classes de travail.

2
Paulo Santos

C’est ce qui a fonctionné pour moi, adapté de Ajout d’en-têtes HTTP aux appels WCF

// Message inspector used to add the User-Agent HTTP Header to the WCF calls for Server
public class AddUserAgentClientMessageInspector : IClientMessageInspector
{
    public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel)
    {
        HttpRequestMessageProperty property = new HttpRequestMessageProperty();

        var userAgent = "MyUserAgent/1.0.0.0";

        if (request.Properties.Count == 0 || request.Properties[HttpRequestMessageProperty.Name] == null)
        {
            var property = new HttpRequestMessageProperty();
            property.Headers["User-Agent"] = userAgent;
            request.Properties.Add(HttpRequestMessageProperty.Name, property);
        }
        else
        {
            ((HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name]).Headers["User-Agent"] = userAgent;
        }
        return null;
    }

    public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
    {
    }
}

// Endpoint behavior used to add the User-Agent HTTP Header to WCF calls for Server
public class AddUserAgentEndpointBehavior : IEndpointBehavior
{
    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(new AddUserAgentClientMessageInspector());
    }

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

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

    public void Validate(ServiceEndpoint endpoint)
    {
    }
}

Après avoir déclaré ces classes, vous pouvez ajouter le nouveau comportement à votre client WCF comme suit:

client.Endpoint.Behaviors.Add(new AddUserAgentEndpointBehavior());
1
paulwhit