2014-01-24 3 views
2

У меня есть следующая структура проекта:WCF повторное использование типов в той же библиотеке

  • Api Project: Содержит WCF SVC конечных точек
  • ClientServer проекта Библиотека: Содержит классы, которые используются сервером

Что я хочу сделать, это распространять мою библиотеку ClientServer как всеохватывающую оболочку API, которую клиенты могут использовать для подключения к API и получения информации.

Поскольку API использует типы, определенные в библиотеке ClientServer я хотел бы надеяться, что добавление ServiceReference в библиотеке ClientServer бы понять, что типы возвращаемых API фактически из тех же библиотек, как ссылки будут.

Причина, по которой я делаю это, заключается только в том, что я должен определять классы, которые отправляются на сервер и с сервера в одном месте, а также предоставлять встроенный механизм для использования API без каких-либо знаний от как он соединяет и без и дополнительные библиотеки зависимостей (например, выделенная библиотека моделей).

Ниже основной пример того, как я хочу это работать:

ClientServer Библиотека:

public class Person { 
    public string Name { get; set; } 
    public int Age { get; set; } 
    ..... 
} 

[ServiceContract] 
public interface IPeopleService { 

    [OperationContract] 
    public Person[] Find(Person person); 
} 

Api Project

public class PeopleService : ClientServerLibrary.IPeopleServer {  
    public ClientServerLibrary.Person Find(ClientServerLibrary.Person person) { 
    // implementation for finding people based on the input person criteria. 
    }  
} 

Учитывая приведенный выше пример Я хочу добавить ссылку на PeopleSer заместитель в библиотеку ClientServer так, что люди, которые используют мою библиотеку можно сделать что-то вдоль линий:

PeopleServiceClient people = new PeopleServiceClient() // Generated from the service references 

// Here "Person" needs to be of type ClientServerLibrary.Person 
Person person = people.Find(new Person() { Name = "Gary" }); 

Но в настоящее время его регенерирующие все классы. Я пробовал тикать и развязывать все варианты в «Добавить служебный диалог», но его всегда тот же результат.

Надеюсь, я хорошо объяснил свои намерения? Спасибо.

EDIT: Все проекты используют C# .NET v4, поэтому никаких расхождений нет.

+0

