0

This is only the idea on what im doing in a window service. I get the idea from this video to do it in parallel processing.

I have two different method and a model class.

Model Class code:

public class Email(){
    public string Recipient { get; set; }
    public string Message { get; set; }
}

Methods is something like this:

public void LoadData(){
    while(Main.IsProcessRunning){
        // 1. Get All Emails
        var emails = new dummyRepositories().GetAllEmails(); //This will return List<Emails>.
        // 2. Send it
        // After sending assume that the data will move to other table so it will not be query again for the next loop.
        SendDataParallel(emails);//this will function async? even though the calling method is sync.

        // This will continue here or wait until it already send?
        // If it will continue here even though it will not send already
        // So there's a chance to get the email again for the next loop and send it again?
    }
}

//This will send email at parallel
public async void SendDataParallel(IList<Email> emails){
    var allTasks = emails.Select(SendDataAsync);
    await TaskEx.WhenAll(allTasks);
}

//Assume this code will send email asynchronously. (this will not send email, for sample only)
public async void SendDataAsync(Email email){
    using (var client = new HttpClient())
    {
        client.PostAsync(email);
    }
}

I only want to get all queued emails then send it in parallel then wait until it already send. I'm avoiding using foreach on every email that I get.

jmvtrinidad
  • 3,347
  • 3
  • 22
  • 42

2 Answers2

1

Doesn't your compiler highlight your code with errors?

If you mark your method as async while it doesn't return any value, you should set your return type as Task, not void:

public async Task SendDataParallel(IList<Email> emails){
    var allTasks = emails.Select(SendDataAsync);
    await Task.WhenAll(allTasks);
}

Your second method also shoud return a Task, otherwise what you want to (a)wait in the first method?

public async Task SendDataAsync(Email email){
    using (var client = new HttpClient())
    {
        return client.PostAsync(email);
    }
}

Now you can Select all your SendDataAsync tasks in SendDataParallel and .Wait() it's task in LoadData in synchronious mode:

public void LoadData(){
    while(Main.IsProcessRunning){
        var emails = new dummyRepositories().GetAllEmails(); //This will return List<Emails>.
        SendDataParallel(emails).Wait();
    }
}

More information you can find reading answers in other SO questions and docs on MSDN:

And as you used LINQ's Select() which is based on foreach cycle next article also could be useful: Nested task inside loop

Community
  • 1
  • 1
Nozim Turakulov
  • 869
  • 1
  • 9
  • 19
  • I will use an wait() on my LoadData().., I think it will have an error on SendDataAsync, there is no await keyword on return.., Anyway thanks for your solution.,. – jmvtrinidad Aug 17 '15 at 10:43
1

Lets start at the bottom:

  1. You dispose your client before you actually finish receiving the HttpResponseMessage asynchronously. You'll need to make your method async Task and await inside:

    public async Task SendDataAsync(Email email)
    {
        using (var client = new HttpClient())
        {
            var response = await client.PostAsync(email);
        }
    }
    
  2. Currently, your SendDataParallel doesn't compile. Again, it needs to return a Task:

    public Task SendEmailsAsync(IList<Email> emails)
    {
        var emailTasks = emails.Select(SendDataAsync);
        return Task.WhenAll(allTasks);
    }
    
  3. At the top, you'll need to await on SendEmailsAsync:

    public async Task LoadDataAsync()
    {
        while (Main.IsProcessRunning)
        {
            var emails = new dummyRepositories().GetAllEmails(); 
            await SendEmailsAsync(emails);
        }
    }
    

Edit:

If you're running this inside a windows service, you can offload it to Task.Run and use the async keyword:

var controller = new Controller();
_processThread = Task.Run(async () => await controller.LoadDataAsync());
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321