好吧,我需要一些澄清和驗證,以確定是否建議在服務器上實現異步,以及如何實現。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;
}
GetNoteAttachmentData在同一臺確切的服務器上運行。我將該代碼放在相同的代碼標記中。所以我完全控制了服務器所有的代碼,因爲它都是從服務本身運行的。數據庫調用?來自服務上的業務對象,因此是「MobileData」對象。 因此,據說,我怎樣才能使GetNoteAttachmentData(它運行在相同的服務,目前在同一個線程上)是異步?我是不是該?根據你剛纔所說的原因,它所做的只是在執行I/O工作時拉另一個線程來保持它,這是反生產的。 – Reshaos
如果這是真的,爲什麼要做異步方法呢?即使執行I/O工作,爲什麼不保持所有Web服務方法同步?任務僅對UI應用程序有用,只能用於Web服務的後臺工作? – Reshaos
在低級別的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