Wpf MVVM和服务对象

Wpf MVVM和服务对象,wpf,web-services,architecture,mvvm,Wpf,Web Services,Architecture,Mvvm,我们目前正在设计一个使用WPF的系统,该系统将使用web服务与其他系统进行通信 我们正在尝试尽可能少的层和映射(通过坚持最简单的方法来降低成本) 我们将使用MVVM模式 所以我们必须有一个视图模型 问题是,我们可以使用从服务返回的对象作为模型对象,还是应该将这些对象映射到客户端中定义的模型对象?您不必创建自己的模型层,但是:如果服务发生更改,您必须在引用模型的所有层中反映这些更改。如果现在创建自己的模型层,则会更安全,但工作量会更大。正如经常发生的那样:更多的工作最终会为你节省更多的工作。如果您

我们目前正在设计一个使用WPF的系统,该系统将使用web服务与其他系统进行通信

我们正在尝试尽可能少的层和映射(通过坚持最简单的方法来降低成本)

我们将使用MVVM模式

所以我们必须有一个视图模型


问题是,我们可以使用从服务返回的对象作为模型对象,还是应该将这些对象映射到客户端中定义的模型对象?

您不必创建自己的模型层,但是:如果服务发生更改,您必须在引用模型的所有层中反映这些更改。如果现在创建自己的模型层,则会更安全,但工作量会更大。正如经常发生的那样:更多的工作最终会为你节省更多的工作。如果您拥有该服务,并且确信永远不会更改它(哈哈),则不需要模型层


当然,这取决于服务检索到的对象是否完全符合您的需要。如果您使用大型对象的1、2个属性,这可能不是一个很好的选择…

是的,您可以使用WCF服务对象作为您的模型层(我们是),尽管如@fantasticfix所说,如果您的WCF服务器对象发生更改,您必须查找引用以修复它们


此外,如果要将整个模型公开给视图并绑定到模型的属性,则需要确保WCF服务器对象实现
INotifyPropertyChanged

