Ответ 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 возвращает исключение, когда генерируется необработанное исключение.