Как вернуть интерфейс из службы WCF? - PullRequest
4 голосов
/ 25 июня 2009

Допустим, у меня есть несколько интерфейсов:

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 ]

6 голосов
/ 25 июня 2009

IBar должен быть конкретным и DataContract. WCF не о распределенных объектах, а скорее о способе передачи данных и работы сервисов с этими данными. Вы не можете вернуть объект в WCF, который имеет поведение.

2 голосов
/ 05 декабря 2013

Я не знаю, нужно ли вам еще решение. Ниже то, что я бы сделал. Хитрость здесь не в том, чтобы использовать стандартные «ссылки на сервисы», как предлагали многие блоги, а в том, чтобы написать собственный клиентский прокси с помощью 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();
}
1 голос
/ 25 июня 2009

Попробуйте представить веб-сервисы кроссплатформенными. Что бы сделал Java-клиент с вашим интерфейсом, если бы вы его вернули?

1 голос
/ 25 июня 2009

Да. Вам необходимо сослаться на проект, содержащий интерфейс, прежде чем добавить ссылку на сервис. Тогда интерфейс будет использован повторно. То же самое будет справедливо для любых используемых пользовательских классов - если клиентский проект ссылается на проект, содержащий их определения, до добавления ссылки на службу, то WCF может повторно использовать эти определения.

Вам также потребуется перейти на вкладку «Дополнительно» в диалоговом окне «Добавить ссылку на службу» и установить флажок «Повторное использование типов в ссылочных сборках».

0 голосов
/ 05 декабря 2013

Еще один способ снять кожу с кошки. Доминик сделал это, используя атрибуты KnownType. Посмотрите его блог ниже.

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

...