【问题标题】:Async WCF call with ChannelFactory and CreateChannel使用 ChannelFactory 和 CreateChannel 进行异步 WCF 调用
【发布时间】:2014-06-27 05:33:54
【问题描述】:

我从事的项目是托管在 Web 服务器上的 Web 应用程序调用托管在应用服务器上的 WCF 服务。 WCF 调用的代理由 ChannelFactory 创建,并通过通道进行调用,例如:

(省略使用块)

var factory = new ChannelFactory<IUserService>(endpointConfigurationName);
var channel = factory.CreateChannel();

var users = channel.GetAllUsers();

如果我理解得很好,通过通道调用是异步的,并且 Web 服务器上的线程在请求​​期间处于空闲状态,只是等待响应。

我想像这样异步调用:

var users = await channel.GetAllUsersAsync();

有没有办法使用 ChannelFactory 和频道异步进行调用?我没有找到。我知道我可以通过 svcutil / 添加服务引用生成异步方法,但我不想这样做。另外我不想通过添加异步方法来更改应用服务器(IUserService)上的服务接口。

有什么方法可以调用与 ChannelFactory 异步的方法吗?谢谢。

【问题讨论】:

    标签: c# .net wcf async-await


    【解决方案1】:

    您可以使用 T4 从原始接口自动生成包含异步版本方法的新接口,并在 ChannelFactory without changing interface on server side 中使用它。

    我使用NRefactory解析原始并生成新的C#源代码,使用AssemblyReferences.tt在T4模板中使用nuget包:

    <#@ template debug="false" hostspecific="true" language="C#" #>
    <#@ include file="AssemblyReferences.tt" #>
    <#@ assembly name="System.Core" #>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="ICSharpCode.NRefactory.CSharp" #>
    <#@ output extension=".cs"#>
    <# 
    var file = System.IO.File.ReadAllText(this.Host.ResolvePath("IUserService.cs")); 
    if(!file.Contains("using System.Threading.Tasks;"))
    { #>
    using System.Threading.Tasks;
    <# } #>
    <#
    CSharpParser parser = new CSharpParser();
    var syntaxTree = parser.Parse(file);
    
    
    foreach (var namespaceDeclaration in syntaxTree.Descendants.OfType<NamespaceDeclaration>())
    {
        namespaceDeclaration.Name += ".Client";
    }
    
    
    foreach (var methodDeclaration in syntaxTree.Descendants.OfType<MethodDeclaration>())
    {
        if (methodDeclaration.Name.Contains("Async"))
            continue;
    
        MethodDeclaration asyncMethod = methodDeclaration.Clone() as MethodDeclaration;
        asyncMethod.Name += "Async"; 
    
        if (asyncMethod.ReturnType.ToString() == "void")
            asyncMethod.ReturnType = new SimpleType("Task");
        else
            asyncMethod.ReturnType = new SimpleType("Task", typeArguments: asyncMethod.ReturnType.Clone());
    
        methodDeclaration.Parent.AddChild(asyncMethod, Roles.TypeMemberRole);
    }
    
    #>
    <#=syntaxTree.ToString()#>​
    

    您将接口文件名传递给模板:

    using System.Collections.Generic;
    using System.ServiceModel;
    
    namespace MyProject
    {
        [ServiceContract]
        interface IUserService
        {
            [OperationContract]
            List<User> GetAllUsers();
        }
    }
    

    要买新的:

    using System.Threading.Tasks;
    using System.Collections.Generic;
    using System.ServiceModel;
    
    namespace MyProject.Client
    {
        [ServiceContract]
        interface IUserService
        {
            [OperationContract]
            List<User> GetAllUsers ();
    
            [OperationContract]
            Task<List<User>> GetAllUsersAsync ();
        }
    }
    

    现在你可以把它放到工厂异步使用通道:

    var factory = new ChannelFactory<MyProject.Client.IUserService>("*");
    var channel = factory.CreateChannel();
    var users = await channel.GetAllUsersAsync();
    

    【讨论】:

    • 嘿,我能够让 T4 正常工作,但我在 T4s 上完全是个菜鸟……如何让生成的 C# 代码运行以允许我访问 MyProject.Client.IUserService ?如果我这样做 string content = myT4.TransformText(); 我会得到新界面,但我不确定从那里去哪里
    • @philr T4 在 IDE 中使用,而不是在运行时使用。在 Visual Studio 中右键单击 *.tt 文件并转到运行自定义工具,这将生成一个 *.cs 文件,您可以将其复制粘贴到解决方案中需要的位置。老实说,这个答案并不是那么有用,因为它只会减少一些复制粘贴;您仍然需要为 GetAllUsersAsync() 或任何等效函数编写代码。
    【解决方案2】:

    很遗憾,没有。

    您从 svcutil 获得的异步方法是根据您的接口在代理中生成的。原始 WCF 通道中没有这样的内容。

    唯一的方法是更改​​服务引用以进行您不想要的本机异步调用,或者创建自己的通道包装器并像生成的代理一样自行实现它们。

    【讨论】:

    • 感谢您的回复。您有关于如何围绕频道创建自定义包装器的任何提示/链接吗?我做了一些调查,但没有发现任何东西。
    【解决方案3】:

    很遗憾,这是不可能的,而且有一个很好的理由。 CreateChannel 返回一个实现所提供接口的对象(在您的示例中为IUserService)。此接口不支持异步,因此无法返回具有正确方法的对象。

    有两种可能的解决方案:

    1. 创建您自己的能够调用 WCF 服务的代理。这意味着您需要编写自己的代理(或让svcutil 为您编写)。
    2. 确保 IUserService 是一个返回任务的异步接口。这在 WCF 4.5 及更高版本中受支持。这是我经常使用的。主要缺点是它使您的服务有点复杂,并且您需要调用异步方法(这也可能被认为是一个优势)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多