响应/请求模式......如何塑造DTO?

时间:2014-08-28 21:35:47

标签: c#

我在服务层使用请求/响应模式。我有,例如:

public class FindPostsByTypeRequest : Request {
  public PostType Type { get; set; }
}

public class FindPostsByTypeResponse : Response {
  public IList<PostDto> Posts { get; set; }

  public class PostDto {
    public Int32 Id { get; set; }
    public String Title { get; set; }
    public String Text { get; set; }
  }
}

要处理此请求,我有一个处理程序:

public class FindPostsByTypeHandler : Handler<FindPostsByTypeRequest, FindPostsByTypeResponse> {

  private IContext _context;

  public FindPostsByTypeHandler(IContext context) {
    _context = context;
  }

  public FindPostsByTypeResponse Handle(FindPostsByTypeRequest request) {

    IList<FindPostsByTypeRequest.PostDto> posts = _context.Posts
     .Where(x => x.Type == request.Type)
     .Select(x => new FindPostsByTypeRequest.PostDto {
       Id = x.Id,
       Title = x.Title,
       Text = x.Text
     }).ToList();

     return new FindPostsByTypeResponse { Posts = posts };

  }

}

然后我有一个调度员并按如下方式使用它:

FindPostsByTypeRequest request = new FindPostsByTypeRequest { Type = type };

FindPostsByTypeResponse response = _dispatcher.Send<FindPostsByTypeResponse>(request);

我正在尝试解决的问题

当我按类型查找帖子有时我需要标签...有时候我不需要。 当然,我总是可以将标签放入我的DTO并使用或不使用... 但是应该避免装载我不需要的东西......

所以基本上我需要按类型获取帖子并“告诉”处理程序我需要什么数据。

我的想法是这样的:

_dispatcher.Send<FindPostsByTypeResponse<PostWithTagsModel>>(request);

PostWithTagsModel将是我需要的DTO。然后在我的处理程序中我会:

public class FindPostsByTypeHandler : Handler<FindPostsByTypeRequest, FindPostsByTypeResponse> {

  private IContext _context;

  public FindPostsByTypeHandler(IContext context) {
    _context = context;
  }

  public FindPostsByTypeResponse<PostsByType> Handle(FindPostsByTypeRequest request) {

    IList<FindPostsByTypeResponse.PostDto> posts = _context.Posts
     .Where(x => x.Type == request.Type)
     .Select(x => new FindPostsByTypeResponse.PostDto {
       Id = x.Id,
       Title = x.Title,
       Text = x.Text
     }).ToList();

     return new FindPostsByTypeResponse { Posts = posts };

  }

  public FindPostsByTypeResponse<PostsWithoutTagsDto> Handle(FindPostsByTypeRequest request) {

    IList<FindPostsByTypeResponse.PostsWithoutTagsDto> posts = _context.Posts
     .Where(x => x.Type == request.Type)
     .Select(x => new FindPostsByTypeResponse.PostsWithoutTagsDto {
       Id = x.Id,
       Title = x.Title,
       Text = x.Text
     }).ToList();

     return new FindPostsByTypeResponse { Posts = posts };

  }

  public FindPostsByTypeResponse<PostsWithTagsDto> Handle(FindPostsByTypeRequest request) {
    // Remaining code
  }

}

我不确定这是可能的,甚至是最好的方法......

基本上我需要“告诉”处理程序我需要哪种格式的响应中包含的DTO。

我怎么能或应该这样做?

1 个答案:

答案 0 :(得分:-1)

更新:

