[ASP.NET] 好用的非同步資料庫執行

摘要:[ASP.NET] 好用的非同步資料庫執行

有沒有辦法在一次的Connection Open就可以同時執行多個Command,

正常情況下ADO.NET去執行SQL的Command時都是循序的處理,

一個Connection在同一時間只可執行一個 Command,

使用非同步的資料庫執行就可以在同一間內執行多個不同的Command,

所以寫了一個簡單範例測試,

主要就是登入時會去判斷這個登入的帳號密碼是否正確,

並且同時寫入是誰登入以及他的IP,

我在資料庫中建立一個簡單的帳號Table如下:

 

 還有一個簡易的登入Log,如下:

 

在頁面方面我是用ASP.NET 2.0以上才內建的Login控制項,畫面和HTML如下

 

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>非同步執行DB</title>
</head>
<body>
    <form id="form1" runat="server">
    <div align="center">
    <asp:Login ID="Login1" runat="server" BackColor="#FFFBD6" BorderColor="#FFDFAD"  
                BorderPadding="4" BorderStyle="Solid" BorderWidth="1px" Font-Names="Verdana"  
                Font-Size="0.8em" ForeColor="#333333" Width="200px"  
            TextLayout="TextOnTop">
                <TextBoxStyle Font-Size="0.8em" />
                <LoginButtonStyle BackColor="White" BorderColor="#CC9966" BorderStyle="Solid"  
                    BorderWidth="1px" Font-Names="Verdana" Font-Size="0.8em"  
                    ForeColor="#990000" />
                <LayoutTemplate>
                    <table border="0" cellpadding="4" cellspacing="0"  
                        style="border-collapse:collapse;">
                        <tr>
                            <td>
                                <table border="0" cellpadding="0" style="width:200px;">
                                    <tr>
                                        <td align="center"  
                                            style="color:White;background-color:#990000;font-size:0.9em;font-weight:bold;">
                                            登入</td>
                                    </tr>
                                    <tr>
                                        <td>
                                            &nbsp;</td>
                                    </tr>
                                    <tr>
                                        <td align="left">
                                            <div style="float:left; width:80px; display:block;">
                                                <asp:Label ID="UserNameLabel" runat="server" AssociatedControlID="UserName">使用者名稱:</asp:Label>
                                            </div>
                                            <div style="float:left;">
                                            <asp:TextBox ID="UserName" runat="server" Font-Size="0.8em"></asp:TextBox>
                                            <asp:RequiredFieldValidator ID="UserNameRequired" runat="server"  
                                                ControlToValidate="UserName" ErrorMessage="必須提供使用者名稱。" ToolTip="必須提供使用者名稱。"  
                                                ValidationGroup="Login1">*</asp:RequiredFieldValidator>
                                            </div>
                                        </td>
                                    </tr>                                    
                                    <tr>
                                        <td align="left">
                                            <div style="float:left; width:80px; display:block;">
                                                <asp:Label ID="PasswordLabel" runat="server" AssociatedControlID="Password">密碼:</asp:Label>
                                            </div>
                                            <div style="float:left;">
                                                <asp:TextBox ID="Password" runat="server" Font-Size="0.8em" TextMode="Password"></asp:TextBox>
                                                <asp:RequiredFieldValidator ID="PasswordRequired" runat="server"  
                                                ControlToValidate="Password" ErrorMessage="必須提供密碼。" ToolTip="必須提供密碼。"  
                                                ValidationGroup="Login1">*</asp:RequiredFieldValidator>
                                            </div>
                                        </td>
                                    </tr>
                                    <tr>
                                        <td>
                                            <asp:CheckBox ID="RememberMe" runat="server" Text="記憶密碼供下次使用。" />
                                        </td>
                                    </tr>
                                    <tr>
                                        <td align="center" style="color:Red;">
                                            <asp:Literal ID="FailureText" runat="server" EnableViewState="False"></asp:Literal>
                                        </td>
                                    </tr>
                                    <tr>
                                        <td align="right">
                                            <asp:Button ID="LoginButton" runat="server" BackColor="White"  
                                                BorderColor="#CC9966" BorderStyle="Solid" BorderWidth="1px" CommandName="Login"  
                                                Font-Names="Verdana" Font-Size="0.8em" ForeColor="#990000" Text="登入"  
                                                ValidationGroup="Login1" />
                                        </td>
                                    </tr>
                                </table>
                            </td>
                        </tr>
                    </table>
                </LayoutTemplate>
                <InstructionTextStyle Font-Italic="True" ForeColor="Black" />
                <TitleTextStyle BackColor="#990000" Font-Bold="True" Font-Size="0.9em"  
                    ForeColor="White" />
            </asp:Login>
    </div>
    </form>
