繁体   English   中英

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

[英]How to make a WCF REST method entirely asynchronous with the 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
        }
    }
}

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

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

使用TPL实现经典异步模式
http://pfelix.wordpress.com/2008/06/27/wcf-and-the-asyncpattern-property-part-1/ http://pfelix.wordpress.com/2008/06/28/wcf-and-所述-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());
}

这是实现Async的服务的实现。 在这里,wcf的回调一直传递给ado.net的sql命令。 当命令返回时,它将调用服务的EndXXX方法,该方法将调用Business层,最终将调用SqlCommand的EndXXX。 如果您遇到任何问题,请告诉我

public class Service
    {
        private BusinessLogic businessLayer = new BusinessLogic();
        public IAsyncResult BeginAnyOperation(AsyncCallback callback, object userState)
        {
            return businessLayer.BeginComputeData(callback, userState);
        }
        public string EndAnyOperation(IAsyncResult result)
        {
            return businessLayer.EndComputeDate(result);
        }
    }

    public class MyState<T> : IAsyncResult
    {
        public MyState() { }
        public object AsyncState { get; set; }
        public WaitHandle AsyncWaitHandle { get; set; }
        public bool CompletedSynchronously
        {
            get { return true; }
        }
        public bool IsCompleted { get; set; }
        public AsyncCallback AsyncCallback { get; set; }
        public T Result { get; set; }
        public IAsyncResult InnerResult { get; set; }
    }

    public class BusinessLogic
    {
        private DataAccessLayer dal = new DataAccessLayer();
        public IAsyncResult BeginComputeData(AsyncCallback callback, object state)
        {
            return dal.BeginGetData(callback, state);
        }
        public string EndComputeDate(IAsyncResult asyncResult)
        {
            return dal.EndGetData(asyncResult);
        }
    }

    public class DataAccessLayer
    {
        public IAsyncResult BeginGetData(AsyncCallback callback, object state)
        {
            var conn = new SqlConnection("");
            conn.Open();
            SqlCommand cmd = new SqlCommand("myProc", conn);
            var commandResult = cmd.BeginExecuteReader(callback, state, System.Data.CommandBehavior.CloseConnection);
            return new MyState<string> { AsyncState = cmd, InnerResult = commandResult };
        }
        public string EndGetData(IAsyncResult result)
        {
            var state = (MyState<string>)result;
            var command = (SqlCommand)state.AsyncState;
            var reader = command.EndExecuteReader(state.InnerResult);
            if (reader.Read())
                return reader.GetString(0);
            return string.Empty;
        }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM