WCF Restful Service - 实现异步操作

时间:2015-11-19 19:34:00

标签: c# web-services wcf asynchronous task

好吧,我需要澄清和验证是否建议在服务器上实现异步以及如何实现。

首先,以下是我服务的一些细节:

  • 在使用Server 2012 R2的服务器上的IIS 8.5中托管。
  • 使用.NET 4.5,可以使用4.6或更高版本。这里没有限制。
  • WCF Restful服务。并发模式=每次呼叫。
  • 客户端是一个移动应用程序,已经在等待我的服务的每个服务操作调用。
  • 从字面上看,每个方法都调用数据库,另一个Web服务(不是异步Web服务)或生成PDF。我是认真的。每一个。单。调用
  • 想使用基于任务的异步操作。

现在,考虑到上述情况,我读到使服务操作异步将有助于I / O操作(即长时间运行数据库,外部Web服务调用,pdf生成等)。但是,我似乎无法就如何做到这一点找到一个很好的共识。

Stephen Clearly似乎是一个知识渊博的人,但是他的一篇博客说永远不会在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 个答案:

答案 0 :(得分:1)

在服务中使用异步操作的全部意义在于,当您所做的一切都在等待某事时,可以释放该线程。如果您的服务代码只进行同步工作,那么Task.Run()允许您释放当前线程但最终只是将保持转移到不对其他线程执行任何操作的线程。然后,您只需增加处理异步操作所需的额外工作的开销。除非您的操作调用的任何方法具有异步等效,否则最好保留原样。例如,是否有一个返回任务的MobileData.GetNoteAttachmentDataAsync方法?如果有,请使您的方法异步并等待该方法的响应。