给定此接口
[ServiceContract]
public interface IProductService
{
[OperationContract]
Product Get(int id);
}
我想手动(也就是说,在VS中不使用scvutil或Add Service Reference)创建一个客户端代理。
我用以下方法
public class ProductService: IProductService
{
readonly ChannelFactory<IProductService> factory;
public ProductService()
{
factory = new ChannelFactory<IProductService>("*");
}
public Product Get(int id)
{
var channel = factory.CreateChannel();
return channel.Get(id);
}
}
我的问题是我还想要这个方法的异步/等待版本,只有在客户端,服务器端仍然是同步的。
我希望这是一个通用解决方案,因为我有很多这种方法和服务。
如果使用ChannelFactory
允许异步等待,则接口需要返回Task
或Task<T>
。
它将强制您的服务器端也返回一个任务,但如果您坚持保持同步,则可以与Task.CompletedTask
和Task.FromResult
同步返回任务(尽管如果您有选择,为什么要这样做)。
例如:
[ServiceContract]
interface IProductService
{
[OperationContract]
Task<Product> GetAsync(int id);
}
class ProductService : IProductService
{
ChannelFactory<IProductService> factory;
public ProductService()
{
factory = new ChannelFactory<IProductService>("*");
}
public Task<Product> GetAsync(int id)
{
var channel = factory.CreateChannel();
return channel.GetAsync(id);
}
}
class ProductAPI : IProductService
{
public Task<Product> GetAsync(int id) => Task.FromResult(Get(id))
}
您实际上可以在不更改服务本身的情况下做到这一点。您可以简单地定义第二个接口,该接口包含方法的异步和Task
返回版本,并标记有[ServiceContract(Name = "NameOfTheIterfaceWhichIsActuallyExposedOnTheServer")]
在您提到的示例中,您将使用GetAsync()
操作定义第二个接口:
[ServiceContract(Name = "IProductService")]
public interface IProductServiceAsync
{
[OperationContract]
Task<Product> GetAsync(int id);
}
即使你的服务仍然实现并公开了IProductService
,你也可以使用ChannelFactory<IProductServiceAsync>
来调用它。只要方法名称与GetFoo
/GetFooAsync
模式匹配,一切都会正常工作。这就是Visual Studio中添加服务引用可以为您生成对同步服务的异步服务引用的方法。
请参阅使用ChannelFactory异步调用同步WCF方法,以获得有关其工作方式的更详细解释。