2010-06-15 6 views
7

Dies ist mein erster Schritt in die Welt von stackoverflow, also entschuldige mich bitte, wenn ich etwas hochklaue.Verwendung von IOperationBehavior zur Bereitstellung eines WCF-Parameters

Ich versuche, eine WCF-Operation zu erstellen, die einen Parameter hat, der nicht der Außenwelt ausgesetzt ist, sondern stattdessen automatisch an die Funktion übergeben wird.

So sieht die Welt dies: int Add(int a, int b)

Aber es ist implementiert als: int Add(object context, int a, int b)

Dann wird der Kontext durch das System zur Laufzeit geliefert. Das Beispiel, mit dem ich arbeite, ist völlig künstlich, ahmt aber etwas nach, das ich in einem realen Szenario untersuche.

Ich kann nah kommen, aber nicht ganz den ganzen Weg dorthin.

Zunächst einmal habe ich eine einfache Methode erstellt und eine Anwendung geschrieben, um zu bestätigen, dass es funktioniert. Es tut. Es gibt a + b zurück und schreibt den Kontext als String in mein Debug. Yay.

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

Ich schrieb dann den folgenden Code:

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

Und meine WCF Operation sieht nun wie folgt aus:

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

nicht mehr Meine aktualisierten Referenzen den 'Kontext' Parameter zeigen, die ist genau das, was ich will.

Das Problem ist, dass, wenn ich den Code ausführen, es über die AllocateInputs und dann löst einen Fehler Index was outside the bounds of the Array. irgendwo in den WCF Eingeweide.

Ich habe andere Dinge ausprobiert, und ich finde, dass ich den Typ des Parameters erfolgreich ändern und umbenennen kann und mein Code funktioniert. Aber in dem Moment, in dem ich den Parameter entferne, fällt er um.

Kann jemand mir eine Idee geben, wie man das zum Funktionieren bringt (oder wenn es überhaupt möglich ist).

Antwort

5

Nun, ich habe es selbst herausgefunden. Die MessagePartDescription hat eine Index-Eigenschaft. Ich muss nur diese Werte neu synchronisieren.

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