阅读后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/