</body>
</html>

 

 

首先我們要在Web.config建立一個非同步的ConnectionString,

其實很簡單只是在我們平常的ConnectionString加上Asynchronous Processing=true,

因為會用到MARS(Multiple Active Result Sets),

所以需要在Web.config中的ConnectionString加上MultipleActiveResultSets=true

接著使用IAsyncResult 介面(詳細)來處理,

 

Partial Class test_Login
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Not Page.IsPostBack Then
            Me.Login1.ToolTip = "請輸入您的帳號密碼"
        End If
    End Sub

    Protected Sub Login1_Authenticate(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.AuthenticateEventArgs) Handles Login1.Authenticate
        Dim cn As New SqlConnection '設定Connect物件
        cn.ConnectionString = ConfigurationManager.ConnectionStrings("testAsy_conndb").ConnectionString
        Dim cmd1 As New SqlCommand '設定Command物件
        Dim cmd2 As New SqlCommand '設定Command物件
        Dim dr1 As SqlDataReader '設定DataReader物件
        Dim AsyncRt1, AsyncRt2 As IAsyncResult
        Dim WtHandle1, WtHandle2 As System.Threading.WaitHandle
        Dim WtHandle(1) As System.Threading.WaitHandle '包含WtHandle(0),WtHandle(1)

        cmd1.CommandText = "Select * From [Account] Where id=@id and pwd=@pwd"
        cmd1.CommandType = CommandType.Text
        cmd1.Connection = cn
        cmd1.Parameters.Add("@id", SqlDbType.NVarChar).Value = Me.Login1.UserName.ToString
        cmd1.Parameters.Add("@pwd", SqlDbType.NVarChar).Value = Me.Login1.Password.ToString

        cmd2.CommandText = "INSERT INTO [LoginLog] ([id],[pwd],[login_date],[ip])"
        cmd2.CommandText += " VALUES  (@id ,@pwd ,getdate() ,@ip)"
        cmd2.CommandType = CommandType.Text
        cmd2.Connection = cn
        cmd2.Parameters.Add("@id", SqlDbType.NVarChar).Value = Me.Login1.UserName.ToString
        cmd2.Parameters.Add("@pwd", SqlDbType.NVarChar).Value = Me.Login1.Password.ToString
        cmd2.Parameters.Add("@ip", SqlDbType.NVarChar).Value = getIP()

        cn.Open()

        AsyncRt1 = cmd1.BeginExecuteReader
        AsyncRt2 = cmd2.BeginExecuteReader

        WtHandle1 = AsyncRt1.AsyncWaitHandle
        WtHandle2 = AsyncRt2.AsyncWaitHandle

        '接下來這邊就可以指定那個指令的先後順序
        WtHandle(0) = WtHandle1
        WtHandle(1) = WtHandle2

        System.Threading.WaitHandle.WaitAll(WtHandle)
        dr1 = cmd1.EndExecuteReader(AsyncRt1)
        cmd2.EndExecuteReader(AsyncRt2)


        If dr1.HasRows Then
            FormsAuthentication.RedirectFromLoginPage(Login1.UserName, Login1.RememberMeSet)
        End If
        dr1.Close()

        cmd1.Dispose()
        cmd2.Dispose()
        cn.Close()
        cn.Dispose()
        
    End Sub

    Public Function getIP() As String
        Dim ip As String
        ip = Request.ServerVariables("HTTP_X_FORWARDED_FOR")
        If ip = String.Empty Then
            ip = Request.ServerVariables("REMOTE_ADDR")
        End If
        Return ip
    End Function

End Class

當你輸入帳號密碼後,便會同時驗證以及寫入資料

以下是寫入的資料和登入成功的畫面