ASMX асинхронный веб-метод возвращает пустой ответ - PullRequest
0 голосов
/ 03 февраля 2019

У меня есть веб-сервис, ориентированный на .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?

1 Ответ

0 голосов
/ 04 февраля 2019

Модель асинхронного программирования (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);
    }

}
...