inheritanceWCF中的通用契约
更多WCF问题…… 🙂
我的所有工作流程都实现了相同的3种方法。 经过大量的复制和粘贴后,我决定让它们从同一个界面inheritance:
[ServiceContract(Namespace = "http://schema.company.com/messages/")] public interface IBasicContract where TRequest : class where TResponse : class { [OperationContract(Name = "GetReport", Action = "http://schema.company.com/messages/GetReport", ReplyAction = "http://schema.company.com/messages/GetReportResponse")] TResponse GetReport(TRequest inquiry); [OperationContract(Name = "GetRawReport", Action = "http://schema.company.com/messages/GetRawReport", ReplyAction = "http://schema.company.com/messages/GetRawReportResponse")] string GetRawReport(string guid); [OperationContract(Name = "GetArchiveReport", Action = "http://schema.company.com/messages/GetArchiveReport", ReplyAction = "http://schema.company.com/messages/GetArchiveReportResponse")] TResponse GetArchiveReport(string guid); }
我还决定创建服务客户端的通用实现:
public class BasicSvcClient : ClientBase<IBasicContract>, IBasicContract where TRequest : class where TResponse : class { public BasicSvcClient() { } public BasicSvcClient(string endpointConfigurationName) : base(endpointConfigurationName) { } public BasicSvcClient(string endpointConfigurationName, string remoteAddress) : base(endpointConfigurationName, remoteAddress) { } public BasicSvcClient(string endpointConfigurationName, EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress) { } public BasicSvcClient(Binding binding, EndpointAddress remoteAddress) : base(binding, remoteAddress) { } public TResponse GetReport(TRequest inquiry) { return Channel.GetReport(inquiry); } public string GetRawReport(string guid) { return Channel.GetRawReport(guid); } public TResponse GetArchiveReport(string guid) { return Channel.GetArchiveReport(guid); } }
问题是当我尝试使用它时:
using (var client = new BasicSvcClient()) { var response = client.GetReport(inquiry); context.Response.ContentType = "text/xml"; context.Response.Write(response.AsXML()); }
我总是收到一个错误,说它无法找到合同IBasicContract的配置,因为.NET使用了这种奇怪的语法:
找不到引用契约’BasicWorkflow.IBasicContract`2的默认端点元素…
我试过这样做:
using (var client = new BasicSvcClient("myConfig"))
它没有帮助 – 它仍然在寻找特定的合同。
我知道ServiceContract属性有一个ConfigurationName参数,但我不能在编译时使用它,因为我有很多工作流程,我从同一个程序调用(因此有很多配置条目)。 有没有办法在运行时设置ConfigurationName? 我认为这是ClientBase构造函数应该做的,但显然不是。
[编辑]这是.config文件中的端点,我不相信它在这种情况下非常有用:
[编辑2]好的……我发现了一种有效的方法,尽管我仍然不满意它:
using (var wf = new BasicSvcClient( new BasicHttpBinding("httpsDataEndpoint"), new EndpointAddress("https://localhost/services/Contract.svc")))
我现在唯一的问题是我更愿意从.config文件中检索端点地址(使用实际的合同名称,如IContract)。 有谁可以帮我这个部分?
[Edit3]终于找到了完整的解决方案:)万岁reflection器!
var cf = (ClientSection) ConfigurationManager.GetSection("system.serviceModel/client"); foreach (ChannelEndpointElement endpoint in cf.Endpoints) { if (endpoint.Name != "ContractSvc") continue; using (var wf = new BasicSvcClient( new BasicHttpBinding("httpsDataEndpoint"), new EndpointAddress(endpoint.Address.ToString()))) { //... call wf.GetReport() } break; }
“.NET使用的奇怪语法”实际上是绑定到特定类型的generics类型在运行时的类型名称。 Typename`n [[Type],…]其中n表示generics类型中包含的类型参数的数量。
您的端点配置如何?
为什么不在ServiceContract属性中指定合同的名称:
[ ServiceContract ( Namespace = "http://schema.company.com/messages/", Name="MyBasicContract" ) ]
如果您没有明确指定名称,则默认使用“.NET使用的奇怪语法”中接口的限定名称。
如果要使用IBasicContract等服务契约,则必须使用在配置文件中定义generics类型的标准方法
它写在配置文件中,如下所示:IBasicContract`2 [TRequest,TResponse]
当你发布他们的问题时,我也在我的博客(www.lybecker.com/blog/)上回复了。
🙂 Anders Lybecker