假设我有一些接口:
public interface IFoo {
IBar DoesStuff();
}
public interface IBar {
string Thingo { get; }
}
我在整个代码库中使用此代码。需要将IFoo进程移动到不同的系统上(x64与x32的差异),这是我们使用WFC的原因。我的WCF服务实现了此接口。当我创建“服务引用”时,会创建代理存根,但会更改接口。
public interface IFoo {
object DoesStuff();
}
我尝试将IBar / Bar定义为DataService和DataContract,没有区别。有没有办法使用我的界面生成代理代码?
我在想,如果模拟对象可以生成我的界面对象进行测试,那么我是否应该能够获得服务来尊重它?或者确实做了一些愚蠢和错误的事情?
答案 0 :(得分:6)
IBar需要具体和DataContract。 WCF不是关于分布式对象,而是一种传输数据并使服务处理该数据的方法。您无法在WCF中返回具有行为的对象。
答案 1 :(得分:2)
我不知道你是否还需要一个解决方案。以下是我的工作。这里的诀窍是不要像许多博客建议的那样使用标准的“添加服务引用”,而是使用Channel Factory编写自己的客户端代理。在这种情况下,您可以选择重用您的接口,但根据需要重新定义具体类。如果您需要,很高兴进一步详细说明。
// Service Contract
[ServiceContract(name="a", namespace="b")]
public interface IFoo {
Bar DoesStuff();
}
// Interface to share
public interface IBar {
string Thingo { get; }
}
// Server Implementation
public class Bar : IBar
{
string Thingo { get; set; }
}
// Client Proxy reference IBar interface only but redefine concrete class Bar.
public class Bar : IBar
{
public string Thingo
{
get { return _thingo; }
set { _thingo = value; }
}
string _thingo;
}
/// Sample channel factory implementation
using System;
using System.Configuration;
using System.ServiceModel;
using System.ServiceModel.Channels;
public abstract partial class ServiceProxyBase<TServiceContract> : IServiceProxy
where TServiceContract : class
{
protected ServiceProxyBase()
: this(null, null)
{
}
protected ServiceProxyBase(string url, Binding binding)
{
var contractName = typeof(TServiceContract).Name;
var urlConfiguration = string.Format("{0}_Url", contractName);
var serviceUrl = url ?? ConfigurationManager.AppSettings.ValueOrDefault (urlConfiguration, string.Empty, true);
if (serviceUrl.IsNullOrEmptỵ̣())
{
throw new Exception(string.Format("Unable to read configuration '{0}'", urlConfiguration));
}
var serviceBinding = binding ?? new BasicHttpBinding();
Factory = new ChannelFactory<TServiceContract>(serviceBinding);
var serviceUri = new Uri(serviceUrl);
var endPoint = new EndpointAddress(serviceUri);
Channel = Factory.CreateChannel(endPoint);
}
public virtual void Abort()
{
isAborted = true;
}
public virtual void Close()
{
if (Channel != null)
{
((IClientChannel)Channel).Close();
}
if (Factory != null)
{
Factory.Close();
}
}
private ChannelFactory<TServiceContract> Factory { get; set; }
protected TServiceContract Channel { get; set; }
private bool isAborted = false;
}
public class FooServiceProxy : ServiceProxyBase<IFooServiceProxy>, IFooServiceProxy
{
public Task<Bar> DoesStuffAsync()
{
return Channel.DoesStuffAsync();
}
}
[ServiceContract(name="a", namespace="b")] // The trick when redefine service contract
public interface IFooServiceProxy
{
[OperationContract]
Task<Bar> DoesStuffAsync();
}
答案 2 :(得分:1)
是。在添加服务引用之前,需要引用包含该接口的项目。然后将重新使用该接口。对于使用的任何自定义类都是如此 - 如果在添加服务引用之前客户端项目引用包含其定义的项目,则WCF可以重用这些定义。
您还需要转到“添加服务引用”对话框中的“高级”选项卡,并勾选“重用引用程序集中的类型”以使其生效。
答案 3 :(得分:1)
尝试将Web服务视为跨平台。如果你退回它,Java客户端会对你的界面做什么?
答案 4 :(得分:0)
皮肤猫的另一种方法。 Dominic使用KnownType属性完成了它。查看下面的博客。
http://blogs.msdn.com/b/domgreen/archive/2009/04/13/wcf-using-interfaces-in-method-signatures.aspx