在 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);
        }

...所以构造函数得到了错误类型的对象。