在 C# 中,是否可以创建一个通用方法来实例化从 Praxedo WSDL 生成的多个 "manager clients"?
In C#, is it possible to create a generic method for instantiating multiple "manager clients" generated from Praxedo WSDL?
我们将 Praxedo 用于多个服务,其中许多服务都在不同的 SOAP API 上,这些 API 与实例化和消费非常相似。
我不想重复代码,而是想做一个通用的方法来做到这一点。
我创建了这个工厂class:
using PraxedoIntegration.Common.Configurations;
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using WcfCoreMtomEncoder;
namespace PraxedoV6.ManagerClientWrappers.Helpers
{
public class PraxedoClientFactory
{
private readonly PraxedoSettings _praxedoSettings;
public PraxedoClientFactory(
PraxedoSettings praxedoSettings
) =>
_praxedoSettings = praxedoSettings ?? throw new ArgumentNullException(nameof(praxedoSettings));
public T Create<T, TChannel>(Uri endpoint, HttpsTransportBindingElement bindingElement)
where T : ClientBase<TChannel>, new()
where TChannel : class
{
MtomMessageEncoderBindingElement encoding = CreateMtomMessageEncoderBindingElement();
CustomBinding customBinding = new(encoding, bindingElement);
T managerClient = (T)Activator.CreateInstance(typeof(T), new object[] { customBinding, endpoint });
_praxedoSettings.AddAuthorizationTo(managerClient);
return Authorize<T, TChannel>(managerClient);
}
private static MtomMessageEncoderBindingElement CreateMtomMessageEncoderBindingElement() =>
new(new TextMessageEncodingBindingElement
{
MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None)
});
public T Authorize<T, TChannel>(T managerClient)
where T : ClientBase<TChannel>, new()
where TChannel : class
{
_ = new OperationContextScope(managerClient.InnerChannel);
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name]
= _praxedoSettings.ToHttpRequestMessageProperty();
return managerClient;
}
}
}
它编译得很好而且很漂亮。
但是当我尝试食用它时,例如:
_customerManagerClient = praxedoClientFactory.Create<CustomerManagerClient, CustomerManagerV6.CustomerManager>(
_praxedoSettings.CustomerManagerEndpoint,
new HttpsTransportBindingElement()
我收到如下运行时错误:
WorkflowTests.TaskProcessor.NewOrg.CreateCustomerAndLocationActionDiagnosticTool.CreateCustomerAndLocationInPraxedoTest
Source: CreateCustomerAndLocationActionDiagnosticTool.cs line 15
Duration: 23 ms
Message: System.MissingMethodException : Constructor on type
'CustomerManagerV6.CustomerManagerClient' not found.
Stack Trace: RuntimeType.CreateInstanceImpl(BindingFlags
bindingAttr, Binder binder, Object[] args, CultureInfo culture)
Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder
binder, Object[] args, CultureInfo culture, Object[]
activationAttributes) Activator.CreateInstance(Type type, Object[]
args) PraxedoClientFactory.Create[T,TChannel](Uri endpoint,
HttpsTransportBindingElement bindingElement) line 25
CustomerManagerClientWrapper.ctor(PraxedoClientFactory
praxedoClientFactory, PraxedoSettings praxedoSettings,
PraxedoThrottleOut praxedoThrottleOut) line 30
CreateCustomerAndLocationActionDiagnosticTool.CreateCustomerAndLocationInPraxedoTest()
line 22
--- End of stack trace from previous location ---
在此实例中,CustomerManagerClient
是一个 class,它继承了抽象 System.ServiceModel.ClientBase<CustomerManagerV6.CustomerManager>
并实现了接口 CustomerManagerV6.CustomerManager
(所有代码都是从 WSDL 自动生成的)。
在另一个实例中,我们有 BusinessEventManagerClient
,它(您可能会预测)继承自抽象 System.ServiceModel.ClientBase<BusinessEventManagerV6.BusinessEventManagerClient>
并实现接口 BusinessEventManagerV6.BusinessEventManagerClient
(所有 [再次] 每个代码从 WSDL 自动生成).
我们还有大约六个类似的“经理客户”。
我是否使用正确的类型参数和约束声明了 Create()
方法?
我是否正确调用它?
还有什么我应该做的吗?
我是在尝试做一些不可能的事情吗?
解决了问题....我忘记将我的 Uri endpoint
转换为 EndpointAddress
,像这样:
public T Create<T, TChannel>(Uri endpoint, HttpsTransportBindingElement bindingElement)
where T : ClientBase<TChannel>, TChannel, new()
where TChannel : class
{
MtomMessageEncoderBindingElement encoding = CreateMtomMessageEncoderBindingElement();
CustomBinding customBinding = new(encoding, bindingElement);
EndpointAddress endpointAddress = new(endpoint);
T managerClient = (T)Activator.CreateInstance(typeof(T), new object[] { customBinding, endpointAddress });
_praxedoSettings.AddAuthorizationTo(managerClient);
return Authorize<T, TChannel>(managerClient);
}
...所以构造函数得到了错误类型的对象。
我们将 Praxedo 用于多个服务,其中许多服务都在不同的 SOAP API 上,这些 API 与实例化和消费非常相似。
我不想重复代码,而是想做一个通用的方法来做到这一点。
我创建了这个工厂class:
using PraxedoIntegration.Common.Configurations;
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using WcfCoreMtomEncoder;
namespace PraxedoV6.ManagerClientWrappers.Helpers
{
public class PraxedoClientFactory
{
private readonly PraxedoSettings _praxedoSettings;
public PraxedoClientFactory(
PraxedoSettings praxedoSettings
) =>
_praxedoSettings = praxedoSettings ?? throw new ArgumentNullException(nameof(praxedoSettings));
public T Create<T, TChannel>(Uri endpoint, HttpsTransportBindingElement bindingElement)
where T : ClientBase<TChannel>, new()
where TChannel : class
{
MtomMessageEncoderBindingElement encoding = CreateMtomMessageEncoderBindingElement();
CustomBinding customBinding = new(encoding, bindingElement);
T managerClient = (T)Activator.CreateInstance(typeof(T), new object[] { customBinding, endpoint });
_praxedoSettings.AddAuthorizationTo(managerClient);
return Authorize<T, TChannel>(managerClient);
}
private static MtomMessageEncoderBindingElement CreateMtomMessageEncoderBindingElement() =>
new(new TextMessageEncodingBindingElement
{
MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None)
});
public T Authorize<T, TChannel>(T managerClient)
where T : ClientBase<TChannel>, new()
where TChannel : class
{
_ = new OperationContextScope(managerClient.InnerChannel);
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name]
= _praxedoSettings.ToHttpRequestMessageProperty();
return managerClient;
}
}
}
它编译得很好而且很漂亮。
但是当我尝试食用它时,例如:
_customerManagerClient = praxedoClientFactory.Create<CustomerManagerClient, CustomerManagerV6.CustomerManager>(
_praxedoSettings.CustomerManagerEndpoint,
new HttpsTransportBindingElement()
我收到如下运行时错误:
WorkflowTests.TaskProcessor.NewOrg.CreateCustomerAndLocationActionDiagnosticTool.CreateCustomerAndLocationInPraxedoTest Source: CreateCustomerAndLocationActionDiagnosticTool.cs line 15
Duration: 23 msMessage: System.MissingMethodException : Constructor on type 'CustomerManagerV6.CustomerManagerClient' not found.
Stack Trace: RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture) Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) Activator.CreateInstance(Type type, Object[] args) PraxedoClientFactory.Create[T,TChannel](Uri endpoint, HttpsTransportBindingElement bindingElement) line 25 CustomerManagerClientWrapper.ctor(PraxedoClientFactory praxedoClientFactory, PraxedoSettings praxedoSettings, PraxedoThrottleOut praxedoThrottleOut) line 30 CreateCustomerAndLocationActionDiagnosticTool.CreateCustomerAndLocationInPraxedoTest() line 22 --- End of stack trace from previous location ---
在此实例中,CustomerManagerClient
是一个 class,它继承了抽象 System.ServiceModel.ClientBase<CustomerManagerV6.CustomerManager>
并实现了接口 CustomerManagerV6.CustomerManager
(所有代码都是从 WSDL 自动生成的)。
在另一个实例中,我们有 BusinessEventManagerClient
,它(您可能会预测)继承自抽象 System.ServiceModel.ClientBase<BusinessEventManagerV6.BusinessEventManagerClient>
并实现接口 BusinessEventManagerV6.BusinessEventManagerClient
(所有 [再次] 每个代码从 WSDL 自动生成).
我们还有大约六个类似的“经理客户”。
我是否使用正确的类型参数和约束声明了 Create()
方法?
我是否正确调用它?
还有什么我应该做的吗?
我是在尝试做一些不可能的事情吗?
解决了问题....我忘记将我的 Uri endpoint
转换为 EndpointAddress
,像这样:
public T Create<T, TChannel>(Uri endpoint, HttpsTransportBindingElement bindingElement)
where T : ClientBase<TChannel>, TChannel, new()
where TChannel : class
{
MtomMessageEncoderBindingElement encoding = CreateMtomMessageEncoderBindingElement();
CustomBinding customBinding = new(encoding, bindingElement);
EndpointAddress endpointAddress = new(endpoint);
T managerClient = (T)Activator.CreateInstance(typeof(T), new object[] { customBinding, endpointAddress });
_praxedoSettings.AddAuthorizationTo(managerClient);
return Authorize<T, TChannel>(managerClient);
}
...所以构造函数得到了错误类型的对象。