WCF Restful服务-实现异步操作
本文关键字:实现 异步操作 服务 Restful WCF | 更新日期: 2023-09-27 18:22:50
好吧,我需要澄清和验证是否建议在服务器上实现异步以及如何实现。
首先,这里是我的服务的一些细节:
- 在服务器2012 R2上的IIS 8.5中托管
- 使用.NET 4.5,可以使用4.6或更高版本。这里没有限制
- WCF Restful服务。并发模式=每次调用
- 客户端是一个移动应用程序,已经在等待对我的服务的每次服务操作调用
- 实际上,每个方法都调用一个数据库、另一个web服务(而不是异步web服务)或生成PDF。我不是在开玩笑。每一个仅有一个的打电话
- 希望使用基于任务的异步操作
现在,考虑到以上内容,我读到使服务操作异步将有助于I/O操作(即长时间运行的数据库、外部web服务调用、pdf生成等)。然而,我似乎无法就如何做到这一点达成良好的共识。
Stephen显然是一个知识渊博的人,但他的一个博客说永远不要使用Task.在web服务上运行,我认为我必须在我自己的WCF服务上调用数据库/web服务的方法上使用它,以便使其异步。(来源:http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html)。他建议使用Task.FromResult?但是我的结果不能/不应该被缓存?
因此,当我的服务收到请求时,它显然会为该请求创建一个线程。实际上,每个请求都会进行一个或多个数据库调用,因此会有一个I/O操作。我希望该线程为另一个人的传入请求提供服务,而不是被束缚在I/O操作上,因此异步服务操作是关键,一旦数据库调用完成(I/O操作),线程就会从原始请求中断的地方开始。我到底该如何在代码中实现这一点?
以下是当前(显然)同步版本代码的示例。如上所述,我需要做些什么来使它异步?
我想我只会异步这个服务操作,然后等待对MobileData.GetNoteAttachmentData的调用。在GetNoteAttachment Data中我要做什么?
服务操作示例:
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;
}
在服务中使用异步操作的全部目的是在您所做的一切都在等待时释放线程。如果你的服务代码只做同步工作,那么Task.Run()允许你释放当前线程,但最终只是将对一个线程的保留转移到另一个线程。然后,您只是在增加管理异步操作所需的额外工作的开销。除非操作调用的任何方法都具有异步等效方法,否则最好保持原样。例如,是否存在返回Task的MobileData.GetNoteAttachmentDataAsync方法?如果存在,请使您的方法异步,并等待该方法的响应。