ASP.NET - 异步 - 在其他两个系统之间同步的系统

时间:2017-06-27 14:15:15

标签: asp.net vb.net asynchronous asp.net-web-api async-await

我正在尝试创建一个在两个其他系统之间同步的系统。数据

我使用VB处理ASP.NET Web窗体(无法更改)

主要系统功能将采用Web API的形式,由计划任务或其他事件(如网站表单或登录页面)触发。

这些函数中的每一个都调用系统1的REST API和系统2的REST API,操作数据,然后调用每个系统REST API以更新双方。

我选择使用ASP.NET Web Api 2作为主系统,使用HttpClient调用函数。

每天将有数十万笔交易。这是很多!所以我选择对HttpClient使用async / await方法(因为同时有很多长处理请求),但是ASP.NET似乎迫使我从下到上转换所有函数,包括Web Api函数和数据库访问到异步

所以我最终将所有函数更改为Async,并且在调用它们的所有函数中,我使用Await来处理所有内容。

一切似乎都有效。我不知道我所做的是否正确,而且我发现我无法检查我的功能是否实际上是异步工作。

关于ConfigureAwait(False)我添加了它,因为我没有与上下文相关的操作。如果有,我将删除此声明。我读过它建议在可能的时候使用它。 (我是对的吗?)

小评论 为什么我的解决方案很好???我试图通过创建更多的工作线程来避免阻塞主线程。为什么这是更好的解决方案?我创造了许多等待每个人开始工作的人。这不是一个比共时解决方案更糟糕的做法吗?

有人可以告诉我,我在做什么是正确的,如果没有 - 请解释为什么或者是否有其他方法来解决这个问题?

以下是代码示例(仅限相关部分)。对你所看到的一点解释:

  • WebApi控制器具有登录功能
  • Login函数以异步方式调用System1.DoSomething
  • System1.DoSomething调用私有函数 System1.SetCredentials异步
  • System1.DoSomething也使用HttpHandler来获取数据 异步来自System1的API
  • System1.SetCredentials函数异步调用MyLoginManager.GetCredentials
  • MyLoginManager.GetCredentials使用DBHelper.ExecuteReaderAsync异步调用数据库
  • DBHelper.ExecuteReaderAsync函数调用ExecuteReaderAsync 异步并且还使用异步打开连接 OpenAsync()函数

WebAPI控制器

     Public Class WebApiController
   Inherits ApiController
     Public Async Function Login() As Threading.Tasks.Task(Of IHttpActionResult)
        Dim result As MyResult= Await System1.DoSomething().ConfigureAwait(False)
     End Function

System1类

 Public Class System1
    Public Shared Async Function DoSomething() As Task(Of MyResult)
        Try
            Using client As New HttpClient
                client.BaseAddress = New Uri("blablabla")
                Await SetCredentials(client).ConfigureAwait(False)
                Dim response As HttpResponseMessage = Await client.GetAsync(urlParameters).ConfigureAwait(False)

                ... More code
            End Using
        Catch ex As Exception
        End Try
    End Function

 Private Shared Async Function SetCredentials(client As HttpClient) As Task
            Dim auth As BasicAuthenticationData = Await MyLoginManager.GetCredentials.ConfigureAwait(False)
            Dim credentials As String = Cryptography.EncodeBase64(String.Format("{0}\{1}:{2}", auth.userName, auth.userPassword))
            client.DefaultRequestHeaders.Add("Authorization", "Basic " & credentials)

            ... More code
        End Function
    End Class

MyLoginManager类

  Public Class MyLoginManager
  Public Shared Async Function GetCredentials() As Threading.Tasks.Task(Of BasicAuthenticationData)
            Dim auth As New BasicAuthenticationData

            Dim dbConn As String = DBConnection.GetConnection(True)
            Dim q As String = "SELECT * FROM BlaBlaBla"

            Using sdr As SqlDataReader = Await DBHelper.ExecuteReaderAsync(dbConn, q, Nothing).ConfigureAwait(False)
                 ... More code
            End Using

            Return auth
        End Function
End Class

DBHelper类

Public Class DBHelper
    Public Shared Async Function ExecuteReaderAsync(ByVal dbConnection As String, ByVal commandText As String, ByVal params() As SqlParameter) As Threading.Tasks.Task(Of SqlDataReader)
            Dim dbConnectionAsync As String = New SqlConnectionStringBuilder(dbConnection) With {
                .AsynchronousProcessing = True
            }.ToString

            Dim objConn As New SqlConnection(dbConnectionAsync)

            Dim oc As New SqlCommand(commandText, objConn)
            Dim sdr As SqlDataReader

            ' Throws a custom exception if there is a problem
            Try

                Await oc.Connection.OpenAsync.ConfigureAwait(False)
                sdr = Await oc.ExecuteReaderAsync(CommandBehavior.CloseConnection).ConfigureAwait(False)

                Return sdr
            Catch ex As Exception
            End Try
        End Function
End Class

2 个答案:

答案 0 :(得分:2)

您应该向ConfigureAwait(false)添加一个调用,以便在任何控制器操作产生的任何等待之后等待。

Mister Epic said,如果您调用HttpContext.Current,则会遗漏ConfigureAwait(false)之类的内容,而您不应该对控制器操作方法执行此操作。但这也意味着每次你不进行上下文切换。

你应该做的是将控制器动作方法中的逻辑提取到他们自己的方法(最好是在他们自己的类中)并传递他们工作所需的每一件事。

所以,你唯一做错的就是在控制器动作方法中调用ConfigureAwait(false)

答案 1 :(得分:1)

不要在您的网络API项目中添加ConfigureAwait。在库代码中使用它。

最重要的是,当您调用使用ConfigureAwait的方法时,您将失去上下文。您的上下文包含会话等重要详细信息,因此您需要确保在调用使用HttpContext的库代码之前从ConfigureAwait获取所需的任何详细信息。