WCF и подтверждения - нужно ли мне отправлять клиенту сообщение «OK получил»? - PullRequest
10 голосов
/ 22 октября 2008

Если на моем сервере подключены сотни / тысячи клиентских компьютеров, должен ли я ответить сообщением типа «200 OK», в котором говорится, что я получил данные и успешно сохранил их в БД?

Это уже встроенный WCF?

Ответы [ 4 ]

18 голосов
/ 23 октября 2008

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

  1. Синхронный запрос-ответ
  2. Асинхронная отправка (запустить и забыть с односторонним обслуживанием)
  3. Асинхронный запрос-ответ (дуплексный сервисный вызов с односторонним обслуживанием)

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

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

Вариант 1

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

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

Вариант 2

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

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

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

Вариант 3

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


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

Как упоминал Виск, у Ювала Лоуи есть статья, в которой много говорится об этой детали (и даже больше!) здесь

Вариант 1

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

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

[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 голосов
/ 22 октября 2008

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

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

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

Удачи!

1 голос
/ 22 октября 2008

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

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

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

0 голосов
/ 23 октября 2008

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

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

...