Andrew Simpson
Andrew Simpson

Reputation: 7324

Handling multiple nested asyncs

I am having an issue working with async methods - namely nested async.

I start off a background task:

public sealed class StartupTask : IBackgroundTask
{
    public async void Run(IBackgroundTaskInstance taskInstance)
    {
        taskInstance.GetDeferral();
        ServerWorkers.WebServer server = new ServerWorkers.WebServer();
        await ThreadPool.RunAsync(workItem =>
         {
             AnotherSync.Get();
             server.Start();
         });
    }

    public static async void Get()
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri(Shared.URL);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(Shared.HeaderType));
            using (var response = await client.GetAsync(route + "?" + GeneralTags.COMPANY_REF + "=" + ApplicationObject.CompanyRef)) //.Result)
            {
                if (response.IsSuccessStatusCode)
                {
                    ApplicationObject.PrintData = JsonConvert.DeserializeObject<Model.Print>(response.Content.ReadAsStringAsync().Result);
                }
                else
                {
                    evError(new Exception(String.Format("{0}: {1}", (int)response.StatusCode, response.ReasonPhrase)), ErrorTags.PRINT_GET);
                }
            }
        }
    }

internal class WebServer
{
    private const uint BufferSize = 8192;

    public void Start()
    {
        StreamSocketListener listener = new StreamSocketListener();

        listener.BindServiceNameAsync("8080");

        listener.ConnectionReceived += async (sender, args) =>
        {
            StringBuilder request = new StringBuilder();
            using (IInputStream input = args.Socket.InputStream)
            {
                byte[] data = new byte[BufferSize];
                IBuffer buffer = data.AsBuffer();
                uint dataRead = BufferSize;
                while (dataRead == BufferSize)
                {
                    await input.ReadAsync(buffer, BufferSize, InputStreamOptions.Partial);
                    request.Append(Encoding.UTF8.GetString(data, 0, data.Length));
                    dataRead = buffer.Length;
                }
            }

            using (IOutputStream output = args.Socket.OutputStream)
            {
                using (Stream response = output.AsStreamForWrite())
                {
                    byte[] bodyArray = Encoding.UTF8.GetBytes("<html><body>Hello, World!</body></html>");
                    var bodyStream = new MemoryStream(bodyArray);

                    var header = "HTTP/1.1 200 OK\r\n" +
                                $"Content-Length: {bodyStream.Length}\r\n" +
                                    "Connection: close\r\n\r\n";

                    byte[] headerArray = Encoding.UTF8.GetBytes(header);
                    await response.WriteAsync(headerArray, 0, headerArray.Length);
                    await bodyStream.CopyToAsync(response);
                    await response.FlushAsync();
                }
            }
        };
    }
}

Then my app acts a web server.. It does not exit out.

If I add this so I have:

  public async void Run(IBackgroundTaskInstance taskInstance)
    {
        taskInstance.GetDeferral();
        ServerWorkers.WebServer server = new ServerWorkers.WebServer();
        await ThreadPool.RunAsync(workItem =>
         {
             AnotherSync.Get();
             AnotherSync.Get();
             server.Start();
         });
    }

internal  class AnotherSync
{
    public static event delError evError;
    private const string route = "/api/Print";

    static wsPrint.IPrint wsPrint = new wsPrint.PrintClient();

    public static void Get()
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri(Shared.URL);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(Shared.HeaderType));
            using (var response =  client.GetAsync(route + "?" + GeneralTags.COMPANY_REF + "=" + ApplicationObject.CompanyRef).Result)
            {
                if (response.IsSuccessStatusCode)
                {
                    ApplicationObject.PrintData = JsonConvert.DeserializeObject<Model.Print>(response.Content.ReadAsStringAsync().Result);
                }
                else
                {
                    evError(new Exception(String.Format("{0}: {1}", (int)response.StatusCode, response.ReasonPhrase)), ErrorTags.PRINT_GET);
                }
            }
        }
    }       
}

then the application exists out.

I may be mistaken but is it because I am using nested async methods?

Upvotes: 1

Views: 202

Answers (1)

MikeT
MikeT

Reputation: 5500

This is an example of what a thread should look like,

public sealed class StartupTask : IBackgroundTask
{
    //has to be declared here to keep the handle alive and prevent garbage collection
    private ServerWorkers.WebServer server = new ServerWorkers.WebServer();



    public async void Run(IBackgroundTaskInstance taskInstance)
    {
        //Start the server running no need for await as its an synchronous
        server.Start();

        //don't exit until work is compelted
        while(server.Running)
        {
            //give up processor and allow other work to occur while you are waiting
            await Task.Yield();
        }
    }

    internal class WebServer
    {
        private const uint BufferSize = 8192;
        private StreamSocketListener listener;
        public bool Running { get; private set;}= false;

        public void Start()
        {
            Lock(this){//prevent any other code interupting
                if(!Running )//prevent multiple starts
                {
                    listener = new StreamSocketListener();
                    listener.BindServiceNameAsync("8080");
                    listener.ConnectionReceived += listener_ConnectionReceived;
                    Running = true;
                }
            }
        }
        public void Stop()
        {
            Lock(this){//prevent any other code interupting
                listener.Close();
                listener.Dispose();
                listener = null;
                Running = false;
            }
        }
        public void listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
        { 
            //process data from listerner's event
        }
    }
}

Note i'm not using the Windows Application Framework so might be different there

Upvotes: 1

Related Questions