Создание сайта-блога. Часть 1.
!!НАШ БЛОГ ПЕРЕЕХАЛ!!
Мы создали свой сайт! Все материалы, опубликованные в этом блоге, переехали туда.
Наш новый сайт maddevelop.ru
Решение "Blog" состоит из двух проектов: "Domain" и "WebUI". В первом хранятся классы сущностей нашего сайта и интерфейс взаимодействия с базой данных. Второй проект реализует взаимодействие пользователя с сущностями.
Сущности
Для работы с Entity Framework используется подход Code-First . Созданы три класса: Category, Post и Tag. У категорий есть идентификатор, название и коллекция постов с конкретной категорией.
public class Category { public int Id { get; set; } // Идентификатор public string Name { get; set; } // Название категории public ICollection<Post> Posts { get; set; } = new List<Post>(); // Коллекция постов в этой категории }
У тега также есть идентификатор, название и коллекция постов, подписанных данным тегом.
public class Tag { public int Id { get; set; } // Идентификатор public string Name { get; set; } // Название тега public virtual ICollection<Post> Posts { get; set; } = new List<Post>(); }
Пост описывается идентификатором, заголовком, автором, идентификатором категории, категорией, датой создания, небольшим вступлением, основным текстом и коллекцией тегов. Категория и пост связаны отношением "один-ко-многим": пост принадлежит одной категории, каждой категории принадлежат несколько постов. Тег и категория связаны отношением "многие-ко-многим". Каждое свойство тега описывается атрибутом в квадратных кавычках. Об этом будет позже.
public class Post { [HiddenInput(DisplayValue = false)] public int Id { get; set; } // Id [Display(Name = "Заголовок")] public string Title { get; set; } // Заголовок [Display(Name = "Автор")] public string Author { get; set; } // Автор поста [HiddenInput(DisplayValue = false)] public int? CategoryId { get; set; } // Идентификатор категории [Display(Name = "Категория")] public Category Category { get; set; } // Категория [Display(Name = "Дата")] public DateTime Date { get; set; } // Дата [Display(Name = "Вступление")] public string ShortText { get; set; } // Краткое описание [Display(Name = "Текст")] public string Text { get; set; } // Основной текст [Display(Name = "Теги")] public virtual ICollection<Tag> Tags { get; set; } = new List<Tag>(); // Коллекция тегов в данном посте. }
Далее создаём контекст данных, в котором свойствами являются коллекции сущностей.
public class EFDbContext : DbContext { public DbSet<Post> Posts { get; set; } public DbSet<Category> Categories { get; set; } public DbSet<Tag> Tags { get; set; } public EFDbContext() : base("DefaultConnection") { } }
Созданная Entity Framework база данных хранится в папке App-Data проекта WebUI. Для этого задана следующая строка подключения:
<connectionStrings> <add name="DefaultConnection" connectionString="Data Source=(localdb)\MSSQLLocalDB; AttachDbFilename='|DataDirectory|\Blog.mdf';Integrated Security=True; MultipleActiveResultSets=true" providerName="System.Data.SqlClient" /> </connectionStrings>
Хранилище постов
В решении используется инверсия управления для написания слабо связанного кода. Поэтому хранилище постов реализуется через интерфейс IPostRepository.
public interface IPostRepository { IEnumerable<Post> Posts { get; } IEnumerable<Tag> Tags { get; } IEnumerable<Category> Categories { get; } void SavePost(Post post); Post DeletePost(int postId); }
Хранилище постов должно иметь свойства с коллекциями постов, тегов и категорий. Для сохранения поста и удаления написаны методы SavePost и DeletePost. О них речь пойдёт при описании админ-панели.
Интерфейс IPostRepository реализуется классом EFBlogRepository:
public class EFBlogRepository : IPostRepository { EFDbContext context = new EFDbContext(); public IEnumerable<Post> Posts { get => context.Posts.Include(z => z.Category); } public IEnumerable<Tag> Tags { get => context.Tags; } public IEnumerable<Category> Categories { get => context.Categories; } public void SavePost(Post post) { //релизация будет написана позже } public Post DeletePost(int postId) { //релизация будет написана позже } }
Методы интерфейса реализуем при создании админ-панели. В описании класса хранилища следует обратить внимание на свойство Posts. Для отображения названий категорий на сайте при показе постов следует прикреплять в списку постов список категорий. Это обеспечивает использование метода Include() при извлечении постов из базы данных.
Инъекция зависимостей
Для того, чтобы класс контроллера не создавал экземпляр класса хранилища постов, в решении реализована инъекция зависимостей с помощью контейнера Ninject. В классе WebUI.NinjectWebCommon есть метод RegisterServices.
private static void RegisterServices(IKernel kernel) { DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel)); }
С помощью него создаётся класс NinjectDependencyResolver, в котором указывается, что при создании интерфейса IPostRepository следует создавать класс EFBlogRepository (данная процедура реализуется в методе AddBindings) :
public class NinjectDependencyResolver : IDependencyResolver { private IKernel kernel; public NinjectDependencyResolver(IKernel kernelParam) { kernel = kernelParam; AddBindings(); } public object GetService(Type serviceType) { return kernel.TryGet(serviceType); } public IEnumerable<object> GetServices(Type serviceType) { return kernel.GetAll(serviceType); } private void AddBindings() { // Здесь размещаются привязки kernel.Bind<IPostRepository>().To<EFBlogRepository>(); } }
Таким образом, создаются слабо связанные друг с другом части программы.
Сайт-блог создан на основе статьи
Professorweb.ru, создание интернет-магазина компьютерных игр
Ещё больше интересной информации на нашем Telegram канале.