Здесь упоминаются три шаблона сообщений:
- Синхронный запрос-ответ
- Асинхронная отправка (запустить и забыть с односторонним обслуживанием)
- Асинхронный запрос-ответ (дуплексный сервисный вызов с односторонним обслуживанием)
Все три отображают различное поведение при обмене сообщениями, и используемый шаблон следует выбирать в зависимости от ваших потребностей.
Для вашего требования возврата успеха клиенту, когда данные были сохранены в базе данных, подходят варианты 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 будет возвращать исключение при возникновении необработанного исключения.