2010-06-15 9 views
7

To jest mój pierwszy krok do świata stackoverflow, więc przepraszam, jeśli coś podniosę.Używanie IOperationBehavior do dostarczenia parametru WCF

Próbuję utworzyć operację WCF, która ma parametr, który nie jest wystawiony na świat zewnętrzny, ale jest automatycznie przekazywany do funkcji.

Więc świat widzi to: int Add(int a, int b)

Ale to jest zaimplementowany jako: int Add(object context, int a, int b)

Następnie kontekst zostanie dostarczony przez system w czasie wykonywania. Przykład, z którym pracuję, jest całkowicie sztuczny, ale naśladuje coś, na co patrzę w realnym scenariuszu.

Jestem w stanie zbliżyć się, ale nie do końca.

Po pierwsze, stworzyłem prostą metodę i napisałem aplikację, aby potwierdzić, że działa. To robi. Zwraca a + b i zapisuje kontekst jako ciąg do mojego debugowania. Yay.

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

Potem napisał następujący kod:

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

A moja praca WCF teraz wygląda tak:

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

Moi aktualizowane odnośniki pokazują już parametr 'kontekstu', który jest dokładnie tym, czego chcę.

Problem polega na tym, że po uruchomieniu kodu przechodzi on poza numer AllocateInputs, a następnie zgłasza błąd Index was outside the bounds of the Array. gdzieś w jelitach WCF.

Próbowałem innych rzeczy i okazało się, że mogę z powodzeniem zmienić typ parametru i zmienić jego nazwę, a mój kod działa. Ale w chwili, gdy usuwam parametr, to się przewraca.

Czy ktoś może mi dać jakiś pomysł, jak to uruchomić (lub jeśli w ogóle można to zrobić).

Odpowiedz

5

Cóż, wymyśliłem to na własną rękę. MessagePartDescription ma właściwość Index. Potrzebuję tylko zsynchronizować te wartości.

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; 
    } 
Powiązane problemy