如何从WCF服务返回接口?

时间:2022-10-30 23:18:49

Lets say I have some interfaces:

可以说我有一些接口:

public interface IFoo {
  IBar DoesStuff();
}
public interface IBar {
  string Thingo { get; }
}

I'm consuming this code throughout my code base. The IFoo process needs to be moved onto a different system (a difference of x64 vs x32), this is our reason for using WFC. My WCF service implements this interface. When I create the "service reference" the proxy stubs are created but the interface is altered.

我在整个代码库中使用此代码。需要将IFoo进程移动到不同的系统上(x64与x32的差异),这是我们使用WFC的原因。我的WCF服务实现了此接口。当我创建“服务引用”时,会创建代理存根,但会更改接口。

public interface IFoo {
   object DoesStuff();
}   

I tried defining IBar/Bar as both a DataService and DataContract with no difference. Is there a way to generate the proxy code using my interface?

我尝试将IBar / Bar定义为DataService和DataContract,没有区别。有没有办法使用我的界面生成代理代码?

I'm thinking if mock objects can produce a object of my interface for testing, then shouldn't I be able to get the service to honor it as well? Or did do something silly and wrong?

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

5 个解决方案

#1


IBar needs to be concrete and a DataContract. WCF isn't about distributed objects, but rather a way to transfer data and have services work on that data. You can't return an object in WCF that has behavior.

IBar需要具体和DataContract。 WCF不是关于分布式对象,而是一种传输数据并使服务处理该数据的方法。您无法在WCF中返回具有行为的对象。

#2


I don't know if you still need a solution. Below is what I'd do. The trick here is not to use the standard "add service references" like many blogs has suggested but rather writer your own client proxy using Channel Factory. In this case, you can choose to reuse your interfaces but redefine the concrete classes as required. Happy to elaborate further if you need.

我不知道你是否还需要一个解决方案。以下是我的工作。这里的诀窍是不要像许多博客建议的那样使用标准的“添加服务引用”,而是使用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();
}

#3


Try to think of web services as being cross-platform. What would a Java client do with your interface if you returned it?

尝试将Web服务视为跨平台。如果您返回它,Java客户端将如何处理您的界面?

#4


Yes. You need to reference the project containing the interface before you add the service reference. Then the interface will be re-used. The same will be true for any custom classes used - if the project containing their definitions is referenced by the client project before the service reference is added, then WCF can re-use those definitions.

是。在添加服务引用之前,需要引用包含该接口的项目。然后将重新使用该接口。对于使用的任何自定义类都是如此 - 如果在添加服务引用之前客户端项目引用包含其定义的项目,则WCF可以重用这些定义。

You will also need to go to the Advanced tab in the Add Service Reference dialog and tick "Reuse types in referenced assemblies" to get this to work.

您还需要转到“添加服务引用”对话框中的“高级”选项卡,并勾选“重用引用的程序集中的类型”以使其生效。

#5


Another way to skin the cat. Dominic has done it using KnownType attributes. Check out his blog below.

皮肤猫的另一种方法。 Dominic使用KnownType属性完成了它。看看下面的博客。

http://blogs.msdn.com/b/domgreen/archive/2009/04/13/wcf-using-interfaces-in-method-signatures.aspx

#1


IBar needs to be concrete and a DataContract. WCF isn't about distributed objects, but rather a way to transfer data and have services work on that data. You can't return an object in WCF that has behavior.

IBar需要具体和DataContract。 WCF不是关于分布式对象,而是一种传输数据并使服务处理该数据的方法。您无法在WCF中返回具有行为的对象。

#2


I don't know if you still need a solution. Below is what I'd do. The trick here is not to use the standard "add service references" like many blogs has suggested but rather writer your own client proxy using Channel Factory. In this case, you can choose to reuse your interfaces but redefine the concrete classes as required. Happy to elaborate further if you need.

我不知道你是否还需要一个解决方案。以下是我的工作。这里的诀窍是不要像许多博客建议的那样使用标准的“添加服务引用”,而是使用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();
}

#3


Try to think of web services as being cross-platform. What would a Java client do with your interface if you returned it?

尝试将Web服务视为跨平台。如果您返回它,Java客户端将如何处理您的界面?

#4


Yes. You need to reference the project containing the interface before you add the service reference. Then the interface will be re-used. The same will be true for any custom classes used - if the project containing their definitions is referenced by the client project before the service reference is added, then WCF can re-use those definitions.

是。在添加服务引用之前,需要引用包含该接口的项目。然后将重新使用该接口。对于使用的任何自定义类都是如此 - 如果在添加服务引用之前客户端项目引用包含其定义的项目,则WCF可以重用这些定义。

You will also need to go to the Advanced tab in the Add Service Reference dialog and tick "Reuse types in referenced assemblies" to get this to work.

您还需要转到“添加服务引用”对话框中的“高级”选项卡,并勾选“重用引用的程序集中的类型”以使其生效。

#5


Another way to skin the cat. Dominic has done it using KnownType attributes. Check out his blog below.

皮肤猫的另一种方法。 Dominic使用KnownType属性完成了它。看看下面的博客。

http://blogs.msdn.com/b/domgreen/archive/2009/04/13/wcf-using-interfaces-in-method-signatures.aspx