Member 11528655 Ответов: 1

Как использовать концепцию асинхронной задачи в веб-службе для обслуживания каждого запроса.


Я создал один веб-сервис в C# , который принимает 2 параметра, делает одну строку XML и отправляет HTTP-запрос на один сервер и отвечает ответом, полученным от сервера. Теперь мой вопрос заключается в том, как я могу использовать асинхронную задачу для обработки нескольких запросов к моему веб-сервису, чтобы все мои запросчики получили ответ. ниже приведен мой код для httprequest.

public class Service1 : System.Web.Services.WebService
    {
        
        [WebMethod]
         public string postXMLData(String Session, String Token)
         {
             string destinationUrl = "https://data.getdata.com";
             String requestXml= "<ENVELOPE> <HEADER> <VERSION>1</VERSION> <REQVERSION>1</REQVERSION> <TALLYREQUEST>EXPORT</TALLYREQUEST> <TYPE>DATA</TYPE> <ID>TPGETCOMPANIES</ID><SESSIONID>" + Session + "</SESSIONID> <TOKEN>" + Token + "</TOKEN> </HEADER><BODY> <DESC> <STATICVARIABLES><SVINCLUDE>CONNECTED</SVINCLUDE></STATICVARIABLES></DESC></BODY> </ENVELOPE>";
             HttpWebRequest request = (HttpWebRequest)WebRequest.Create(destinationUrl);
             byte[] bytes;
             bytes = System.Text.Encoding.ASCII.GetBytes(requestXml);
             request.ContentType = "text/xml; encoding='utf-8'";
             request.ContentLength = bytes.Length;
             request.Method = "POST";
             request.Headers.Add("ID","TPGETCOMPANIES");
             request.Headers.Add("SOURCE","EA");
             request.Headers.Add("TARGET","TNS");
             //request.Headers.Add("CONTENT-TYPE","text/xml;charset=utf-8");
             request.Headers.Add("Accept-Encoding","identity");
             Stream requestStream = request.GetRequestStream();
             requestStream.Write(bytes, 0, bytes.Length);
             requestStream.Close();
             HttpWebResponse response;
             response = (HttpWebResponse)request.GetResponse();
             if (response.StatusCode == HttpStatusCode.OK)
             {
                 Stream responseStream = response.GetResponseStream();
                 string responseStr = new StreamReader(responseStream).ReadToEnd().Trim();
                 return responseStr;
                 //responseStr.ToString();
             }
             else
             {

                 return "Problem in getting resp";
             
             }
             return null;
         }

    } 


Что я уже пробовал:

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

1 Ответов

Рейтинг:
1

Richard Deeming

То WebService класс предшествует задаче параллельной библиотеки и ничего не знает о ней. async задачи.

Однако это делает поддержка старшего IAsyncResult / APM pattern:
Как создать асинхронные методы веб-службы[^]

И этот паттерн можно реализовать с помощью Task:
Реализация паттерна APM с помощью задач[^]
Использование задач для реализации паттерна APM / параллельное программирование с помощью .NET[^]

Начните с ToApm метод расширения из блога Стивена Туба:

public static class TaskExtensions
{
    // Found at: http://blogs.msdn.com/b/pfxteam/archive/2011/06/27/10179452.aspx
    public static Task<TResult> ToApm<TResult>(this Task<TResult> task, AsyncCallback callback, object state)
    {
        if (task == null) throw new ArgumentNullException(nameof(task));
        
        if (task.AsyncState == state)
        {
            if (callback != null)
            {
                task.ContinueWith(t => callback(t), CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
            }
            
            return task;
        }
        
        var tcs = new TaskCompletionSource<TResult>(state);
        
        task.ContinueWith(delegate
        {
            if (task.IsFaulted) tcs.TrySetException(task.Exception.InnerExceptions);
            else if (task.IsCanceled) tcs.TrySetCanceled();
            else tcs.TrySetResult(task.Result);
            
            if (callback != null) callback(tcs.Task);
        }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default);
        
        return tcs.Task;
    }
}

Затем переместите свою реализацию в частный async способ возврата Task<string>, и использовать метод расширения, чтобы адаптировать его к шаблону APM:
public class Service1 : System.Web.Services.WebService
{
    private async Task<string> PostXMLDataAsync(string session, string token)
    {
        ...
    }
    
    [WebMethod]
    public IAsyncResult BeginPostXMLDataAsync(string session, string token, AsyncCallback callback, object asyncState)
    {
        return PostXMLDataAsync(session, token).ToApm(callback, asyncState);
    }
    
    [WebMethod]
    public string EndPostXMLDataAsync(IAsyncResult asyncResult)
    {
        // Using ".GetAwaiter().GetResult()" prevents exceptions from being wrapped in an AggregateException:
        return ((Task<string>)asyncResult).GetAwaiter().GetResult();
    }
}

Для реализации вы можете посмотреть на использование классов из Системы.Нет.Пространства имен http [^], так как это обеспечивает более приятный асинхронный API, чем raw HttpWebRequest / HttpWebResponse занятия.

Однако, если вы сделаете это, вы должны убедиться, что используете один статический HttpClient экземпляр для всех запросов, как описано здесь: Вы неправильно используете HttpClient и это дестабилизирует ваше программное обеспечение | ASP.NET монстры[^]
private static readonly HttpClient Http = new HttpClient();

private async Task<string> PostXMLDataAsync(string session, string token)
{
    const string destinationUrl = "https://data.getdata.com";
    string requestXml= "<ENVELOPE> <HEADER> <VERSION>1</VERSION> <REQVERSION>1</REQVERSION> <TALLYREQUEST>EXPORT</TALLYREQUEST> <TYPE>DATA</TYPE> <ID>TPGETCOMPANIES</ID><SESSIONID>" + Session + "</SESSIONID> <TOKEN>" + Token + "</TOKEN> </HEADER><BODY> <DESC> <STATICVARIABLES><SVINCLUDE>CONNECTED</SVINCLUDE></STATICVARIABLES></DESC></BODY> </ENVELOPE>";
    
    var requestMessage = new HttpRequestMessage(HttpMethod.Post, destinationUrl);
    requestMessage.Content = new StringContent(requestXml, System.Text.Encoding.UTF8, System.Net.Mime.MediaTypeNames.Text.Xml);
    requestMessage.Headers.AcceptEncoding.Add(new StringWithQualityHeaderValue("identity"));
    requestMessage.Headers.Add("ID", "TPGETCOMPANIES");
    requestMessage.Headers.Add("SOURCE", "EA");
    requestMessage.Headers.Add("TARGET", "TNS");
    
    var response = await Http.SendAsync(requestMessage).ConfigureAwait(false);
    
    // Check the status code:
    if (!response.IsSuccessStatusCode) return "Problem in getting resp";
    
    // Or, to throw an exception:
    // response.EnsureSuccessStatusCode();
    
    return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}


Karthik_Mahalingam

5