【问题标题】:WCF reuse types in SAME libraryWCF 在 SAME 库中重用类型
【发布时间】:2014-01-24 12:00:16
【问题描述】:

我的项目结构如下:

  • Api 项目:包含 WCF svc 端点
  • ClientServer 库项目:包含服务器使用的类

我想要做的是将我的 ClientServer 库作为一个包罗万象的 API 包装器分发,客户端可以使用它来连接到 API 并提取信息。

由于 API 使用 ClientServer 库中定义的类型,我希望在 ClientServer 库中添加 ServiceReference 可以理解 API 返回类型实际上是来自与引用相同的库.

我这样做的原因是,我只需要在一个地方定义发送到服务器和从服务器发送的类,而且还为客户端提供一种“内置”机制,以便在不了解任何相关知识的情况下使用 API 如何它连接和不连接其他依赖库(例如专用模型库)。

下面是我希望它如何工作的基本示例

客户端服务器库:

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

[ServiceContract]
public interface IPeopleService {

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

API 项目

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

鉴于上面的示例,我想将 PeopleService 的引用添加到 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" });

但目前它正在重新生成所有类。 我尝试在“添加服务对话框”中勾选和取消勾选所有选项,但结果始终相同。

希望我已经很好地解释了我的意图? 谢谢。

编辑:所有项目都使用 C# .NET v4,因此没有差异。

【问题讨论】:

  • Web 服务不必像 WCF 那样难。使用ServiceStack
  • @rmayer06 感谢您的链接,但不幸的是,使用不同的框架不是 atm 的选项。尤其是每个开发人员要花费 200 美元。无论如何,谢谢,感谢您的意见。
  • @rmayer06 另外,问题不是服务端所必需的,我正在寻找一种方法来创建一个重用现有类型而不是生成自己的类型的包装库。
  • ServiceStack 3 是免费的——您可能需要四处点击才能找到它。 v4 的许可证模型已更改(但 3 可以满足您在没有 WCF 自动生成垃圾的情况下所需的一切)。只是我的想法 - 我不使用 WCF 来解决您遇到的问题(还有很多很多)。
  • @rmayer06 仅供参考,API 实际上相当广泛并且已经在线,我的任务不是更改它的框架或从头开始重写它。我的任务是创建一个自包含的包装库,我的客户可以使用它来避免他们必须添加引用并自行配置它们。 ServiceStack 对于一个新的新建项目来说看起来很干净,但由于当前的架构,我无法切换。

标签: c# wcf web-services service-reference


【解决方案1】:

正如here 解释的那样,WCF 代理生成器(通过 svcutil 或添加服务引用)不在当前程序集中查找。

您必须将数据合同和服务接口分离到另一个库中,如下所示:

  • Service.Library
    • 人物类
    • IPeopleService 接口
  • Service.Implementation,参考 Service.Library
    • PeopleService 类
  • Service.Web,引用 Service.LibraryService.Implementation
    • Web.config (WCF)
    • PeopleService.svc(端点)
  • ClientLibrary,引用 Service.Library
    • PersonServiceClient 类(从 Service.Web 生成,使用 Service.Library.Person

因此,在尊重您的标准“[没有]专用模型库”的同时,似乎没有简单的方法可以做到这一点。

如果您的唯一目标是能够提供一个包含所有消费者需求的 DLL 文件,请查看ILMerge 以组合程序集。

【讨论】:

    【解决方案2】:

    好的,所以最后为了完全满足我的所有要求,我基本上不得不放弃使用自动化工具并亲自手工制作每个客户的想法。

    这并不像听起来那么难。


    我基本上创建了一个抽象的通用基类 ServiceClient,其中 T 是一个 ServiceContract 接口(我已经定义了)

    ServiceClient 的工作类似于 VS 和 CLI 工具(svcutil 等)生成的工作。它通过 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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-07
      • 2011-01-26
      • 2011-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多