c# - 无法访问我在泛型方法中用作类型参数的类的基类的属性
问题描述
背景
我有一个提供 SOAP API 的第三方系统。他们的 WSDL 的类结构总体上还有很多不足之处,但我正在努力解决的一个领域是简化绑定的检索。他们的示例代码有大约 20 个这样的方法,每个端点/类/接口一个:
public static ICreateObjectPortType GetCreateObjectHttpBinding()
{
var servicePort = new CreateObjectPortTypeClient();
servicePort.Endpoint.ListenUri = GetServiceUrl("ReadObject");
servicePort.ClientCredentials.UserName.UserName = SDK.Username;
servicePort.ClientCredentials.UserName.Password = SDK.Password;
SetupHttpHeader(servicePort.InnerChannel);
return servicePort;
}
我的主要目标是将这些转换为一个通用方法,我可以只用一个或两个参数调用它并返回类。(您还会在我当前的代码中看到我正在实现一些动态绑定代码。这是因为我要访问多家公司,并且它们的系统结构需要每个公司的绑定。这与问题无关。)
所有类和接口的基本结构如下。我只包含了我要定位的构造函数。这些是在从 WSDL 创建的存根类中定义的,如果可能的话,我不想直接编辑。:
接口public interface ICreateObjectPortType { }
课程
public partial class CreateObjectPortTypeClient : ClientBase<ICreateObjectPortType>, ICreateObjectPortType
{
public CreateObjectPortTypeClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
}
以下是存根中声明的其他接口和类的示例。它们之间唯一的共同点是所有类都继承自ClientBase<interface>
and interface
:
IReadObjectPortType
和ReadObjectPortTypeClient
IUpdateObjectPortType
和UpdateObjectPortTypeClient
IFindObjectsPortType
和FindObjectsPortTypeClient
这是SetupHttpHeader
他们的示例代码中定义的方法。我还没有检查它是否真的需要,但为了完整起见,我将其包括在内:
public static void SetupHttpHeader(IClientChannel serviceChannel)
{
using (new OperationContextScope(serviceChannel))
{
// Add a HTTP Header to an outgoing request
var requestMessage = new HttpRequestMessageProperty();
requestMessage.Headers["Authorization"] = "Basic " + System.Convert.ToBase64String(Encoding.UTF8.GetBytes(SDK.Username + ":" + SDK.Password));
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
}
}
我的代码
最后,对于代码示例,这是我对通用方法、支持凭证设置方法以及使用它们的样子的尝试:
public static T ConfigureServicePort<T>(Func<string,EndpointAddress, T> test, string serviceName) where T : class
{
var endpointName = serviceName + "HttpPort";
var endpointAddress = new EndpointAddress($"https://hcmiller.myprintdesk.com:443/rpc/company:public/services/{serviceName}");
var servicePort = test(endpointName, endpointAddress);
return servicePort;
}
public static void SetClientCredentials(this ClientCredentials creds)
{
creds.UserName.UserName = SDK.Username;
creds.UserName.Password = SDK.Password;
}
public static ICreateObjectPortType GetCreateObjectHttpBinding()
{
var servicePort = ConfigureServicePort((x, y) => new CreateObjectPortTypeClient(x, y), "CreateObject");
servicePort.ClientCredentials.SetClientCredentials();
SetupHttpHeader(servicePort.InnerChannel);
return servicePort;
}
如您所见,我还没有完全到那里。我已经成功地在方法中实现了一个函数参数,以便T
使用参数调用构造函数。它比我更喜欢我的泛型要开放得多,但我不知道有另一种方法可以允许这样做,同时也限制T
可以是什么。
问题
我现在的问题是在该通用方法中也进行设置ClientCredentials
和调用。SetupHttpHeader
鉴于这些类没有基本接口,它们唯一的共同点是ClientBase<T>
我还没有找到一种方法将servicePort
内部ConfigureServicePort
视为继承自ClientBase<T>
以获取必要属性的东西。
我怎样才能得到它,以便ConfigureServicePort<T>
可以像对待它T
一样对待它ClientBase<T>
,以便我可以访问我需要配置的属性?
解决方案
我无法对此进行测试,因为我需要实际的服务,但假设您可以这样做:
public CreateObjectPortTypeClient() { }
如果不满足某些条件(如ClientBase<T>
构造函数中指定),则可能会失败:
//
// Summary:
// Initializes a new instance of the System.ServiceModel.ClientBase`1 class using
// the default target endpoint from the application configuration file.
//
// Exceptions:
// T:System.InvalidOperationException:
// Either there is no default endpoint information in the configuration file, more
// than one endpoint in the file, or no configuration file.
如果这对你有用,你可以让你的生活变得很轻松。
让我们用 2 个服务来简化情况:
public interface IService1 { }
public class Service1 : ClientBase<IService1>, IService1 { }
public interface IService2 { }
public class Service2 : ClientBase<IService2>, IService2 { }
那么你可以使用这个:
public static TClient ConfigureServicePort<TClient, TService>(string serviceName)
where TClient : ClientBase<TService>, new()
where TService : class
{
var servicePort = new TClient();
servicePort.Endpoint.Address = new EndpointAddress($"https://hcmiller.myprintdesk.com:443/rpc/company:public/services/{serviceName}");
servicePort.Endpoint.Name = serviceName + "HttpPort";
servicePort.ClientCredentials.SetClientCredentials();
SetupHttpHeader(servicePort.InnerChannel);
return servicePort;
}
然后简单地调用它:
var service1Client = X.ConfigureServicePort<Service1, IService1>("Service1");
var service2Client = X.ConfigureServicePort<Service2, IService2>("Service2");
请注意,需要两个泛型参数,因为您需要满足由 设置的泛型约束ClientBase<T>
。
推荐阅读
- emacs - 如何防止宏扩展全部跳过列表中的第一个表单?
- r - 查看 SQLite 中是否已启动事务
- javascript - angular应用的目录结构,在角色实现的情况下
- vb.net - 具有多个动态复杂参数的 LINQ GroupBy
- c++ - 查找给定 n 的产品数量的程序的复杂性
- python - 使用索引提取张量的行和列
- r - 如何将一列中的唯一变量以条件提取另一列中的变量并使用输出创建一个新的数据框?
- arrays - 在 TypeScript 中查找比较两个数组的每个匹配项
- php - 从 php 生成的邮件在 Outlook 中没有格式化,但在 Iphone 邮件上看起来很完美
- laravel - Laravel 刀片,这是授权的吗?