[ Полезный рекламный блок ]
Попробуйте свои силы в игре, где ваши навыки программирования на C# станут решающим фактором. Переходите по ссылке 🔰.
В этой статье, разработаем простой счетчик статистики, для отслеживания количества уникальных посетителей и просмотров сайта.
Для примера, создадим простой проект ASP.NET Core Web Application (Веб-приложение ASP.NET Core), который будет содержать пару страниц, собственный компонент middleware и минимальную логику работы с базой данных на основе EF Core.
Я ожидаю от вас минимальные знания концепций Entity Framework Core и фреймворка MVC, поэтому в некоторых местах, вдаваться в подробности не стану.
Статистика посещений для веб приложения Asp.net Core 7
Конфигурирование поставщика базы данных и класса контекста
Создание контроллера и представлений
Создание проекта
Чтобы создать проект VisitsCounter, запустите Visual Studio и выберите в меню File (Файл) — New Project (Создать Проект). Укажите шаблон проекта ASP.NET Core Web Application (Веб-приложение ASP.NET Core).
Введите VisitsCounter, в поле Name, на следующей странице укажите Framework .Net 7.0 и нажмите кнопку Create:
Конфигурирование подключения
Для начала загрузим библиотеку Entity Framework Core Sql Server:
Или через Package Manager Console:
1 |
Install-Package Microsoft.EntityFrameworkCore.SqlServer |
Перейдем в файл appsettings.json и пропишем конфигурацию подключения и логирования:
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "ConnectionStrings": { "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=visitsCounterDb;Trusted_Connection=True;" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Information" } }, "AllowedHosts": "*" } |
Строки подключения определяются в файле appsettings.json, в коде выше, представлено определение строки подключения для БД приложения GameStore. В проекте применяется версия LocalDB продукта SQL Server, которая спроектирована специально для разработчиков и не требует конфигурирования или учетных данных.
Вы обязаны обеспечить, чтобы строка подключения была единственной неразрывной строкой. Формат строки подключения специфичен для каждого сервера баз данных.
Даже в проекте, сохраняющем лишь небольшой объем данных, важно понимать запросы и команды SQL, которые инфраструктура Entity Framework Core посылает серверу баз данных.
Модель и Репозиторий
Модель для приложения VisitsCounter будет основываться на посетителях, а именно: дате визита, количество визитов и количестве просмотров за сутки. Создайте папку Models и добавьте в нее файл класса по имени Visitor.cs со следующим содержимым:
1 2 3 4 5 6 7 |
public class Visitor { public Guid Id { get; set; } public int Visitors { get; set; } public int Views { get; set; } public DateTime Date { get; set; } } |
В обеспечении доступа к данным в БД инфраструктура Entity Framework Core полагается на класс контекста БД. Чтобы снабдить пример приложения контекстом, добавьте в папку Models файл класса по имени ApplicationContext.cs со следующим кодом:
1 2 3 4 5 6 7 8 |
public class ApplicationContext : DbContext { public ApplicationContext(DbContextOptions<ApplicationContext> context) : base(context) { } public DbSet<Visitor> Visitors { get; set; } } |
Мне нравится обеспечивать согласованный доступ к данным в приложении с использованием паттерна «Хранилище» (Repository), в котором интерфейс определяет свойства и методы, предназначенные для доступа к данным, а для работы с механизмом хранения данных применяется класс реализации.
Преимущество использования паттерна «Хранилище» связано с облегчением модульного тестирования части MVC приложения, а также с тем, что детали, касающиеся хранения данных, скрыты от остальных частей приложения.
Чтобы создать интерфейс хранилища, создайте папку Interfaces и добавьте в нее файл интерфейса по имени IVisitor.cs со следующим содержимым:
1 2 3 4 5 6 |
public interface IVisitor { Task<IEnumerable<Visitor>> GetStatisticsByDate(DateTime startDate, DateTime endDate); Task IncrementVisitors(); Task IncrementViews(); } |
Метод GetStatisticsByDate(), позволит получать статистику по указанным временным отрезкам, методы IncrementVisitors() и IncrementViews(), необходимы для увеличения количества просмотров и посетителей ресурса.
Теперь определим класс реализации хранилища, чтобы обращаться к данным через класс контекста, создадим папку Repository и добавим туда класс по имени VisitorRepository, со следующим содержимым:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
public class VisitorRepository : IVisitor { private ApplicationContext _context; public VisitorRepository(ApplicationContext context) { _context = context; } public async Task<IEnumerable<Visitor>> GetStatisticsByDate(DateTime startDate, DateTime endDate) { return await _context.Visitors.Where(e => e.Date >= startDate && e.Date <= endDate).ToListAsync(); } public async Task IncrementViews() { if (_context.Visitors.Any(e => e.Date.Equals(DateTime.Today))) { await _context.Database.ExecuteSqlRawAsync($"UPDATE Visitors SET [Views] += 1 WHERE Date = '{DateTime.Today.ToString("yyyy/MM/dd")}'"); } else { await _context.Visitors.AddAsync(new Visitor { Date = DateTime.Today, Visitors = 1, Views = 1 }); await _context.SaveChangesAsync(); } } public async Task IncrementVisitors() { if (_context.Visitors.Any(e => e.Date.Equals(DateTime.Today))) { await _context.Database.ExecuteSqlRawAsync($"UPDATE Visitors SET [Visitors] += 1, [Views] += 1 WHERE Date = '{DateTime.Today.ToString("yyyy/MM/dd")}'"); } else { await _context.Visitors.AddAsync(new Visitor { Date = DateTime.Today, Visitors = 1, Views = 1 }); await _context.SaveChangesAsync(); } } } |
Конфигурирование поставщика базы данных и класса контекста
Добавьте в класс Program.cs операторы конфигурации, чтобы сообщить инфраструктуре Entity Framework Core о том, каким образом использовать строку подключения, которую должен применять поставщик БД, и как управлять классом контекста:
1 2 3 4 5 6 7 |
IConfigurationRoot _confString = new ConfigurationBuilder(). SetBasePath(AppDomain.CurrentDomain.BaseDirectory).AddJsonFile("appsettings.json").Build(); builder.Services.AddDbContext<ApplicationContext>(options => options.UseSqlServer(_confString.GetConnectionString("DefaultConnection"))); builder.Services.AddTransient<IVisitor, VisitorRepository>(); |
Расширяющий метод AddDbContext<T>() применяется для настройки класса контекста, указывает инфраструктуре Entity Framework Core, какой поставщик БД использовать (в этом случае посредством метода UseSqlServer(), но для каждого поставщика БД предусмотрен свой метод), и предоставляет строку подключения.
Создание базы данных
В предыдущем разделе для инфраструктуры Entity Framework Core был указан вид данных, подлежащих хранению, и способ подключения к серверу баз данных. Далее необходимо создать БД.
Инфраструктура Entity Framework Core управляет базами данных через средство, называемое миграциями, которые представляют собой наборы изменений, создающих или модифицирующих БД с целью ее синхронизации с моделью данных.
Для работы с миграцией, необходимо скачать следующую библиотеку:
1 |
Microsoft.EntityFrameworkCore.Tools |
Для создания миграции в окне Package Manager Console введите следующую команду:
1 |
Add-Migration Init |
Просто создать миграцию, которая представляет собой всего лишь набор инструкций, недостаточно. Инструкции миграции должны быть выполнены, чтобы создать БД, которая сможет хранить данные приложения. Для выполнения инструкций миграции, в окне Package Manager Console выполните команду:
1 |
Update-Database |
Инфраструктура Entity Fгamework Core подключится к серверу баз данных, указанному в строке подключения, и выполнит операторы в миграции. Результатом будет БД, которую можно использовать для хранения объектов Visitor.
Создание класса middleware
В проект добавим папку Middleware, а в ней создадим класс VisitorCounterMiddleware, со следующим содержимым:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public class VisitorCounterMiddleware { private readonly RequestDelegate _requestDelegate; public VisitorCounterMiddleware(RequestDelegate requestDelegate) { _requestDelegate = requestDelegate; } public async Task Invoke(HttpContext context, IVisitor _visitors) { string visitorId = context.Request.Cookies["VisitorId"]; if (visitorId == null) { context.Response.Cookies.Append("VisitorId", Guid.NewGuid().ToString(), new CookieOptions() { Path = "/", HttpOnly = true, Secure = false, Expires = DateTimeOffset.UtcNow.AddDays(1) }); await _visitors.IncrementVisitors(); } else { await _visitors.IncrementViews(); } await _requestDelegate(context); } } |
Класс middleware обязан содержать конструктор, который принимает параметр типа RequestDelegate. Через этот параметр он получает ссылку на делегат запроса, который стоит следующим в конвейере обработки запроса.
Также в классе должен быть определен метод, который должен называться либо Invoke, либо InvokeAsync. Причем этот метод должен возвращать объект Task и принимать в качестве параметра контекст запроса — объект HttpContext. Данный метод собственно и будет обрабатывать запрос.
Суть действия класса заключается в том, что мы проверяем создана ли для текущего посетителя кука с именем “VisitorId”, если создана, то такой посетитель уже был сегодня на сайте, поэтому необходимо увеличить только количество просмотров. Если же кука отсутствует, значит это новый посетитель, и по мимо, просмотров, увеличиваем количество посетителей. В конце метода, передаем запрос следующему компоненту, вызвав метод _next.Invoke().
Для добавления компонента middleware, который представляет класс, в конвейер обработки запроса применяется метод UseMiddleware(). Добавим в класс Program.cs, следующую строку:
1 |
app.UseMiddleware(typeof(VisitorCounterMiddleware)); |
С помощью метода UseMiddleware<T>, в конструктор объекта VisitorCounterMiddleware будет внедряться объект для параметра RequestDelegate next. Поэтому явным образом передавать значение для этого параметра нам не нужно.
Создание контроллера и представлений
Для тестирования приложения, определим в контроллере HomeController действие для просмотра статистики посещений и оставим действия по умолчанию, для возможности навигации по сайту:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public class HomeController : Controller { private readonly IVisitor _visitors; public HomeController(IVisitor visitors) { _visitors = visitors; } public async Task<IActionResult> GetStatistics() { var today = DateTime.Today; var statistic = await _visitors.GetStatisticsByDate(today.AddMonths(-1), today); return View(statistic); } public IActionResult Index() { return View(); } public IActionResult Privacy() { return View(); } [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } } |
В действии GetStatistics, получаем информацию по просмотрам и посетителям за прошедший месяц (можете передавать любые диапазоны) и передаем в представление. В папке Views / Home, определим представление GetStatistics.cshtml, со следующим содержимым:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@{ ViewData["Title"] = "Site Statistics"; } @model IEnumerable<Visitor> <table class="table"> <tr> <th>Date</th> <th>Visitors</th> <th>Views</th> </tr> @foreach (Visitor visitor in Model) { <tr> <td>@visitor.Date.ToShortDateString()</td> <td>@visitor.Visitors</td> <td>@visitor.Views</td> </tr> } </table> |
Запустим приложение, пооткрываем разные страницы, после передйем по адресу и посмотрим статистику. Можете удалить куку, что бы создать нового посетителя или зайти на сайт в режиме инкогнито.
Теперь перейдем по адресу: https://localhost:XXXX/Home/GetStatistics
На этом все. Приложение содержит минимальный функционал, для успешного использования в проектах.
Вы можете скачать исходный код в моем репозитории — Github.
Поделитесь вашим мнением в комментариях, вы используете готовые сервисы аналитики для ваших сайтов или пишите собственные?
Так же вам может быть интересна предыдущая статья:
Вы начинающий программист, который хочет изучить все тонкости языка C#?
Пройдите наш тест на 13 вопросов, чтобы узнать, как много вы знаете на самом деле!
C# Braincheck |
Вы хотите научится писать код на языке программирования C#?
Создавать различные информационные системы, состоящие из сайтов, мобильных клиентов, десктопных приложений, телеграмм-ботов и т.д.
Переходите к нам на страницу Dijix и ознакомьтесь с условиями обучения, мы специализируемся только на индивидуальных занятиях, как для начинающих, так и для более продвинутых программистов. Вы можете взять как одно занятие для проработки интересующего Вас вопроса, так и несколько, для более плотной работы. Благодаря личному кабинету, каждый студент повысит качество своего обучения, в вашем распоряжении:
- Доступ к пройденному материалу
- Тематические статьи
- Библиотека книг
- Онлайн тестирование
- Общение в закрытых группах
Живи в своем мире, программируй в нашем.