Веб-сервисы не обязательно должны быть такими же сложными, как и WCF. Используйте [ServiceStack] (https://servicestack.net/) – theMayer

+0

@ rmayer06 Спасибо за ссылку, но, к сожалению, использование другой структуры не является вариантом atm. Особенно тот, который стоит 200 долларов за разработчика. Спасибо, в любом случае, оцените ввод. –

+0

@ rmayer06 Кроме того, проблема не нужна со стороны службы, я ищу средство для создания библиотеки-обертки, которая повторно использует существующие типы, а не генерирует их собственные. –

ответ

2

ОК, поэтому, в конце концов, чтобы полностью выполнить все мои требования, мне в основном пришлось отказаться от идеи использования автоматических инструментов и ручной работы каждого клиента.

Это не так сложно, как кажется.


я в основном создал абстрактный общий базовый класс ServiceClient, где T представляет собой интерфейс ServiceContract (который я уже определен)

Работа в ServiceClient она похожа на те, генерируемых VS и CLI инструменты (svcutil, Etc). Он выставил «Канал» производным классам через свойство ServiceChannel. Это достигается с помощью:

// T here is the ServiceContract as configured by the derived class. 
ChannelFactory<T>.CreateChannel(binding, endpoint); 

теперь у меня есть возможность создавать клиентов следующим образом:

class PeopleServiceClient : ServiceClient<IPeopleService>, IPeopleService { 
    public Person[] Find(Person person) { 
     // Delegate all responsability to the channel (which is connected to the API) 
     return base.ServiceChannel.Find(person); 
    } 
} 

Потому что все связано с интерфейсом IPeopleService я могу гарантировать, что каждый метод был реализован, или минимальные изменения будут замечены во время компиляции.

теперь я могу использовать клиент, как это:

using(var client = new PeopleServiceClient()) { 
    Person[] people = client.Find(new Person() { Name = "Gary" }); 
} 

Так, чтобы ответить на мой вопрос:

Да, вы можете иметь всеохватывающую библиотеку, содержащую модели, контракты и клиент; Вам просто нужно все это закодировать

Так что если вы не против кодирования еще нескольких классов и не полагаетесь на код, генерируемый VS, тогда я думаю, что этот подход является приемлемым.

В случае, если вы найдете это полезным, ниже первого проекта класса ServiceClient (там БУДУ быть ошибки и непредвиденные проблемы, поэтому, пожалуйста, использовать в учебных целях только):


ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ " КАК ЕСТЬ "И АВТОР ОТКАЗЫВАЕТСЯ ОТ ВСЕХ ГАРАНТИЙ В ОТНОШЕНИИ ДАННОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, ВКЛЮЧАЯ ВСЕ ПОДРАЗУМЕВАЕМЫЕ ГАРАНТИИ КОММЕРЧЕСКОЙ ЦЕННОСТИ И ПРИГОДНОСТИ. НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ АВТОР НЕ НЕСЕТ ОТВЕТСТВЕННОСТИ ЗА КАКИЕ-ЛИБО СПЕЦИАЛЬНЫЕ, ПРЯМЫЕ, КОСВЕННЫЕ ИЛИ КОСВЕННЫЕ УБЫТКИ ИЛИ ЛЮБЫЕ УБЫТКИ, КАКИЕ-ЛИБО, ПОЛУЧЕННЫЕ ОТ ПОТЕРИ ИСПОЛЬЗОВАНИЯ, ДАННЫХ ИЛИ ПРИБЫЛИ, КАК В ДЕЙСТВИИ КОНТРАКТА, НЕБРЕЖНОСТИ ИЛИ ДРУГИХ ТОРТИЧЕСКИХ ДЕЙСТВИЙ, ВОЗНИКАЮЩИХ ИЗ ИЛИ В СВЯЗИ С ИСПОЛЬЗОВАНИЕМ ИЛИ ПРОИЗВОДИТЕЛЬНОСТЬЮ ЭТОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ.

/// <summary> 
/// Abstract base class for Service Clients wishing to utilise an API 
/// via some service contract channel. 
/// </summary> 
public abstract class ServiceClient<T> : IDisposable where T : class { 

    /// <summary> 
    /// Creates and configures the ServiceClient and opens the connection 
    /// to the API via its Channel. 
    /// </summary> 
    protected ServiceClient(EndpointAddress endpoint, Binding binding) { 
     this.ServiceChannel = ChannelFactory<T>.CreateChannel(binding, endpoint); 
     (this.ServiceChannel as ICommunicationObject).Open(); 
    } 

    /// <summary> 
    /// Closes the client connection. 
    /// </summary> 
    public void Close() { 
     (this.ServiceChannel as ICommunicationObject).Close(); 
    } 

    /// <summary> 
    /// Releases held resources. 
    /// </summary> 
    public void Dispose() { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    /// <summary> 
    /// Closes the client connection and releases any additional resources. 
    /// </summary> 
    protected virtual void Dispose(bool disposing) { 
     if (disposed) return; 

     if (disposing) { 
      if (this.ServiceChannel != null) { 
       this.Close(); 
       this.ServiceChannel = null; 
       this.disposed = true; 
      } 
     } 
    } 

    /// <summary> 
    /// Provides a derived class access to the API via a dedicated channel. 
    /// </summary> 
    protected T ServiceChannel { get; private set; } 

    /// <summary> 
    /// Indicates if this instance has been disposed. 
    /// </summary> 
    private bool disposed = false; 
} 
3

Как пояснил here, прокси-генератор WCF (либо через SvcUtil или Add Reference Service) не выглядит в текущего сборки.

Вы должны отделить свои контракты данных и интерфейсов сервисов в другую библиотеку, например:

  • Service.Библиотека
    • Person интерфейс класса
    • IPeopleService
  • Service.Implementation, ссылки Service.Library
    • PeopleService класс
  • Service.Web, ссылается Service.Library и Service.Implementation
    • Web.config (WCF)
    • PeopleService.svc (конечная точка)
  • ClientLibrary, ссылки Электронная библиотека.
    • PersonServiceClient класса (генерируется из Service.Web, используя Service.Library.Person)

Так что, кажется, нет простого способа сделать это, уважая свой критерий «[без] выделенной модели библиотека ".

Если ваша единственная цель состоит в том, чтобы быть в состоянии поставить один DLL-файл, содержащий все Потребителем, потребности, взглянуть на ILMerge объединить сборки.