Использование IOperationBehavior для предоставления параметра WCF - PullRequest
7 голосов
/ 15 июня 2010

Это мой первый шаг в мир переполнения стека, поэтому прошу прощения, если я что-нибудь исправлю.

Я пытаюсь создать операцию WCF, у которой есть параметр, который не отображается во внешнем мире, но вместо этого автоматически передается в функцию.

Итак, мир видит это: int Add(int a, int b)

Но это реализовано так: int Add(object context, int a, int b)

Затем контекст предоставляется системой во время выполнения. Пример, с которым я работаю, полностью искусственный, но имитирует то, с чем я сталкиваюсь в реальном сценарии.

Я могу приблизиться, но не совсем так.

Прежде всего, я создал простой метод и написал приложение, чтобы подтвердить, что он работает. Оно делает. Он возвращает + b и записывает контекст в виде строки для моей отладки. Yay.

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

Затем я написал следующий код:

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

И моя операция WCF теперь выглядит так:

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

В моих обновленных ссылках больше не отображается параметр context, а это именно то, что мне нужно.

Проблема в том, что всякий раз, когда я запускаю код, он проходит AllocateInputs, а затем выдает ошибку Index was outside the bounds of the Array. где-то в кишках WCF.

Я пробовал другие вещи, и я обнаружил, что могу успешно изменить тип параметра, переименовать его и заставить мой код работать. Но в тот момент, когда я удаляю параметр, он падает.

Может ли кто-нибудь дать мне некоторое представление о том, как заставить это работать (или если это можно сделать вообще).

1 Ответ

5 голосов
/ 15 июня 2010

Ну, я понял это самостоятельно. MessagePartDescription имеет свойство Index. Мне просто нужно повторно синхронизировать эти значения.

    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;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...