Click here to Skip to main content
15,891,900 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have created one web service in C# which takes 2 parameters make one XML string and send the HTTP Request to one server and reply with the response received from Server. Now my question is, how i can use Async task to handle multiple requests to my web service so all my requester get the response. following is my code for httprequest.

C#
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;
         }

    } 


What I have tried:

I have tried to host this simple service but it is not able to serve multiple request at the same time.
Posted
Updated 13-Sep-16 5:12am

1 solution

The WebService class pre-dates the Task Parallel Library, and knows nothing about async tasks.

However, it does support the older IAsyncResult / APM pattern:
How to: Create Asynchronous Web Service Methods[^]

And it's possible to implement that pattern using a Task:
Implementing the APM Pattern By Using Tasks[^]
Using Tasks to implement the APM Pattern | Parallel Programming with .NET[^]

Start with the ToApm extension method from Stephen Toub's blog post:
C#
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;
    }
}

Then, move your implementation to a private async method returning a Task<string>, and use the extension method to adapt it to the APM pattern:
C#
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();
    }
}

For the implementation, you might want to look at using the classes from the System.Net.Http namespace[^], as that provides a nicer async-aware API than the raw HttpWebRequest / HttpWebResponse classes.

However, if you do that, you should make sure you use a single static HttpClient instance for all requests, as described here: You're using HttpClient wrong and it is destabilizing your software | ASP.NET Monsters[^]
C#
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);
}
 
Share this answer
 
Comments
Karthik_Mahalingam 13-Sep-16 11:19am    
5
Revox 31-Dec-20 21:25pm    
Thank you so very much for taking the time to post this solution...and with the extension method that is no longer accessible from the web! I was having a very difficult time piecing this together from the older articles I could find but this spelled it out in very easy to follow instructions.

Very much appreciated!
Richard Deeming 5-Jan-21 3:33am    
The blog post for the extension method is still available. Unfortunately, the redirect to the new URL doesn't work, so you have to go hunting for it:
Using Tasks to implement the APM Pattern | .NET Parallel Programming[^]

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900