,而您可以在模型中使用从服务返回的数据对象,有几个原因可以避免这种情况:

  • 您最终可能会在服务数据对象中引入数据绑定需求(、等)
  • 独立地发展服务和WPF应用程序变得更加困难,特别是在服务可能被多个应用程序使用的情况下
  • 您应该考虑使用模型内的服务来封装您的服务通勤作为一个或多个Web服务库。Web服务存储库允许您集中服务的访问逻辑,并为单元测试提供替换点,同时也为您提供了缓存以前服务操作结果的机会

    存储库充当不同域中的数据和操作之间的桥梁。存储库向数据源发出适当的查询,然后将结果集映射到业务实体,通常使用模式在表示之间进行转换

    您的视图模型将使用服务存储库来检索或持久化信息,存储库将处理对服务的调用,并将数据的服务表示映射到您最终将绑定到的特定于模型的类

    您可以更进一步,为服务存储库定义通用接口,使您能够围绕应用程序可能执行的基于CRUD的操作实现特定于服务的存储库

    通用服务存储库接口示例:

    /// <summary>
    /// Describes a service repository that separates the logic that retrieves, persists and maps data to the 
    /// domain model from the business logic that acts on the domain model.
    /// </summary>
    /// <typeparam name="TChannel">The type of channel produced by the channel factory used by the repository.</typeparam>
    /// <typeparam name="TMessage">The type of data contract to map to the domain entity of type <typeparamref name="T"/>.</typeparam>
    /// <typeparam name="T">The type of domain entity mediated by the repository.</typeparam>
    /// <typeparam name="TKey">The type of the key that uniquely identifies domain entities within the repository.</typeparam>
    public interface IServiceRepository<TChannel, TMessage, T, TKey> : IRepository<T, TKey> 
      where T : class
    {
      /// <summary>
      /// Occurs when the repository transitions from one state to another.
      /// </summary>
      event EventHandler<StateChangedEventArgs> StateChanged;
    
      /// <summary>
      /// Gets the configuration name used for the service endpoint.
      /// </summary>
      /// <value>
      /// The name of the endpoint in the application configuration file that is used 
      /// to create a channel to the service endpoint.
      /// </value>
      string EndpointConfigurationName
      {
          get;
      }
    
      /// <summary>
      /// Gets the current state of the service repository.
      /// </summary>
      /// <value>
      /// The current <see cref="CommunicationState"/> of the service repository.
      /// </value>
      CommunicationState State
      {
          get;
      }
    }
    
    /// <summary>
    /// Describes a repository that separates the logic that retrieves, persists and maps data to the domain model 
    /// from the business logic that acts on the domain model.
    /// </summary>
    /// <typeparam name="T">The type of domain entity mediated by the repository.</typeparam>
    /// <typeparam name="TKey">The type of the key that uniquely identifies domain entities within the repository.</typeparam>
    public interface IRepository<T, TKey> 
      where T : class
    {
      /// <summary>
      /// Occurs when a repository action has been completed.
      /// </summary>
      event EventHandler<RepositoryActionCompletedEventArgs<T>> Completed;
    
      /// <summary>
      /// Occurs when a repository action fails to execute.
      /// </summary>
      event EventHandler<RepositoryActionFailedEventArgs<T>> Failed;
    
      /// <summary>
      /// Gets a value indicating if the repository has been disposed of.
      /// </summary>
      /// <value>
      /// <see langword="true" /> if the repository has been disposed of; otherwise, <see langword="false" />.
      /// </value>
      bool IsDisposed
      {
          get;
      }
    
      /// <summary>
      /// Adds a new <paramref name="entity"/> to the data source layer.
      /// </summary>
      /// <param name="entity">The entity of type <typeparamref name="T"/> to insert into the data source layer.</param>
      /// <param name="callback">
      /// The optional <see langword="delegate"/> method that will be executed after the <paramref name="entity"/> is insert into the data source layer.
      /// </param>
      /// <returns>
      /// The <see cref="IRepository{T, Tkey}"/> object that this method was called on.
      /// </returns>
      /// <exception cref="ArgumentNullException">The <paramref name="entity"/> is a <see langword="null"/> reference (Nothing in Visual Basic).</exception>
      IRepository<T, TKey> Add(T entity, Action<T, Exception> callback = null);
    
      /// <summary>
      /// Retrieves all entities of type <typeparamref name="T"/> from the data source layer.
      /// </summary>
      /// <param name="callback">
      /// The optional <see langword="delegate"/> method that will be executed after all entities of type <typeparamref name="T"/> are retrieved from the data source layer.
      /// </param>
      /// <returns>
      /// The <see cref="IRepository{T, Tkey}"/> object that this method was called on.
      /// </returns>
      IRepository<T, TKey> Get(Action<IEnumerable<T>, Exception> callback = null);
    
      /// <summary>
      /// Retrieves an entity of type <typeparamref name="T"/> from the data source layer that 
      /// matches the specified <paramref name="key"/>.
      /// </summary>
      /// <param name="key">The unique identifier of the entity of type <typeparamref name="T"/> to retrieve from the data source layer.</param>
      /// <param name="callback">
      /// The optional <see langword="delegate"/> method that will be executed after an entity of type <typeparamref name="T"/> that matches the specified <paramref name="key"/> is retrieved from the data source layer.
      /// </param>
      /// <returns>
      /// The <see cref="IRepository{T, Tkey}"/> object that this method was called on.
      /// </returns>
      IRepository<T, TKey> Get(TKey key, Action<T, Exception> callback = null);
    
      /// <summary>
      /// Removes an existing <paramref name="entity"/> from the data source layer.
      /// </summary>
      /// <param name="entity">An entity of type <typeparamref name="T"/> to delete from the data source layer.</param>
      /// <param name="callback">
      /// The optional <see langword="delegate"/> method that will be executed after the <paramref name="entity"/> is removed from the data source layer.
      /// </param>
      /// <returns>
      /// The <see cref="IRepository{T, Tkey}"/> object that this method was called on.
      /// </returns>
      /// <exception cref="ArgumentNullException">The <paramref name="entity"/> is a <see langword="null"/> reference (Nothing in Visual Basic).</exception>
      IRepository<T, TKey> Remove(T entity, Action<T, Exception> callback = null);
    
      /// <summary>
      /// Updates an existing <paramref name="entity"/> within the data source layer.
      /// </summary>
      /// <param name="entity">The entity of type <typeparamref name="T"/> to update within the data source layer.</param>
      /// <param name="callback">
      /// The optional <see langword="delegate"/> method that will be executed after the <paramref name="entity"/> is updated within the data source layer.
      /// </param>
      /// <returns>
      /// The <see cref="IRepository{T, Tkey}"/> object that this method was called on.
      /// </returns>
      /// <exception cref="ArgumentNullException">The <paramref name="entity"/> is a <see langword="null"/> reference (Nothing in Visual Basic).</exception>
      IRepository<T, TKey> Update(T entity, Action<T, Exception> callback = null);
    }
    
    //
    ///描述一个服务存储库,该存储库分离用于检索、持久化数据并将数据映射到
    ///来自作用于域模型的业务逻辑的域模型。
    /// 
    ///存储库使用的通道工厂生成的通道类型。
    ///要映射到类型为的域实体的数据协定类型。
    ///存储库介导的域实体的类型。
    ///唯一标识存储库中的域实体的密钥类型。
    公共接口IServiceRepository:IRepository
    T:在哪里上课
    {
    /// 
    ///当存储库从一种状态转换到另一种状态时发生。
    /// 
    事件处理程序状态已更改;
    /// 
    ///获取用于服务端点的配置名称。
    /// 
    /// 
    ///所使用的应用程序配置文件中端点的名称
    ///创建到服务端点的通道。
    /// 
    字符串EndpointConfigurationName
    {
    得到;
    }
    /// 
    ///获取服务存储库的当前状态。
    /// 
    /// 
    ///服务存储库的当前名称。
    /// 
    通讯状态
    {
    得到;
    }
    }
    
    通用存储库接口示例:

    /// <summary>
    /// Describes a service repository that separates the logic that retrieves, persists and maps data to the 
    /// domain model from the business logic that acts on the domain model.
    /// </summary>
    /// <typeparam name="TChannel">The type of channel produced by the channel factory used by the repository.</typeparam>
    /// <typeparam name="TMessage">The type of data contract to map to the domain entity of type <typeparamref name="T"/>.</typeparam>
    /// <typeparam name="T">The type of domain entity mediated by the repository.</typeparam>
    /// <typeparam name="TKey">The type of the key that uniquely identifies domain entities within the repository.</typeparam>
    public interface IServiceRepository<TChannel, TMessage, T, TKey> : IRepository<T, TKey> 
      where T : class
    {
      /// <summary>
      /// Occurs when the repository transitions from one state to another.
      /// </summary>
      event EventHandler<StateChangedEventArgs> StateChanged;
    
      /// <summary>
      /// Gets the configuration name used for the service endpoint.
      /// </summary>
      /// <value>
      /// The name of the endpoint in the application configuration file that is used 
      /// to create a channel to the service endpoint.
      /// </value>
      string EndpointConfigurationName
      {
          get;
      }
    
      /// <summary>
      /// Gets the current state of the service repository.
      /// </summary>
      /// <value>
      /// The current <see cref="CommunicationState"/> of the service repository.
      /// </value>
      CommunicationState State
      {
          get;
      }
    }
    
    /// <summary>
    /// Describes a repository that separates the logic that retrieves, persists and maps data to the domain model 
    /// from the business logic that acts on the domain model.
    /// </summary>
    /// <typeparam name="T">The type of domain entity mediated by the repository.</typeparam>
    /// <typeparam name="TKey">The type of the key that uniquely identifies domain entities within the repository.</typeparam>
    public interface IRepository<T, TKey> 
      where T : class
    {
      /// <summary>
      /// Occurs when a repository action has been completed.
      /// </summary>
      event EventHandler<RepositoryActionCompletedEventArgs<T>> Completed;
    
      /// <summary>
      /// Occurs when a repository action fails to execute.
      /// </summary>
      event EventHandler<RepositoryActionFailedEventArgs<T>> Failed;
    
      /// <summary>
      /// Gets a value indicating if the repository has been disposed of.
      /// </summary>
      /// <value>
      /// <see langword="true" /> if the repository has been disposed of; otherwise, <see langword="false" />.
      /// </value>
      bool IsDisposed
      {
          get;
      }
    
      /// <summary>
      /// Adds a new <paramref name="entity"/> to the data source layer.
      /// </summary>
      /// <param name="entity">The entity of type <typeparamref name="T"/> to insert into the data source layer.</param>
      /// <param name="callback">
      /// The optional <see langword="delegate"/> method that will be executed after the <paramref name="entity"/> is insert into the data source layer.
      /// </param>
      /// <returns>
      /// The <see cref="IRepository{T, Tkey}"/> object that this method was called on.
      /// </returns>
      /// <exception cref="ArgumentNullException">The <paramref name="entity"/> is a <see langword="null"/> reference (Nothing in Visual Basic).</exception>
      IRepository<T, TKey> Add(T entity, Action<T, Exception> callback = null);
    
      /// <summary>
      /// Retrieves all entities of type <typeparamref name="T"/> from the data source layer.
      /// </summary>
      /// <param name="callback">
      /// The optional <see langword="delegate"/> method that will be executed after all entities of type <typeparamref name="T"/> are retrieved from the data source layer.
      /// </param>
      /// <returns>
      /// The <see cref="IRepository{T, Tkey}"/> object that this method was called on.
      /// </returns>
      IRepository<T, TKey> Get(Action<IEnumerable<T>, Exception> callback = null);
    
      /// <summary>
      /// Retrieves an entity of type <typeparamref name="T"/> from the data source layer that 
      /// matches the specified <paramref name="key"/>.
      /// </summary>
      /// <param name="key">The unique identifier of the entity of type <typeparamref name="T"/> to retrieve from the data source layer.</param>
      /// <param name="callback">
      /// The optional <see langword="delegate"/> method that will be executed after an entity of type <typeparamref name="T"/> that matches the specified <paramref name="key"/> is retrieved from the data source layer.
      /// </param>
      /// <returns>
      /// The <see cref="IRepository{T, Tkey}"/> object that this method was called on.
      /// </returns>
      IRepository<T, TKey> Get(TKey key, Action<T, Exception> callback = null);
    
      /// <summary>
      /// Removes an existing <paramref name="entity"/> from the data source layer.
      /// </summary>
      /// <param name="entity">An entity of type <typeparamref name="T"/> to delete from the data source layer.</param>
      /// <param name="callback">
      /// The optional <see langword="delegate"/> method that will be executed after the <paramref name="entity"/> is removed from the data source layer.
      /// </param>
      /// <returns>
      /// The <see cref="IRepository{T, Tkey}"/> object that this method was called on.
      /// </returns>
      /// <exception cref="ArgumentNullException">The <paramref name="entity"/> is a <see langword="null"/> reference (Nothing in Visual Basic).</exception>
      IRepository<T, TKey> Remove(T entity, Action<T, Exception> callback = null);
    
      /// <summary>
      /// Updates an existing <paramref name="entity"/> within the data source layer.
      /// </summary>
      /// <param name="entity">The entity of type <typeparamref name="T"/> to update within the data source layer.</param>
      /// <param name="callback">
      /// The optional <see langword="delegate"/> method that will be executed after the <paramref name="entity"/> is updated within the data source layer.
      /// </param>
      /// <returns>
      /// The <see cref="IRepository{T, Tkey}"/> object that this method was called on.
      /// </returns>
      /// <exception cref="ArgumentNullException">The <paramref name="entity"/> is a <see langword="null"/> reference (Nothing in Visual Basic).</exception>
      IRepository<T, TKey> Update(T entity, Action<T, Exception> callback = null);
    }
    
    //
    ///描述一个存储库,该存储库分离用于检索、持久化数据并将数据映射到域模型的逻辑
    ///从作用于域模型的业务逻辑。
    /// 
    ///存储库介导的域实体的类型。
    ///唯一标识存储库中的域实体的密钥类型。
    公共接口假定
    T:在哪里上课
    {
    /// 
    ///在存储库操作完成时发生。
    /// 
    事件处理程序已完成;
    /// 
    ///当存储库操作无法执行时发生。
    /// 
    事件处理程序失败;
    /// 
    ///获取一个值,该值指示存储库是否已被释放。
    /// 
    /// 
    ///如果存储库已被处置,则为。
    /// 
    布勒被揭穿了
    {
    得到;
    }
    /// 
    ///向数据源层添加新的。
    /// 
    ///要插入到数据源层中的类型的实体。
    /// 
    ///将插入数据源层后将执行的可选方法。
    /// 
    /// 
    ///调用此方法的对象。
    /// 
    ///是一个引用(在Visual Basic中没有)。
    i正向添加(T实体,动作回调=null);
    /// 
    ///从数据源层检索类型为的所有实体。
    /// 
    /// 
    ///从数据源层检索所有类型的实体后将执行的可选方法。
    /// 
    /// 
    ///调用此方法的对象。
    /// 
    IRepository Get(操作回调=null);
    /// 
    ///从要删除的数据源层检索类型为的实体
    ///匹配指定的。
    /// 
    ///实体o的唯一标识符