好的,如果不确切知道你的其他课程是什么样的,这里有一个近似的例子,我认为包含所有辅助课程对你有用。我把它放在Visual Studio中并确认它编译。在此方法中,ResponseTypeEnum子类实例根据可通过子类的枚举类上的ConstructItem方法的类型映射来确定要实例化的帖子类型。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestRequestResponse
{

    #region Generic portions

    /// <summary>
    /// Base request class
    /// </summary>
    public  class       Request {}

    /// <summary>
    /// Base response class
    /// </summary>
    public  class       Response {}

    /// <summary>
    /// Generic typed namespace for Response/Request support
    /// </summary>
    /// <typeparam name="tRequestResponseSet">Request/Response set type parameter (for namespace constraining)</typeparam>
    /// <typeparam name="tItem">Item type parameter</typeparam>
    /// <typeparam name="tSourceItem">Source item type parameter</typeparam>
    public  class       RequestResponseSet<tRequestResponseSet, tItem, tSourceItem>
            where       tRequestResponseSet : RequestResponseSet<tRequestResponseSet, tItem, tSourceItem>
            where       tItem               : RequestResponseSet<tRequestResponseSet, tItem, tSourceItem>.Item
    {

        /// <summary>
        /// Base item class
        /// </summary>
        public
        abstract    class   Item
        {
            public
            abstract    void    Initialize(tSourceItem sourceItem);
        }

        /// <summary>
        /// Base type specific subclassable enum class (see https://github.com/TyreeJackson/atomic/blob/master/Atomic.Net/DataTypes/SubclassableEnum.cs for a more generic version)
        /// </summary>
        public
        abstract    class   ResponseTypeEnum
        {
            private
            static      Dictionary
                        <
                            string,
                            ResponseTypeEnum
                        >                       allValues                       = new Dictionary<string,ResponseTypeEnum>();
            private     string                  type;
            private     Func<tItem>             constructItem;
            protected                           ResponseTypeEnum
                                                (
                                                    string      type, 
                                                    Func<tItem> constructItem
                                                )
            {
                this.type           = type;
                this.constructItem  = constructItem;
            }

            public      tItem                   ConstructItem(tSourceItem sourceItem)
            {
                var returnItem  = this.constructItem();
                returnItem.Initialize(sourceItem);
                return returnItem;
            }

            public
            static      ResponseTypeEnum        Select(string type)
            {
                ResponseTypeEnum returnTypeEnum = null;
                return  type == null || !ResponseTypeEnum.allValues.TryGetValue(type, out returnTypeEnum)
                        ?   null
                        :   returnTypeEnum;
            }

            public
            static
            implicit
            operator                            ResponseTypeEnum(string type)
            {
                return ResponseTypeEnum.Select(type);
            }

            public
            static
            implicit
            operator                            string(ResponseTypeEnum typeEnum)
            {
                return typeEnum == null ? null : typeEnum.type;
            }

        }

    }

    #endregion Generic portions

    #region Post specific portions

    /// <summary>
    /// Stored post /entity
    /// </summary>
    public  class       StoredPost
    {
        public  String          Type    { get; set; }
        public  Int32           Id      { get; set; }
        public  String          Title   { get; set; }
        public  String          Text    { get; set; }
        public  List<String>    Tags    { get; set; }
    }

    /// <summary>
    /// Post specific typed namespace
    /// </summary>
    public  class       PostsSet : RequestResponseSet<PostsSet, PostsSet.Post, StoredPost>
    {

        public  class   Types : ResponseTypeEnum
        {

            public  static      Types   Basic       = new Types("basic",    ()=>new Post());
            public  static      Types   WithTags    = new Types("withTags", ()=>new PostWithTags());

            protected                   Types(string type, Func<Post> createPost) : base(type, createPost) {}
        }

        public  class   Post : Item
        {
            public      Int32   Id      { get; set; }
            public      String  Title   { get; set; }
            public      String  Text    { get; set; }

            public
            override    void    Initialize(StoredPost sourceItem)
            {
                this.Id     = sourceItem.Id;
                this.Title  = sourceItem.Title;
                this.Text   = sourceItem.Text;
            }

        }

        public  class   PostWithTags : Post
        {
            public      List<String>    Tags    { get; set; }

            public
            override    void            Initialize(StoredPost sourceItem)
            {
                base.Initialize(sourceItem);
                this.Tags   = sourceItem.Tags;
            }
        }

    }

    /// <summary>
    /// Post specific response class
    /// </summary>
    public  class       FindPostsResponse : Response
    {
        public IList<PostsSet.Post> Posts   { get; set; }
    }

    /// <summary>
    /// Post specific request class
    /// </summary>
    public  class       FindPostsRequest : Request
    {
        public  string  Type    { get; set; }
    }

    /// <summary>
    /// Post specific context
    /// </summary>
    public  interface   IContext
    {
        IEnumerable<StoredPost> Posts   { get; set; }
    }

    /// <summary>
    /// Post specific handler
    /// </summary>
    public  class       FindPostHandler
    {

        private IContext            context;

        public                      FindPostHandler(IContext context)
        {
            this.context    = context;
        }

        public  FindPostsResponse   Handle(FindPostsRequest request)
        {
            var type    = PostsSet.Types.Select(request.Type);

            return
            type == null
            ?   null
            :   new FindPostsResponse()
                {
                    Posts   =
                    this.context.Posts
                    .Where(x => x.Type == request.Type)
                    .Select(x => type.ConstructItem(x))
                    .ToList()
                };
        }

    }

    #endregion Post specific portions

}