WCF 服务参考生成自己的合约接口,不会重用我的
Posted
技术标签:
【中文标题】WCF 服务参考生成自己的合约接口,不会重用我的【英文标题】:WCF Service Reference generates its own contract interface, won't reuse mine 【发布时间】:2011-03-08 08:29:46 【问题描述】:我的第一个问题,希望它适合:
共享接口程序集 - 我有一个“共享”程序集,它有一个接口,我们称之为IDocRepository
。它用[ServiceContract]
标记,并且有几个[OperationContract]
标记的方法。
WCF 实现程序集 - 我有两个 WCF 服务项目,每个都引用共享程序集,每个都将该接口实现为 WCF 服务。
消费者程序集 - 最后,我有一个“客户端”项目,它也引用共享程序集,并引用两个 WCF 服务中的每一个。
但是,消费者程序集中生成的服务引用派生自接口的自动生成版本:
public partial class ExampleClient : System.ServiceModel.ClientBase<SomeNamespace.ExampleSvcRef.IDocRepository>, SomeNamespace.ExampleSvcRef.IDocRepository
我的预期 我希望这两个引用都会自动继承我定义的接口,即消费者/客户端程序集也正在引用。有点像重用它为参数和返回类型提供的类,但用于服务接口。
为什么 这样我就可以创建任一服务引用代理的实例并将其转换为我的接口类型。
所以我每次都可以手动修改生成的代码,但是应该有更好的方法...?
(编辑:我确实为两个服务引用选择了“在引用的程序集中重用类型”和“在所有引用的程序集中重用类型”选项)
【问题讨论】:
【参考方案1】:Visual Studio 不支持在为您生成代理类时重用您现有的接口。正如 Quartermeister 指出的那样,重用类型不会重用合约接口。
我们已经通过继承解决了这个问题。与上面 Jester Software 建议的部分类思想非常相似。
我们就是这样解决的:
在您客户的项目中,只需像您一样创建一个服务引用。然后添加一个类来代替客户端:
internal class MyServiceProxy : MyServiceClient, MyLogicNamespace.IMyService
此类继承自生成的 MyServiceClient,但声明该客户端确实实现了原始接口。
(我建议你把它们放在一个名为“ServiceProxies”的文件夹中)
如果 MyServiceClient 类包含任何与原始接口不匹配的方法,那么您可以将它们添加到该代理中并在代码中进行转换。
在此之后,只需在您将使用 MyServiceClient 的地方使用 MyServiceProxy。
【讨论】:
【参考方案2】:还有另一个不错的选择,如果您想继续使用代理生成器,因为它的功能有限但有些用处...使用分部类:
namespace <same namespace as generated proxy>
public partial class MyClient : <namespace of "real" service contract>.IServiceContract
确保代理生成代码的方式与您的服务合同定义它的方式相同,即,如果它使用“列表”,则在配置服务引用中也使用该选项。换句话说,请确保您生成的服务接口与您的真实服务接口完全相同,并且上面的代码应该可以工作,并且要使用右键单击而不是编写代码来更新引用。
【讨论】:
【参考方案3】:“在引用的程序集中重用类型”仅允许您重用数据协定,而不是服务协定。如果要共享服务合同,则根本不需要使用“添加服务引用”。您可以直接使用ChannelFactory。
// Supply the binding and address in code
Binding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress("http://tempuri.org/address");
IServiceContract channel = ChannelFactory<IServiceContract>.CreateChannel(binding, address);
// Or read them from the config file
ChannelFactory<IServiceContract> channelFactory = new ChannelFactory<IServiceContract>();
IServiceContract channel = channelFactory.CreateChannel();
通道对象也将实现ICommunicationObject,因此如果您需要调用Open() 或Close() 等方法,您可以强制转换它。
【讨论】:
我选择了第二个选项,但我得到了必须指定 EndpointAddress 的错误。我在配置文件中设置了一个端点,指定了相同的合同(接口),但它似乎不在那里?你能帮忙吗? 没关系;您需要将端点配置名称传递给 ChannelFactory 构造函数。 很棒的解决方案,谢谢!我能够在我们的项目中完全消除笨重的庞大服务引用! 这样做的诸多好处之一是您实际上会看到接口 xml 文档(否则您看不到,因为 ServiceReference 不会复制文档) 如果您的服务项目在同一个解决方案中,您可以使用 Resharper 的 Go to Implementation 和 Find References。【参考方案4】:创建服务引用时,您可以勾选一个框以使其重用共享定义。确保客户端项目已经在引用共享程序集,再次添加服务引用,并仔细检查所有选项。
如果仍然不起作用,请检查您使用的绑定。我有一个模糊的回忆,基本的 HTTP 绑定不支持类型的重用?
【讨论】:
嗨,大卫,感谢您的评论! - 我确实做到了,我应该提到。 (如上)。 该路由的唯一问题是如果您想引用具有相同共享库的 2 个服务;你得到重复的对象。 @eschneider - 我不明白这是怎么回事,这就是“重用...”选项的作用,它通过使用现有的引用类来停止类(“对象”)的复制- 不是吗?但是我看到重复的接口,这是我在问题中描述的问题:)。 我是说可能会发生重复(警告);不是你的问题。以上是关于WCF 服务参考生成自己的合约接口,不会重用我的的主要内容,如果未能解决你的问题,请参考以下文章
WCF ChannelFactory 和通道 - 缓存、重用、关闭和恢复