Skip to main content
 首页 » 编程设计

c#之如何在 ASP.NET 4.5 WebForms 中异步执行两个同步的 I/O 绑定(bind)任务

2024年01月26日32JustinYoung

如何异步执行以下两个方法(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); 
        } 
    } 
} 

请您参考如下方法:

最好的方法是使用异步数据库访问(例如 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; 
    } 
} 

然后您可以使用 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!"; 
    } 
} 

在此示例中,为简单起见,我使用了 async void,但 ASP.NET 团队更喜欢您使用 PageAsyncTask as described in the tutorial .