Создание сайта-блога. Часть 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 канале.