Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用ChannelFactory和CreateChannel进行异步WCF调用_C#_.net_Wcf_Async Await - Fatal编程技术网

C# 使用ChannelFactory和CreateChannel进行异步WCF调用

C# 使用ChannelFactory和CreateChannel进行异步WCF调用,c#,.net,wcf,async-await,C#,.net,Wcf,Async Await,我从事的项目是,托管在web服务器上的web应用程序调用托管在应用服务器上的WCF服务。WCF调用的代理由ChannelFactory创建,并通过channel进行调用,例如: (省略使用块) 有没有办法使用ChannelFactory和Channel async进行调用?我没找到。我知道我可以通过svcutil/Add服务引用生成异步方法,但我不想这样做。另外,我不想通过添加异步方法来更改AppServer上的服务接口(IUserService) 有没有办法用ChannelFactory异步调

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

(省略使用块)

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


有没有办法用ChannelFactory异步调用方法?谢谢。

不幸的是,没有

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


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

不幸的是,这是不可能的,这是有充分理由的
CreateChannel
返回实现所提供接口的对象(
IUserService
,在您的示例中)。此接口不支持异步,所以无法使用正确的方法返回对象

有两种可能的解决方案:

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

  • 您可以使用从原始接口自动生成包含异步版本的方法的新接口,并在
    ChannelFactory
    中使用它

    我曾经解析原始代码并生成新的C#源代码,并在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();
        }
    }
    
    
    使用System.Threading.Tasks;
    ​
    
    将接口文件名传递给模板:

    <#@ 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();
        }
    }
    
    使用System.Collections.Generic;
    使用System.ServiceModel;
    名称空间MyProject
    {
    [服务合同]
    接口服务
    {
    [经营合同]
    列出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 ();
        }
    }
    
    使用System.Threading.Tasks;
    使用System.Collections.Generic;
    使用System.ServiceModel;
    名称空间MyProject.Client
    {
    [服务合同]
    接口服务
    {
    [经营合同]
    列出GetAllUsers();
    [经营合同]
    任务GetAllUsersAsync();
    }
    }
    
    现在,您可以将其放在工厂中异步使用通道:

    var factory = new ChannelFactory<MyProject.Client.IUserService>("*");
    var channel = factory.CreateChannel();
    var users = await channel.GetAllUsersAsync();
    
    var-factory=newchannelfactory(“*”);
    var channel=factory.CreateChannel();
    var users=await channel.GetAllUsersAsync();
    
    感谢您的回复。关于如何在频道周围创建自定义包装器,您有任何提示/链接吗?我做了一些调查,但没有发现任何东西。嘿,我能让T4正常工作,但我在T4s是个彻头彻尾的傻瓜。。。如何让生成的C#代码运行以允许我访问
    MyProject.Client.IUserService
    ?如果我执行
    string content=myT4.TransformText()我得到了新的界面,但我真的不确定从哪里开始there@philrT4在IDE中使用,而不是在运行时使用。在Visual Studio中右键单击*.tt文件,然后转到运行自定义工具,该工具将生成一个*.cs文件,您可以在解决方案中需要粘贴的位置复制粘贴该文件。老实说,这个答案不是很有用,因为它只减少了一些拷贝粘贴;您仍然需要为
    GetAllUsersAsync()
    或任何等效函数编写代码。