如何异步在ASP.NET 4.5 WebForms中执行两个同时进行的I/O绑定任务?

Blu*_*Sky 1 c# asp.net asynchronous async-await .net-4.5

如何异步执行以下两种方法(StoreInSql,StoreInOtherDatabase),然后在设置标签输出消息之前等待两个结果都返回?可以使用await关键字干净地完成吗?非常感谢你.

using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.RetryPolicies;
using Microsoft.WindowsAzure.Storage.Table;
using System;
using System.Web.UI;

namespace UpdateStorage
{
    public partial class _Default : Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            string email = "test@test.com";

            // It takes approximately 300 ms to store in SQL Azure
            bool sqlStorageSuccessful = MyAppStorage.StoreInSqlAzureViaEF(email);

            // It takes approximately 300 ms to store in Azure Table Storage
            bool otherdbStorageSuccessful = MyAppStorage.StoreInAzureTableStorage(email);

            if (sqlStorageSuccessful && otherdbStorageSuccessful)
            {
                labelOutputMessage.Text = "Successfully stored the email.";
            }
            else
            {
                labelOutputMessage.Text = "We couldn't store the email, sorry!";
            }

            // 300ms + 300ms = It takes 600ms for this Page_Load method to complete.
            // How can I write it using the "await" keyword so that it only takes ~ 300ms?
        }
    }
    public static class MyAppStorage
    {
        public static bool StoreInSqlAzureViaEF(string s)
        {
            try
            {
                using (MyDataModelContainer db = new MyDataModelContainer())
                {
                    Email e = new Email();
                    e.EmailAddress = s;
                    db.SaveChanges();
                }
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }
        public static bool StoreInAzureTableStorage(string s)
        {
            try
            {
                AzureEmailMessage a = new AzureEmailMessage();
                a.EmailAddress = s;
                a.Save();
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }
    }
    public static class AzureStorage
    {
        private static string _ConnectionString = "DefaultEndpointsProtocol=http;AccountName=myaccount;AccountKey=mykey";

        static AzureStorage() { }

        private static CloudTable GetTableRef(string tableName)
        {
            CloudStorageAccount account = CloudStorageAccount.Parse(_ConnectionString);
            CloudTableClient tableClient = account.CreateCloudTableClient();
            IRetryPolicy linearRetryPolicy = new LinearRetry(TimeSpan.FromSeconds(2), 10);
            tableClient.RetryPolicy = linearRetryPolicy;
            CloudTable table = tableClient.GetTableReference(tableName);
            table.CreateIfNotExists();
            return table;
        }
        public static bool SaveObject(ITableEntity entity)
        {
            try
            {
                string tableName = entity.GetType().ToString();
                int lastNs = tableName.LastIndexOf(".");
                if (lastNs > 0)
                {
                    tableName = tableName.Substring(lastNs + 1);
                }
                CloudTable table = GetTableRef(tableName);
                TableOperation insertOperation = TableOperation.Insert(entity);
                table.Execute(insertOperation);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
    public class AzureEmailMessage : TableEntity
    {
        public string EmailAddress { get; set; }

        public AzureEmailMessage() { }

        public bool Save()
        {
            return AzureStorage.SaveObject(this);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 6

最好的方法是使用异步数据库访问(例如,EF6):

public static class MyAppStorage
{
    public static Task<bool> StoreInSqlAsync(string s)
    {
        return FakeStorageJobAsync(s);
    }
    public static Task<bool> StoreInOtherDatabaseAsync(string s)
    {
        return FakeStorageJobAsync(s);
    }

    private static async Task<bool> FakeStorageJobAsync(string s)
    {
        // This simulates waiting on a SQL database, or a web service, or any other storage task.
        await Task.Delay(300);
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用Task.WhenAll和自然地消耗它们await:

protected async void Page_Load(object sender, EventArgs e)
{
    string email = "test@test.com";

    bool[] success = await Task.WhenAll(MyAppStorage.StoreInSqlAsync(email),
        MyAppStorage.StoreInOtherDatabaseAsync(email));
    if (success[0] && success[1])
    {
        labelOutputMessage.Text = "Successfully stored the email.";
    }
    else
    {
        labelOutputMessage.Text = "We couldn't store the email, sorry!";
    }
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我使用的async void是简单,但ASP.NET团队更喜欢PageAsyncTask 按照教程中的描述使用.