2009-06-12 13 views
4

En définissant un attribut qui implémente IContactBehavior et IWsdlExportExtension et définissez cet attribut sur votre contrat de service, vous pouvez facilement ajouter têtes de savon à votre wsdl (voir http://wcfextras.codeplex.com/ pour plus d'informations)WCF WSDL savon en-tête sur toutes les opérations

Mais maintenant je dois placer un contrat d'en-tête de savon dans le wsdl sur tous les contrats d'opération et cette fois je ne peux pas placer un attribut.

code suivant (appelé de IWsdlExportExtension.ExportEndPoint) ne fonctionne pas, mais fonctionne lorsqu'il est appelé à partir des SoapHeaderAttributes (qui exécute un IWsdlExportExtension.ExportContract)

foreach (OperationDescription operationDescription in context.ContractConversionContext.Contract.Operations) 
{ 
    AddSoapHeader(operationDescription, "SomeHeaderObject", typeof(SomeHeaderObject), SoapHeaderDirection.InOut);      
} 

internal static void AddSoapHeader(OperationDescription operationDescription, string name, Type type, SoapHeaderDirection direction) 
{ 
    MessageHeaderDescription header = GetMessageHeader(name, type); 
    bool input = ((direction & SoapHeaderDirection.In) == SoapHeaderDirection.In); 
    bool output = ((direction & SoapHeaderDirection.Out) == SoapHeaderDirection.Out); 

    foreach (MessageDescription msgDescription in operationDescription.Messages) 
    { 
     if ((msgDescription.Direction == MessageDirection.Input && input) || 
      (msgDescription.Direction == MessageDirection.Output && output)) 
      msgDescription.Headers.Add(header); 
    } 
} 

internal static MessageHeaderDescription GetMessageHeader(string name, Type type) 
{ 
    string headerNamespace = SoapHeaderHelper.GetNamespace(type); 
    MessageHeaderDescription messageHeaderDescription = new MessageHeaderDescription(name, headerNamespace); 
    messageHeaderDescription.Type = type; 
    return messageHeaderDescription; 
} 

Toute personne a une idée comment appliquer ce code sur toutes les opérations (sans utiliser d'attributs) et en faisant cela, en ajoutant le contrat de l'en-tête au wsdl?

Répondre

5

le IEndpointBehavior a l'interface suivante:

ApplyDispatchBehavior(ServiceEndpoint endPoint, EndPointDispatcher endpointDispatcher); 

Vous pouvez ajouter en-têtes de savon au wsdl pour les opérations par itérer sur les endpoint.Contract.Operations du ApplyDispatchBehavior.

Ici vous avez la solution complète qui a fonctionné pour moi:

void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
{ 
    foreach (OperationDescription operationDescription in endpoint.Contract.Operations) 
    { 
     foreach (MessageDescription msgDescription in operationDescription.Messages) 
     { 
      AddSoapHeader(operationDescription, "SomeHeaderObject", typeof(SomeHeaderObject), SoapHeaderDirection.InOut); 
     } 
    } 
} 

internal static void AddSoapHeader(OperationDescription operationDescription, string name, Type type, SoapHeaderDirection direction) 
{ 
    MessageHeaderDescription header = GetMessageHeader(name, type); 
    bool input = ((direction & SoapHeaderDirection.In) == SoapHeaderDirection.In); 
    bool output = ((direction & SoapHeaderDirection.Out) == SoapHeaderDirection.Out); 

    foreach (MessageDescription msgDescription in operationDescription.Messages) 
    { 
      if ((msgDescription.Direction == MessageDirection.Input && input) || 
        (msgDescription.Direction == MessageDirection.Output && output)) 
        msgDescription.Headers.Add(header); 
    } 
} 

internal static MessageHeaderDescription GetMessageHeader(string name, Type type) 
{ 
    string headerNamespace = SoapHeaderHelper.GetNamespace(type); 
    MessageHeaderDescription messageHeaderDescription = new MessageHeaderDescription(name, headerNamespace); 
    messageHeaderDescription.Type = type; 
    return messageHeaderDescription; 
} 

Le SoapHeaderHelper se trouve dans le WcfExtras.

+1

Vous avez une boucle 'foreach MessageDescription' dans' ApplyDispatchBehavior() 'et' AddSoapHeader() '. Je crois que celui de 'ApplyDispatchBehavior()' devrait être supprimé. – Constantin

4

Vous pouvez jeter un oeil au projet WCFExtras sur CodePlex - il a un certain support pour les en-têtes SOAP personnalisés et d'autres choses comme ça. Pas sûr à 100% s'il est capable de répondre à vos besoins, mais vérifiez-le!

Marc

MISE À JOUR: avez-vous regardé dans la création d'une extension WCF, par exemple quelque chose comme un inspecteur de message, sur le côté du client et du serveur?

Le IClientMessageInspector côté client définit deux méthodes BeforeSendRequest et AfterReceiveReply tandis que le IDispatchMessageInspector côté serveur a les méthodes opposées, à savoir AfterReceiveRequest et BeforeSendReply. Avec cela, vous pouvez ajouter des en-têtes à chaque message qui passe à travers le fil (ou sélectivement seulement à quelques-uns).

Voici un extrait d'un implémenteur de IClientMessageInspector que nous utilisons pour transmettre automagiquement les informations locales (langue et information de la culture) à travers des clients vers le serveur - devrait vous donner une idée de comment commencer:

public object BeforeSendRequest(ref Message request, IClientChannel channel) 
{ 
    International intlHeader = new International(); 
    intlHeader.Locale = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName; 

    MessageHeader header = MessageHeader.CreateHeader(WSI18N.ElementNames.International, WSI18N.NamespaceURI, intlHeader); 
    request.Headers.Add(header); 

    return null; 
} 
+1

Je faisais moi-même référence à WCFExtras, mais je ne savais pas comment ajouter un en-tête de savon à Il wsdl sur toutes les opérations sans définir d'attributs. – Linefeed

+0

J'ai complètement raté votre lien vers wcf extras ..... –

+0

Je ne vois pas comment cela s'applique à la modification du contrat WSDL. Pouvez-vous clarifier ? – Linefeed

0

manière la plus simple est d'utiliser WCFExtrasPlus "https://wcfextrasplus.codeplex.com/wikipage?title=SOAP%20Headers&referringTitle=Documentation", ajoutez simplement dll comme référence à votre projet et modifier votre service de telle façon:

[DataContract(Name="MyHeader", Namespace="web")] 
public class MyHeader 
{ 
    [DataMember(Order=1)] 
    public string UserName {get; set;} 
    [DataMember(Order=2)] 
    public string Password { get; set; } 
} 

[SoapHeaders] 
[ServiceContract] 
public interface IMyService 
{ 
    [SoapHeader("MyHeader", typeof(MyHeader), Direction = SoapHeaderDirection.In)] 
    [OperationContract] 
    [WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped)] 
    bool MyMethod(string input); 
} 

Puis demande de savon ressemble à:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="web" xmlns:tem="http://tempuri.org/"> 
<soapenv:Header> 
    <web:MyHeader> 
    <web:UserName>?</web:UserName> 
    <web:Password>?</web:Password> 
    </web:MyHeader> 
</soapenv:Header> 
<soapenv:Body> 
    <tem:MyMethod> 
    <tem:input>?</tem:input> 
    </tem:MyMethod> 
</soapenv:Body> 
</soapenv:Envelope> 

Si vous avez besoin de Soap et JSON au même service, voici un exemple: https://stackoverflow.com/a/23910916/3667714

Questions connexes