Go to my github

《ASP.ENT Core 与 RESTful API 开发实战》-- (第4章)-- 读书笔记(上)

第 4 章 资源操作

4.1 项目创建

从本章起,我们将创建一个在线图书馆项目,通过这个 Web API 应用程序来实际地熟悉并掌握如何使用 ASP.NET Core 创建 RESTful API 应用

这个项目由两个实体,作者和图书组成,我们将使用数据传输对象(DTO)来表示这两种资源

新建一个 ASP.NET Core 项目 Library.API,项目模板选择 API

创建两个 DTO

namespace Library.API.Models
{
    public class AuthorDto
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public string Email { get; set; }
    }
}

namespace Library.API.Models
{
    public class BookDto
    {
        public Guid Id { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public int Pages { get; set; }
        public Guid AuthorId { get; set; }
    }
}

4.2 使用内存数据

创建内存数据源 LibraryMockData,专门用于提供模拟数据

namespace Library.API.Data
{
    public class LibraryMockData
    {
        // 获取 LibraryMockData 实例
        public static LibraryMockData Current { get; } = new LibraryMockData();
        public List<AuthorDto> Authors { get; set; }
        public List<BookDto> Books { get; set; }

        public LibraryMockData()
        {
            var authorId1 = Guid.NewGuid();
            var authorId2 = Guid.NewGuid();

            Authors = new List<AuthorDto>
            {
                new AuthorDto
                {
                    Id = authorId1,
                    Name = "Author 1",
                    Age = 46,
                    Email = "Author.com",
                },
                new AuthorDto
                {
                    Id = authorId2,
                    Name = "Author 2",
                    Age = 38,
                    Email = "Author2.com",
                }
            };

            Books = new List<BookDto>
            {
                new BookDto
                {
                    Id = Guid.NewGuid(),
                    Title = "Book 1",
                    Description = "Description of Book 1",
                    Pages = 281,
                    AuthorId = authorId1,
                },                new BookDto
                {
                    Id = Guid.NewGuid(),
                    Title = "Book 2",
                    Description = "Description of Book 2",
                    Pages = 370,
                    AuthorId = authorId2,
                }
            };
        }
    }
}

接下来,我们使用仓储模式来访问 LibraryMockData 类中的数据

仓储模式作为领域动态设计(DDD)的一部分,用于解耦业务逻辑层与数据访问层

实现仓储模式的方法有许多种,最简单的一种是对每一个与数据库交互的业务对象创建一个仓储接口以及实现,还有一种就是创建一个通用的仓储接口,所有其他仓储接口都继承这个接口,下面的例子就是通用的仓储接口

namespace Library.API.Services
{
    public interface IRepositoryBase<T>
    {
        IEnumerable<T> FindAll();
        IEnumerable<T> FindByCondition(Expression<Func<T, bool>> expression);
        void Create(T entity);
        void Update(T entity);
        void Delete(T entity);
        void Save();
    }
}

本章使用第一种方法来实现仓储模式,创建仓储接口

namespace Library.API.Services
{
    public interface IAuthorRepository
    {
        IEnumerable<AuthorDto> GetAuthors();
        AuthorDto GetAuthor(Guid authorId);
        bool IsAuthorExists(Guid authorId);
    }
}

namespace Library.API.Services
{
    public interface IBookRepository
    {
        IEnumerable<BookDto> GetBooksForAuthor(Guid authorId);
        BookDto GetBookForAuthor(Guid authorId, Guid bookId);
    }
}

接下来创建接口的具体仓储实现

namespace Library.API.Services
{
    public class AuthorMockRepository : IAuthorRepository
    {
        public IEnumerable<AuthorDto> GetAuthors()
        {
            return LibraryMockData.Current.Authors;
        }

        public AuthorDto GetAuthor(Guid authorId)
        {
            var author = LibraryMockData.Current.Authors.FirstOrDefault(au => au.Id == authorId);
            return author;
        }

        public bool IsAuthorExists(Guid authorId)
        {
            return LibraryMockData.Current.Authors.Any(au => au.Id == authorId);
        }
    }
}

namespace Library.API.Services
{
    public class BookMockRepository : IBookRepository
    {
        public IEnumerable<BookDto> GetBooksForAuthor(Guid authorId)
        {
            return LibraryMockData.Current.Books.Where(b => b.AuthorId == authorId).ToList();
        }

        public BookDto GetBookForAuthor(Guid authorId, Guid bookId)
        {
            return LibraryMockData.Current.Books.FirstOrDefault(b => b.AuthorId == authorId && b.Id == bookId);
        }
    }
}

为了在程序中使用上述两个仓储接口,还需要在 ConfigureServices 方法中注入

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddScoped<IAuthorRepository, AuthorMockRepository>();
    services.AddScoped<IBookRepository, BookMockRepository>();
}

4.3 创建控制器

首先从依赖注入容器中获取之前定义的仓储接口

namespace Library.API.Controllers
{
    [Route("api/authors")]
    [ApiController]
    public class AuthorController : ControllerBase
    {
        public IAuthorRepository AuthorRepository { get; }

        public AuthorController(IAuthorRepository authorRepository)
        {
            AuthorRepository = authorRepository;
        }
    }
}

4.4 获取资源

获取集合

[HttpGet]
public ActionResult<List<AuthorDto>> GetAuthors()
{
    return AuthorRepository.GetAuthors().ToList();
}

获取单个资源

[HttpGet("{authorId}")]
public ActionResult<AuthorDto> GetAuthor(Guid authorId)
{
    var author = AuthorRepository.GetAuthor(authorId);

    if (author == null)
    {
        return NotFound();
    }
    else
    {
        return author;
    }
}

获取父/子形式资源

namespace Library.API.Controllers
{
    [Route("api/authors/{authorId}/books")]
    [ApiController]
    public class BookController : ControllerBase
    {
        public IAuthorRepository AuthorRepository { get; }
        public IBookRepository BookRepository { get; }

        public BookController(IAuthorRepository authorRepository, IBookRepository bookRepository)
        {
            AuthorRepository = authorRepository;
            BookRepository = bookRepository;
        }

        [HttpGet]
        public ActionResult<List<BookDto>> GetBooks(Guid authorId)
        {
            if (!AuthorRepository.IsAuthorExists(authorId))
            {
                return NotFound();
            }

            return BookRepository.GetBooksForAuthor(authorId).ToList();
        }
    }
}

获取某一个具体的子级资源

[HttpGet("{bookId}")]
public ActionResult<BookDto> GetBook(Guid authorId, Guid bookId)
{
    if (!AuthorRepository.IsAuthorExists(authorId))
    {
        return NotFound();
    }

    var targetBook = BookRepository.GetBookForAuthor(authorId, bookId);
    if (targetBook == null)
    {
        return NotFound();
    }

    return targetBook;
}

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。

posted @ 2020-06-28 01:30  郑子铭  阅读(414)  评论(0编辑  收藏  举报