c# - 更简单的通用 ClientBase 工厂

标签 c# .net generics factory webservice-client

阅读后C# generic ClientBase with interface confusion我成功创建了一个 Soap Webservice Factory 来简化我的代码:

private T ClientMaker<TInterface, T>(string username, string password, string address)
    where TInterface : class 
    where T : ClientBase<TInterface>, TInterface
{
    var binding = new BasicHttpBinding();
    binding.MaxBufferPoolSize = int.MaxValue;
    binding.MaxBufferSize = int.MaxValue;
    binding.MaxReceivedMessageSize = int.MaxValue;

    binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
    binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

    EndpointAddress ordersEndpoint = new EndpointAddress(address);

    T client = Activator.CreateInstance(typeof(T), new object[] { binding, ordersEndpoint }) as T;

    client.ClientCredentials.UserName.UserName = username;
    client.ClientCredentials.UserName.Password = password;

    return client;
}

使用方式如下:

var client = ClientMaker<CreateWebOrder.WEB_Functions_Port, CreateWebOrder.WEB_Functions_PortClient>(user, pass, endpointBase + "Codeunit/WEB_Functions");

CreateWebOrder.WEB_Functions_Port是CreateWebOrder.WEB_Functions_PortClient实现的接口(interface)

我不太喜欢的一件事是我需要提供接口(interface)和网络服务的类/类型,所以我想知道是否有一种方法可以通过找出接口(interface)或类来解决这个问题来自类型参数。

考虑到返回类型是 ClientBase 并且 TInterface 由于提供的类型参数而已知,为什么我需要提供“PortClient”?

理想情况下,我想仅使用 1 个类型参数来调用工厂,但我不知道是否可能

最佳答案

简答

该功能已经开箱即用。给定一个带注释的接口(interface):

[ServiceContract()]
interface IMath
{
    [OperationContract()]
     double Add(double A, double B);
}

您可以为特定绑定(bind)和端点创建工厂:

BasicHttpBinding myBinding = new BasicHttpBinding();

//configure the binding ........ then 

EndpointAddress myEndpoint = new EndpointAddress("http://localhost/MathService/Ep1");

ChannelFactory<IMath> myChannelFactory = new ChannelFactory<IMath>(myBinding, myEndpoint);

// Create a channel.
IMath wcfClient1 = myChannelFactory.CreateChannel();
double s = wcfClient1.Add(3, 39);

长解释

WCF 已经为所有这些东西提供了工厂,事实上,它有太多的工厂,而且没有足够的文档 - 早在 2008 年,人们就认为每个人都会从符合 WS-* 标准的 WSDL 生成客户端代理,并通过 XML 进行配置.

当时每个人都真的认为 XML 是一切问题的解决方案,就像 5 年前每个人都认为 JSON 是解决方案,或者 2 年前每个人都认为 YAML 一样。

客户端使用行为。行为结合了端点和绑定(bind)。所有这些都可以在代码中创建并根据需要注入(inject)。 WCF 提供了从 app.config/web.config 文件加载设置的基础结构。不幸的是,此配置基础设施无法轻松自定义,并且操作方法文档没有显示以编程方式构建 channel 的整个过程,因为它被认为是高级案件。

用于绑定(bind)、端点、消息信封、正文等的工厂。没有人想到记录所有这些,因为他们认为每个人都会使用工具来生成代理。

例如 WCF Client Overview显示如何创建接口(interface)和客户端库,但 5 个构造函数中有 4 个使用默认配置或期望配置名称。最后一个接受 Binding 和 EndpointAddress。无需硬编码,例如:


public partial class SampleServiceClient : System.ServiceModel.ClientBase<ISampleService>, ISampleService
{
    public SampleServiceClient(Binding binding, EndpointAddress remoteAddress)
        :base(binding, remoteAddress)
    {
    }
}

每次都生成该代码是不切实际的,尤其是当行为需要更改时。例如,添加加密或检查/修改自定义 header 。因此WCF为“高级”场景提供了ChannelFactory。代理也使用它来缓存行为、绑定(bind)和端点实例。这些文档位于“高级”部分 How to: Use the ChannelFactory .

从该文档示例来看,它很简单:

[ServiceContract()]
interface IMath
{
    [OperationContract()]
     double Add(double A, double B);
}


private void Run()
{
        BasicHttpBinding myBinding = new BasicHttpBinding();

        EndpointAddress myEndpoint = new EndpointAddress("http://localhost/MathService/Ep1");

        ChannelFactory<IMath> myChannelFactory = new ChannelFactory<IMath>(myBinding, myEndpoint);

        // Create a channel.
        IMath wcfClient1 = myChannelFactory.CreateChannel();
        double s = wcfClient1.Add(3, 39);
}

为什么我要以相反的顺序编写示例?

正是因为ChannelFactory“隐藏”在高级功能中。我首先找到了编程客户端示例,然后是 Configuring Client Behaviors它指向 ClientFactory,最后是 How To: Use the ChannelFactory .

关于c# - 更简单的通用 ClientBase 工厂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59624323/

相关文章:

c# - 对象未将所有属性序列化为 XML

c# - 插入、子查询、值

c# - MongoDb - 使用 .NET 驱动程序运行 adminCommand (2.4.4)

java - 通配符,它​​是如何工作的?

c# - 在 C# 泛型类型上强制执行任意函数

c# - XAML 中的枚举转换器

c# - TPL 数据流工作流

c# - 我可以在 C# 中从泛型类型转换为枚举类型吗?

用于读取视频帧的 .NET 库

c# - 通过 WebClient.DownloadFile 获取的文件立即消失