2010-06-15 3 views
7

Ceci est ma première étape dans le monde de stackoverflow, alors je m'excuse si je bats quelque chose.Utilisation de IOperationBehavior pour fournir un paramètre WCF

Je suis en train de créer une opération WCF qui a un paramètre qui est pas exposé au monde extérieur, mais est à la place automatiquement transmise dans la fonction.

Ainsi, le monde voit ceci: int Add(int a, int b)

Mais il est mis en œuvre comme: int Add(object context, int a, int b)

Ensuite, le contexte se fourni par le système lors de l'exécution. L'exemple avec lequel je travaille est complètement artificiel, mais imite quelque chose que je regarde dans un scénario réel. Je suis capable d'être proche, mais pas tout à fait là-bas.

Tout d'abord, je créé une méthode simple et a écrit une application pour confirmer cela fonctionne. Cela fait. Il renvoie a + b et écrit le contexte en tant que chaîne dans mon débogage. Yay.

[OperationContract] 
    int Add(object context, int a, int b); 

J'ai alors écrit le code suivant:

public class SupplyContextAttribute : Attribute, IOperationBehavior 
{ 
    public void Validate(OperationDescription operationDescription) 
    { 
     if (!operationDescription.Messages.Any(m => m.Body.Parts.First().Name == "context")) 
      throw new FaultException("Parameter 'context' is missing."); 
    } 

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) 
    { 
     dispatchOperation.Invoker = new SupplyContextInvoker(dispatchOperation.Invoker); 
    } 

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) 
    { 
    } 

    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) 
    { 
     // Remove the 'context' parameter from the inbound message 
     operationDescription.Messages[0].Body.Parts.RemoveAt(0); 
    } 
} 

public class SupplyContextInvoker : IOperationInvoker 
{ 
    readonly IOperationInvoker _invoker; 

    public SupplyContextInvoker(IOperationInvoker invoker) 
    { 
     _invoker = invoker; 
    } 

    public object[] AllocateInputs() 
    { 
     return _invoker.AllocateInputs().Skip(1).ToArray(); 
    } 

    private object[] IntroduceContext(object[] inputs) 
    { 
     return new[] { "MyContext" }.Concat(inputs).ToArray(); 
    } 

    public object Invoke(object instance, object[] inputs, out object[] outputs) 
    { 
     return _invoker.Invoke(instance, IntroduceContext(inputs), out outputs); 
    } 

    public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state) 
    { 
     return _invoker.InvokeBegin(instance, IntroduceContext(inputs), callback, state); 
    } 

    public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) 
    { 
     return _invoker.InvokeEnd(instance, out outputs, result); 
    } 

    public bool IsSynchronous 
    { 
     get { return _invoker.IsSynchronous; } 
    } 
} 

Et mon opération WCF ressemble maintenant à ceci:

[OperationContract, SupplyContext] 
    int Amend(object context, int a, int b); 

Mes références mises à jour ne montrent plus le paramètre 'contexte', qui est exactement ce que je veux. Le problème est que lorsque j'exécute le code, il dépasse le AllocateInputs et renvoie une erreur Index was outside the bounds of the Array. quelque part dans les entrailles WCF.

J'ai essayé d'autres choses, et je trouve que je peux changer avec succès le type du paramètre et le renommer et que mon travail de code. Mais au moment où je supprime le paramètre, il tombe.

Quelqu'un peut-il me donner une idée de la façon d'obtenir ce travail (ou si elle peut être fait du tout).

Répondre

5

Eh bien, je l'ai compris par moi-même. MessagePartDescription a une propriété Index. J'ai juste besoin de resynchroniser ces valeurs.

public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) 
    { 
     var parts = operationDescription.Messages[0].Body.Parts; 
     parts.RemoveAt(0); 
     for (int i = 0; i < parts.Count; i++) 
      parts[i].Index = i; 
    } 
Questions connexes