【问题标题】:WCF Restful Service - Implement Asynchronous OperationsWCF Restful 服务 - 实现异步操作
【发布时间】:2015-11-19 19:34:00
【问题描述】:

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

首先,这里是我的服务的一些细节:

  • 在装有 Server 2012 R2 的服务器上托管在 IIS 8.5 中。
  • 使用 .NET 4.5,可以使用 4.6 或更高版本。这里没有限制。
  • WCF Restful 服务。并发模式 = 每次调用。
  • 客户端是一个移动应用程序,已经在等待对我的服务的每个服务操作调用。
  • 实际上,每个方法都会调用数据库、另一个 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;
}

【问题讨论】:

    标签: c# web-services wcf asynchronous task


    【解决方案1】:

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

    【讨论】:

    • GetNoteAttachmentData 在同一台服务器上运行。我将该代码放在同一个代码标签中。所以我可以完全控制服务器接触的所有代码,因为它们都是从服务本身运行的。数据库调用?来自服务上的业务对象,因此是“MobileData”对象。话虽如此,我怎样才能使 GetNoteAttachmentData (目前在同一个服务上运行,在同一个线程上)是异步的?我是不是该?因为根据你刚才所说的,它所做的只是在它执行 I/O 工作时拉另一个线程来保持它,这会适得其反。
    • 如果这是真的,为什么还要创建异步方法呢?为什么不让所有 Web 服务方法保持同步,即使它们执行 I/O 工作?任务是否仅对 UI 应用程序有用,并且仅用于 Web 服务的后台工作?
    • 在底层 win32 api 中,所有 I/O 操作都有异步变化。所以任何调用 I/O api 的东西都应该调用异步版本。大多数(如果不是全部)包装原生 I/O 调用的框架 API 都暴露了异步变体。例如,FileStream 类有一个 ReadAsync 方法。在某处,有一些代码调用了 I/O 方法,应该切换到使用异步版本,然后冒泡异步,以便您可以等待它。
    猜你喜欢
    • 2016-01-02
    • 2010-12-25
    • 2014-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-16
    • 2012-04-26
    • 1970-01-01
    相关资源
    最近更新 更多