[英]I can't get access to static properties or fields of my generic base class in C#
[英]Can't access properties of the base class of the class I am using as the type argument in a generic method
我有一个提供 SOAP API 的第三方系统。 他们的 WSDL 的 class 结构一般来说还有很多不足之处,但我正在努力解决的一个领域是简化绑定的检索。 他们的示例代码有大约 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;
}
我的主要目标是将它们转换成一个通用方法,我可以只用一两个参数调用它并返回 class。(你还会在我当前的代码中看到我正在实现一些动态绑定代码。这是因为我有多家公司可以访问,他们的系统结构需要每个公司绑定。这与问题无关。)
所有类和接口的基本结构如下。 我只包含了我的目标构造函数。 这些是在从 WSDL 创建的存根类中定义的,如果可能,我不想直接编辑它们。
接口public interface ICreateObjectPortType { }
班级
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;
}
}
以下是存根中声明的其他接口和类的示例。 它们之间唯一的共同点是所有类都继承自ClientBase<interface>
和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; }
如您所见,我还没有完成。 我已经成功地在方法中实现了一个 function 参数,以便使用参数调用T
上的构造函数。 它比我更喜欢我的 generics 更开放,但我不知道另一种方法可以允许它同时限制T
可以是什么。
我现在的问题是让 ClientCredentials 的设置和ClientCredentials
的调用SetupHttpHeader
那个通用方法中发生。 鉴于这些类没有基本接口,并且它们唯一的共同点是ClientBase<T>
我还没有找到一种方法来将ConfigureServicePort
中的servicePort
视为从ClientBase<T>
继承的东西以获取必要的属性.
我怎样才能得到它,以便ConfigureServicePort<T>
可以像对待ClientBase<T>
一样对待它的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>
设置的通用约束。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.