2015-11-19 62 views
1

好吧,我需要一些澄清和驗證,以確定是否建議在服務器上實現異步,以及如何實現。WCF Restful Service - 實現異步操作

首先,這裏是我服務的一些細節:

  • 託管在IIS 8.5服務器2012 R2的服務器上。
  • 使用.NET 4.5,可以使用4.6或更高版本。這裏沒有限制。
  • WCF Restful service。併發模式=每次調用。
  • 客戶端是一個移動應用程序,已經在等待我的服務的每個服務操作調用。
  • 字面上,每個方法都會調用數據庫,另一個Web服務(而不是異步Web服務)或生成PDF。我是認真的。每一個。單。呼叫。
  • 想使用基於任務的異步操作。

現在,考慮到上述情況,我發現使服務操作異步將有助於I/O操作(即長時間運行的數據庫,外部Web服務調用,pdf生成等)。但是,我似乎無法就如何做到這一點達成良好的共識。

Stephen很顯然,他似乎是一個非常有知識的人,但他的一個博客說,從來沒有使用任何Web服務Task.Run,​​我會假設我將不得不使用的方法使數據庫/ Web服務調用我的自己的WCF服務,以使其異步。 (來源:http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html)。他建議使用Task.FromResult?我的結果不能/不應該被緩存?

所以,當我的服務得到一個請求時,它顯然會爲該請求創建一個線程。而且由於每個請求都會進行一個或多個數據庫調用,因此將會有一個I/O操作。我希望該線程去服務另一個人傳入的請求,而不是綁定在該I/O操作上,因此需要使用異步服務操作,並且一旦該數據庫調用完成(I/O操作),線程會選擇在原始請求停止的地方。我如何在代碼中完成此操作?

這是一個當前(明顯)同步版本的代碼示例。如上所述,我需要做些什麼才能實現異步?

我猜我只是異步這個服務操作,並等待MobileData.GetNoteAttachmentData的調用。在GetNoteAttachmentData中我需要做什麼?

示例服務操作:

public NoteAttachmentContract GetNoteAttachmentData(string annotationId) 
    { 
     DataSet NoteAttachmentData = null; 
     MobileData MobileData = new MobileData(); 
     NoteAttachmentContract Result = null; 
     TokenContract CurrentToken = MobileData.GetToken(); 

     try 
     { 
      NoteAttachmentData = MobileData.GetNoteAttachmentData(CurrentToken, annotationId); 

      if (NoteAttachmentData != null && NoteAttachmentData.HasData()) 
      { 
       DataRow NoteAttachmentRecord = NoteAttachmentData.Tables[0].Rows[0]; 

       string DocumentBody = NoteAttachmentRecord["documentbody"].ToString(); 
       string NoteId = NoteAttachmentRecord["annotationid"].ToString(); 
       string FileName = NoteAttachmentRecord["filename"].ToString(); 

       Result = new NoteAttachmentContract(DocumentBody, FileName, NoteId.IsGuid(false) ? new Guid(NoteId) : (Guid?)null); 
      } 
     } 
     catch (MobileServiceException ex) 
     { 
      throw ex; 
     } 
     catch (Exception ex) 
     { 
      throw new MobileServiceException(ex.Message, CurrentToken); 
     } 
     finally 
     { 
      if (NoteAttachmentData != null) 
      { 
       NoteAttachmentData.Dispose(); 
       NoteAttachmentData = null; 
      } 
     } 

     return Result; 
    } 



public DataSet GetNoteAttachmentData(TokenContract token, string annotationId) 
{ 
    DataSet Result = null; 
    SqlCommand Command = null; 

    try 
    { 
     using (SqlConnection connection = new SqlConnection(token.ConnectionString)) 
     { 
      SqlParameter AnnotationIdParameter = new SqlParameter(); 
      AnnotationIdParameter.SqlDbType = SqlDbType.UniqueIdentifier; 
      AnnotationIdParameter.ParameterName = "@AnnotationId"; 
      AnnotationIdParameter.Value = new Guid(annotationId); 

      connection.Open(); 
      Command = new SqlCommand(Properties.Resources.GetNoteAttachmentData, connection); 
      Command.Parameters.Add(AnnotationIdParameter); 

      using (SqlDataAdapter adapter = new SqlDataAdapter(Command)) 
      { 
       adapter.Fill(Result); 
       Command.Parameters.Clear(); 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
     if (Result != null) 
     { 
      Result.Dispose(); 
      Result = null; 
     } 

     throw ex; 
    } 
    finally 
    { 
     if (Command != null) 
     { 
      Command.Parameters.Clear(); 
      Command.Dispose(); 
     } 
    } 

    return Result; 
} 

回答

1

在服務中使用異步操作的全部意義在於釋放線程時,你正在做的是在等待着什麼。如果你的服務代碼只做同步工作,那麼Task.Run()允許你釋放當前的線程,但最終只是將一個線程轉移到一個線程上,而不會執行任何其他線程。然後,您只需添加額外的工作來處理管理異步操作。除非您的操作調用的任何方法具有異步等價物,否則最好保持原樣。例如,是否有一個返回任務的MobileData.GetNoteAttachmentDataAsync方法?如果有,請使您的方法異步並等待來自該方法的響應。

+0

GetNoteAttachmentData在同一臺確切的服務器上運行。我將該代碼放在相同的代碼標記中。所以我完全控制了服務器所有的代碼,因爲它都是從服務本身運行的。數據庫調用?來自服務上的業務對象,因此是「MobileData」對象。 因此,據說,我怎樣才能使GetNoteAttachmentData(它運行在相同的服務,目前在同一個線程上)是異步?我是不是該?根據你剛纔所說的原因,它所做的只是在執行I/O工作時拉另一個線程來保持它,這是反生產的。 – Reshaos

+0

如果這是真的,爲什麼要做異步方法呢?即使執行I/O工作,爲什麼不保持所有Web服務方法同步?任務僅對UI應用程序有用,只能用於Web服務的後臺工作? – Reshaos

+0

在低級別的win32 API中,所有I/O操作都有異步變化。所以任何調用I/O API的應該調用異步版本。大多數(如果不是全部的話)封裝本地I/O調用的框架API會暴露異步變體。例如,[FileStream](https://msdn.microsoft.com/en-us/library/system.io.filestream%28v=vs.110%29.aspx)類具有ReadAsync方法。在某處,有一些代碼調用I/O方法,應該切換到使用異步版本,然後冒泡異步,以便您可以等待。 – MattC