如何使WCF REST方法与任务并行库完全异步?

Mar*_*tin 21 c# wcf asynchronous task-parallel-library

我试图使WCF REST方法完全异步(我不想阻止任何地方).基本上我有一个简单的服务,有3层:服务,业务逻辑和数据访问层.数据访问层正在访问数据库,可能需要几秒钟才能从该方法获得响应.

我不太清楚如何链接所有这些方法的工作.有人可以帮我完成我试图在下面写的样本吗?我不太了解WCF使用的模式,我没有找到关于这个主题的很多文档.

有人可以帮我完成以下示例吗?此外,如何测量服务能够处理比典型同步实现更多的负载?

using System;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Threading.Tasks;

namespace WcfRestService1
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = 
        AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class Service1
    {
        private BusinessLogic bll = new BusinessLogic();

        // Synchronous version
        [WebGet(UriTemplate = "/sync")]
        public string GetSamples()
        {
            return bll.ComputeData();
        }

        // Asynchronous version - Begin
        [WebGet(UriTemplate = "/async")]
        [OperationContract(AsyncPattern = true)]
        public IAsyncResult BeginGetSampleAsync(AsyncCallback callback, 
            object state)
        {
            Task<string> t = bll.ComputeDataAsync();

            // What am I suppose to return here
            // return t.AsyncState; ???
        }

        // Asynchronous version - End
        public List<SampleItem> EndGetSampleAsync(IAsyncResult result)
        {
            // How do I handle the callback here?
        }
    }

    public class BusinessLogic
    {
        public Task<string> ComputeDataAsync()
        {
            DataAccessLayer dal = new DataAccessLayer();
            return dal.GetData();
        }

        public string ComputeData()
        {
            Task<string> t = this.ComputeDataAsync();

            // I am blocking... Waiting for the data
            t.Wait();

            return t.Result;
        }
    }

    public class DataAccessLayer
    {
        public Task<string> GetData()
        {
            // Read data from disk or network or db
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

JMa*_*sch 11

这是一个例子.我得到了以下帖子的帮助:

编辑:添加了异步客户端的示例

使用TPL实现经典异步模式
http://pfelix.wordpress.com/2008/06/27/wcf-and-the-asyncpattern-property-part-1/ http://pfelix.wordpress.com/2008/06/ 28/WCF和最asyncpattern部分-2 /

这是一个小小的无所事事服务:


namespace WcfAsyncTest
{
    [ServiceContract]
    public interface IAsyncTest
    {
        [OperationContract(AsyncPattern=true)]
        IAsyncResult BeginOperation(AsyncCallback callback, object state);

        string EndOperation(IAsyncResult ar);
    }

    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class Service1 : IAsyncTest
    {
        public IAsyncResult BeginOperation(AsyncCallback callback, object state)
        {
            Task result = Task.Factory.StartNew((x) =>
                {
                    // spin to simulate some work
                    var stop = DateTime.Now.AddSeconds(10);
                    while (DateTime.Now < stop)
                        Thread.Sleep(100);
                }, state);
            if (callback != null)
                result.ContinueWith(t => callback(t));
            return result;
        }

        public string EndOperation(IAsyncResult ar)
        {
            ar.AsyncWaitHandle.WaitOne();
            return "Hello!!";
        }
    }
}


这是客户端(命令行):


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestClient
{
    class Program
    {
        static void Main(string[] args)
        {
            var client = new ServiceReference1.AsyncTestClient();
            var result = client.Operation();
            Console.WriteLine(result);
            Console.ReadLine();
        }
    }
}

如果你在服务上放置跟踪点,你可以看到WCF真正为你调用EndOperation.

异步客户端示例

首先,您需要生成异步代理.您可以通过右键单击"服务引用"(在项目的"引用"文件夹中),然后选择"配置服务引用"来完成此操作.选中"生成异步操作"复选框.

现在,您的客户端代理将拥有一些以前不存在的新成员.以下是如何使用它们:


// this is in the command-line test client
// no changes to your service required.
static void AsyncTest()
{
  var client = new ServiceReference1.AsyncTestClient();
  client.OperationCompleted += new EventHandler(client_OperationCompleted);
  client.OperationAsync();
  Console.WriteLine("Operation Running");
}

static void client_OperationCompleted(object sender, ServiceReference1.OperationCompletedEventArgs e)
{
  if (e.Error == null)
    Console.WriteLine("Operation Complete.  Result: " + e.Result);
  else
    Console.WriteLine(e.Error.ToString());
}


  • @ np-hard:拥有End块是MS的异步模型标准的一部分(http://msdn.microsoft.com/en-us/library/ms228963.aspx)因为wcf在完成之前不会调用EndOperation,在这种情况下,呼叫永远不会阻止.但是,它是有效的(在非wcf用例中)调用BeginOperation,执行某些操作,然后调用EndOperation(),期望您将被阻塞直到操作完成(有关更详细的说明,请参阅上面的链接) . (2认同)