February 5, 2019

Создание сайта-блога. Часть 2.


!!НАШ БЛОГ ПЕРЕЕХАЛ!!

Мы создали свой сайт! Все материалы, опубликованные в этом блоге, переехали туда.

Наш новый сайт maddevelop.ru


Контроллер отображения постов

Контроллер BlogController выбирает из базы данных посты и передаёт их представлению для визуализации. На уровне класса у него есть переменные:

private IPostRepository postRepository;
private PostsListViewModel model = new PostsListViewModel();
private int pageSize = 3;

В переменную postRepository будет записываться экземпляр класса нашего хранилища. Как было сказано в первой части, из-за использования Ninject при этом будет создаваться класс EFBlogRepository.

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

public class PostsListViewModel
    {
        public IEnumerable<Post> Posts { get; set; }
        public IEnumerable<string> CategoryNames { get; set; }
        public IEnumerable<string> TagNames { get; set; }
        public PagingInfo PagingInfo { get; set; }
        public string CurrentCategory { get; set; }
        public string CurrentTag { get; set; }
        public string CurrentAuthor { get; set; }
        public Post FullPost { get; set; }
    }

Он содержит кроме списка постов (IEnumerable<Post> Posts) список названий категорий (IEnumerable<string> CategoryNames), список названий тегов (IEnumerable<string> TagNames), информацию о разбиении на страницы (PagingInfo PagingInfo), название текущей категории (string CurrentCategory), название выбранного тега (string CurrentTag), имя выбранного автора (string CurrentAuthor) и класс выбранного для чтения поста (Post FullPost).

Класс для пагинации (разбиения на страницы) содержит свойства:

public class PagingInfo
    {
        public int TotalItems { get; set; }     // Общее количество постов
        public int ItemsPerPage { get; set; }   // Количество товаров на одной странице
        public int CurrentPage { get; set; }    // Номер текущей страницы

        public int TotalPages                   // Количество страниц
        {
            get { return (int)Math.Ceiling((decimal)TotalItems / ItemsPerPage); }
        }
    }

Для удобства проверки работы пагинации отображаем на одной странице три поста: pageSize = 3.

В конструкторе контроллера сразу определяем из базы данных списки названий тегов и категорий:

public BlogController(IPostRepository repoPost)
        {
            postRepository = repoPost;
            model.CategoryNames = postRepository.Categories.Select(cat => cat.Name);
            model.TagNames = postRepository.Tags.Select(tag => tag.Name);
        }     

После этого приступаем к созданию метода действия, который возвращает класс ViewResult. Этот класс производит рендеринг представления в веб-страницу и возвращает ее в виде ответа клиенту.

public ViewResult List(string category, int page = 1)
        {            
            model = new PostsListViewModel
            {                
                Posts = postRepository.Posts
                    .Where(p => category == null || p.Category.Name == category)
                    .OrderByDescending(v => v.Date)
                    .Skip((page - 1) * pageSize)
                    .Take(pageSize),
                PagingInfo = new PagingInfo
                {
                    CurrentPage = page,
                    ItemsPerPage = pageSize,
                    TotalItems = category == null ? postRepository.Posts.Count()
                        : postRepository.Posts.Where(q => q.Category.Name == category).Count()
                },
                CurrentCategory = category
            };           
            return View(model);
        }

Класс возвращается с параметром, моделью представления. Для отображения списка постов нет надобности определять все его свойства, достаточно лишь задать свойства Posts и PagingInfo.

Метод List имеет два параметра: string category и int page = 1. Второй, как видим, является параметром со значением по умолчанию. Метод List используется не только для предоставления информации при первой загрузке сайта, но и при выборе какой-либо категории. Для второго случая в методе определяется свойство CurrentCategory.

Для выборки постов по тегам и авторам используются два метода действия:

public ViewResult TagList(string tag, int page = 1)
        {
            model = new PostsListViewModel
            {
                Posts = postRepository.Posts
                    .Where(p => tag == null || p.Tags.Select(v => v.Name).Contains(quot;#{tag}"))
                    .OrderByDescending(v => v.Date)
                    .Skip((page - 1) * pageSize)
                    .Take(pageSize),
                PagingInfo = new PagingInfo
                {
                    CurrentPage = page,
                    ItemsPerPage = pageSize,
                    TotalItems = tag == null ? postRepository.Posts.Count()
                        : postRepository.Posts.Count(p => p.Tags.Select(v => v.Name).Contains(quot;#{tag}"))
                },
                CurrentTag = tag
            };
            return View("List",model);
        }

        public ViewResult AuthorList(string author, int page = 1)
        {
            model = new PostsListViewModel
            {
                Posts = postRepository.Posts
                    .Where(p => p.Author == author)
                    .OrderByDescending(v => v.Date)
                    .Skip((page - 1) * pageSize)
                    .Take(pageSize),
                PagingInfo = new PagingInfo
                {
                    CurrentPage = page,
                    ItemsPerPage = pageSize,
                    TotalItems = postRepository.Posts.Count(p => p.Author == author)
                },
                CurrentAuthor = author
            };
            return View("List", model);
        }

Они не сильно отличаются от метода действия List(): есть соответствующие изменения в фильтрации, появляются определения свойств CurrentAuthor и CurrentTag. Так как названия этих методов отличаются от названия страницы представления List, то оно явно указывается в возвращаемом методе View("List", model).

Последний метод подготавливает данные для показа полного текста поста:

public ViewResult FullPost(int id)
        {
            model = new PostsListViewModel
            {
                Posts = new List<Post> {postRepository.Posts.SingleOrDefault(x => x.Id == id)},
                PagingInfo = new PagingInfo {CurrentPage = 1, ItemsPerPage = 1, TotalItems = 1},
                FullPost = postRepository.Posts.SingleOrDefault(x => x.Id == id) 
            };
            return View("List", model);
        }

Его параметром является идентификатор поста, на основании которого происходит его поиск в базе данных.



Ещё больше интересной информации на нашем Telegram канале.