У меня есть веб-сервис, ориентированный на .NET 4.5, в котором реализован асинхронный WebMethod и другие синхронные методы.Синхронные методы работают просто отлично.То есть я вызываю их с помощью приложения-клиента WCF Test, и они возвращают ответ.Но!кажется, что асинхронный веб-метод возвращает реальный объект в операторе return, но тестовый клиент ничего не возвращает.
Я создал пример.Рассмотрим следующий метод:
[WebMethod] public int Test() { return 42; }
Я вызываю его следующим образом:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Header> <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/Test</Action> </s:Header> <s:Body> <Test xmlns="http://tempuri.org/" /> </s:Body> </s:Envelope>
И я получаю ответ:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" /> <soap:Body> <TestResponse xmlns="http://tempuri.org/"> <TestResult>42</TestResult> </TestResponse> </soap:Body> </soap:Envelope>
Пока все хорошо.Но когда я попробую это:
[WebMethod] public async Task<int> Test() { await Task.Delay(10); return 42; }
И вызову это:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"> <s:Header> <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/Test</Action> </s:Header> <s:Body> <Test xmlns:d3p1="http://schemas.datacontract.org/2004/07/" i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/" /> </s:Body> </s:Envelope>
я получу пустой ответ.Это происходит с любым объектом, который я пытаюсь вернуть.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <s:Header xmlns:s="http://www.w3.org/2003/05/soap-envelope" /> <soap:Body> <TestResponse xmlns="http://tempuri.org/"> <TestResult /> </TestResponse> </soap:Body> </soap:Envelope>
Это сделано в VS2017.Подпись класса выглядит следующим образом:
[WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] public class MyService : System.Web.Services.WebService
Что мне нужно изменить, чтобы веб-сервис поддерживал вызов асинхронных методов с использованием SOAP?
Модель асинхронного программирования (APM) Асинхронная операция, использующая шаблон проектирования IAsyncResult , реализована в виде двух начинающихся методов BeginOperationName и EndOperationNameи завершите асинхронную операцию OperationName соответственно.
Модель асинхронного программирования (APM)
Асинхронная операция, использующая шаблон проектирования IAsyncResult , реализована в виде двух начинающихся методов BeginOperationName и EndOperationNameи завершите асинхронную операцию OperationName соответственно.
Следующий пример включает два веб-метода с именами SyncUpdateRecords и AsyncUpdateRecords .Пожалуйста, внимательно посмотрите на унаследованный класс ниже.
WebService1.asmx.cs
public class WebService1 : System.Web.Services.Protocols.SoapHttpClientProtocol { public WebService1() { this.Url = "http://localhost:61192/WebService1.asmx"; } [WebMethod] public string SyncUpdateRecords() { return "Records updated => sync"; } [WebMethod] public IAsyncResult BeginAsyncUpdateRecords(AsyncCallback cb, object state) { var updateRecords = new UpdateRecords(); return updateRecords.BeginUpdateRecords(cb, state); } [WebMethod] public string EndAsyncUpdateRecords(IAsyncResult result) { return UpdateRecords.EndUpdateRecords(result); } }
UpdateRecords.cs
public class UpdateRecords { private static string SleepAndWake() { System.Threading.Thread.Sleep(1000); return "Records updated => async"; } private delegate string SleepAndWakeRecords(); private class RecordsState { public readonly SleepAndWakeRecords AsyncDelegate = new SleepAndWakeRecords(SleepAndWake); } public IAsyncResult BeginUpdateRecords(AsyncCallback cb, object s) { var state = new RecordsState(); return state.AsyncDelegate.BeginInvoke(cb, state); } public static string EndUpdateRecords(IAsyncResult result) { var returnDelegate = (RecordsState)result.AsyncState; return returnDelegate.AsyncDelegate.EndInvoke(result); } }