WCF и подтверждения - мне нужно отправить обратно "OK got it" клиенту?

Если у меня есть сотни/тысячи клиентских компьютеров WCP'ing на моем сервере, я должен ответить сообщением типа "200 OK", в котором говорится, что я получил данные и успешно сохранил их в db?

Является ли это уже встроенным в WCF?

Ответ 1

Здесь упоминаются три шаблона обмена сообщениями:

  • Синхронный запрос-ответ
  • Асинхронная отправка (пожар и задержка с односторонней службой)
  • Асинхронный запрос-ответ (дуплексный вызов службы с односторонней службой)

Все три отображают поведение разных сообщений, а шаблон, который нужно использовать, следует выбирать в соответствии с вашими потребностями.

Для вашего требования вернуть успех клиенту, когда данные были сохранены в базе данных, подходят варианты 1 или 3.

Вариант 1

Это конфигурация по умолчанию.

Это возвращает ответ 200 на том же http-соединении, когда служба выполнила все свои задачи. Это означает, что вызовы службы будут блокироваться в ожидании ответа - ваш клиент будет висеть до тех пор, пока служба не будет записана в базу данных и не сделает все, что ему нужно.

Вариант 2

Возвращает ответ 202, пока уровень транспортного уровня и уровня обмена сообщениями преуспевает. Возвращенный 202 указывает, что сообщение принято. Из http rfc:

Запрос принят для обработки, но обработка еще не завершена. (...) Ответ 202 намеренно не допускается.

Это означает, что ваш клиент продолжит выполнение, как только сервисная инфраструктура успешно запустит службу, и вы не получите никакой информации о том, успешно ли вызван вызов базы данных.

Вариант 3

Как и в случае с вариантом 2, ответ представляет собой HTTP 202, а не 200, но теперь, когда вы вызываете службу от клиента, вы предоставляете объект InstanceContext, который указывает объект для обработки обратного вызова. Клиент восстанавливает контроль, и новый поток ожидает асинхронно для ответа службы, информирующего вас об успехе или неудаче.


Ниже приведена подробная информация об использовании этих шаблонов в WCF. После написания, это довольно долго, но есть несколько полезных комментариев, а также код.

Как отметил Уиск, у Juval Lowy есть статья, в которой подробно описывается эта деталь (и многое другое!) здесь

Вариант 1

Это поведение по умолчанию в WCF, поэтому вам не нужно ничего делать - он работает с множеством разных привязок, включая wsHttpBinding и basicHttpBinding.

Следует отметить, что поведение, описанное с вашим клиентом, висящим в ожидании ответа 200, даже если у вас есть операция void:

[ServiceContract]
interface IMyServiceContract
{
    [OperationContract]       
    void DoSomeThing(InputMessage Message);
}

Вариант 2

Чтобы установить операцию как одностороннюю, вы просто украшаете ее так:

[ServiceContract]
interface IMyServiceContract
{
    [OperationContract(IsOneWay = true)]       
    void DoSomeThing(InputMessage Message);
}

Методы, оформленные таким образом, должны иметь только возвращаемый тип void. Один из них заключается в том, что служба будет с радостью работать, и вы не получите исключение, заявив, что конфиг службы недействителен, пока вы не подключитесь к нему.

Вариант 3

Код интерфейса для создания двусторонней службы обратного вызова:

[ServiceContract(CallbackContract = typeof(IMyContractCallback))]
interface IMyContract
{
    [OperationContract(IsOneWay=true)]       
    void DoSomeThing(InputMessage Message);
}

public interface IMyContractCallback
{
    [OperationContract(IsOneWay = true)]
    void ServiceResponse(string result);      
}

И на стороне клиента вам нужно что-то вроде этого, чтобы настроить обратный вызов:

public class CallbackHandler : IMyContractCallback        
{
    #region IEchoContractCallback Members

    public void ServiceResponse(string result)
    {
        //Do something with the response
    }

    #endregion
}

// And in the client when you set up the service call:

InstanceContext instanceContext = new InstanceContext(new CallbackHandler());
MyContractClient client = new MyContractClient(instanceContext);

InputMessage msg = new InputMessage();

client.DoSomething(msg);           

В сервисе у вас, возможно, есть код вроде:

class MyContractImplementation : IMyContract
{
    public void DoSomeThing(MyMessage Message)
    {

        string responseMessage;

        try
        {
           //Write to the database
           responseMessage = "The database call was good!";
        }
        catch (Exception ex)
        {
            responseMessage = ex.Message;
        }

        Callback.ServiceResponse(responseMessage);
    }
}

Одна важная вещь, которая должна была заметить меня, заключалась в том, чтобы быть осторожным в отношении исключений. Если вы:

  • Примите исключение, вы не получите предупреждения об ошибке (но произойдет обратный вызов)

  • Выбросьте необработанное исключение, служба завершится, и клиент даже не получит обратный вызов.

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

Ответ 2

По умолчанию ваша служба вернет клиенту сообщение "ОК" (даже если ваш метод службы указывает тип возврата void), если не будет выбрано исключение. Клиент будет ждать, пока он не получит это сообщение, прежде чем продолжить с ним жизнь.

Таким образом, исходя из вашего вопроса, вы по умолчанию хотите получить поведение.

Если вы этого не хотите, я соглашусь с Whisk и отметьте вашу операцию как One Way (настройка в вашем рабочем контракте).

Удачи!

Ответ 3

Есть два способа сделать это: верните значение из вашего wcf-вызова, указывающего на успех или неудачу, или предположите успех и используйте обратный вызов, чтобы сообщить клиенту, есть ли проблемы.

Моим преимуществом было бы использовать сервисный вызов one-way с duplex service и использовать контракт обратного вызова для службы, чтобы уведомить клиента об ошибке. Там хорошее описание контрактов обратного вызова здесь и здесь.

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

Ответ 4

Я думаю, что вопрос мог бы использовать немного более подробную информацию, чтобы правильно ответить. Первичный, какой тип привязки вы используете в настоящее время?

Если вы используете привязку, которая поддерживает надежность, и вы просто хотите быть уверенным, с клиентской стороны этот сервер действительно получил сообщение, а затем просто включите надежность, и вы добры. При этом WCF будет, под капотом автоматически, иметь каждую сторону разговора: "Ты понял?" "Я понял, ты понял?" "Я понял".