[ Полезный рекламный блок ]
Попробуйте свои силы в игре, где ваши навыки программирования на 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#?
Створювати різні інформаційні системи, що складаються з сайтів, мобільних клієнтів, десктопних додатків, телеграм-ботів тощо.
Переходьте до нас на сторінку Dijix і ознайомтеся з умовами навчання, ми спеціалізуємося тільки на індивідуальних заняттях, як для початківців, так і для просунутих програмістів. Ви можете взяти як одне заняття для опрацювання питання, що вас цікавить, так і кілька, для більш щільної роботи. Завдяки особистому кабінету, кожен студент підвищить якість свого навчання, у вашому розпорядженні:
- Доступ до пройденого матеріалу
- Тематичні статті
- Бібліотека книг
- Онлайн тестування
- Спілкування в закритих групах