如何从WCF服务返回接口?

时间:2009-06-24 21:07:47

标签: wcf wcf-client

假设我有一些接口:

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,没有区别。有没有办法使用我的界面生成代理代码?

我在想,如果模拟对象可以生成我的界面对象进行测试,那么我是否应该能够获得服务来尊重它?或者确实做了一些愚蠢和错误的事情?

5 个答案:

答案 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