[英]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.