Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Client.Wasm/Components/StudentCard.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
</CardHeader>
<CardBody>
<UnorderedList Unstyled>
<UnorderedListItem>Номер <Strong>№X "Название лабораторной"</Strong></UnorderedListItem>
<UnorderedListItem>Вариант <Strong>№Х "Название варианта"</Strong></UnorderedListItem>
<UnorderedListItem>Выполнена <Strong>Фамилией Именем 65ХХ</Strong> </UnorderedListItem>
<UnorderedListItem><Link To="https://puginarug.com/">Ссылка на форк</Link></UnorderedListItem>
<UnorderedListItem>Номер <Strong>№1 "Кэширование"</Strong></UnorderedListItem>
<UnorderedListItem>Вариант <Strong>№39 "Программный проект"</Strong></UnorderedListItem>
<UnorderedListItem>Выполнил <Strong>Жидяев Дмитрий 6513</Strong> </UnorderedListItem>
<UnorderedListItem><Link To="https://github.com/Dmitrii14/cloud-development">Ссылка на форк</Link></UnorderedListItem>
</UnorderedList>
</CardBody>
</Card>
6 changes: 3 additions & 3 deletions Client.Wasm/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchBrowser": false,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "http://localhost:5127",
"environmentVariables": {
Expand All @@ -22,7 +22,7 @@
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchBrowser": false,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "https://localhost:7282;http://localhost:5127",
"environmentVariables": {
Expand All @@ -31,7 +31,7 @@
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchBrowser": false,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
Expand Down
2 changes: 1 addition & 1 deletion Client.Wasm/wwwroot/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
}
},
"AllowedHosts": "*",
"BaseAddress": ""
"BaseAddress": "http://localhost:5299/api/software-projects"
}
18 changes: 18 additions & 0 deletions CloudDevelopment.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ VisualStudioVersion = 17.14.36811.4
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client.Wasm", "Client.Wasm\Client.Wasm.csproj", "{AE7EEA74-2FE0-136F-D797-854FD87E022A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SoftwareProjects.AppHost", "SoftwareProjects\SoftwareProjects.AppHost\SoftwareProjects.AppHost.csproj", "{EC51E772-B7D1-4185-86B3-9E0ACF79C521}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SoftwareProjects.ServiceDefaults", "SoftwareProjects\SoftwareProjects.ServiceDefaults\SoftwareProjects.ServiceDefaults.csproj", "{D568B20D-5F65-3DB5-3289-0CA101BC09FE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SoftwareProjects.Api", "SoftwareProjects.Api\SoftwareProjects.Api.csproj", "{D333DF66-6F24-76D8-CFA9-228C3368FF0D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -15,6 +21,18 @@ Global
{AE7EEA74-2FE0-136F-D797-854FD87E022A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE7EEA74-2FE0-136F-D797-854FD87E022A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE7EEA74-2FE0-136F-D797-854FD87E022A}.Release|Any CPU.Build.0 = Release|Any CPU
{EC51E772-B7D1-4185-86B3-9E0ACF79C521}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC51E772-B7D1-4185-86B3-9E0ACF79C521}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC51E772-B7D1-4185-86B3-9E0ACF79C521}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC51E772-B7D1-4185-86B3-9E0ACF79C521}.Release|Any CPU.Build.0 = Release|Any CPU
{D568B20D-5F65-3DB5-3289-0CA101BC09FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D568B20D-5F65-3DB5-3289-0CA101BC09FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D568B20D-5F65-3DB5-3289-0CA101BC09FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D568B20D-5F65-3DB5-3289-0CA101BC09FE}.Release|Any CPU.Build.0 = Release|Any CPU
{D333DF66-6F24-76D8-CFA9-228C3368FF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D333DF66-6F24-76D8-CFA9-228C3368FF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D333DF66-6F24-76D8-CFA9-228C3368FF0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D333DF66-6F24-76D8-CFA9-228C3368FF0D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
143 changes: 25 additions & 118 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,128 +1,35 @@
# Современные технологии разработки программного обеспечения
[Таблица с успеваемостью](https://docs.google.com/spreadsheets/d/1an43o-iqlq4V_kDtkr_y7DC221hY9qdhGPrpII27sH8/edit?usp=sharing)
# Лабораторная работа №1 «Кэширование»

## Задание
### Цель
Реализация проекта микросервисного бекенда.
## Вариант №39 — «Программный проект»

### Задачи
* Реализация межсервисной коммуникации,
* Изучение работы с брокерами сообщений,
* Изучение архитектурных паттернов,
* Изучение работы со средствами оркестрации на примере .NET Aspire,
* Повторение основ работы с системами контроля версий,
* Интеграционное тестирование.
## Описание

### Лабораторные работы
<details>
<summary>1. «Кэширование» - Реализация сервиса генерации контрактов, кэширование его ответов</summary>
<br>

В рамках первой лабораторной работы необходимо:
* Реализовать сервис генерации контрактов на основе Bogus,
* Реализовать кеширование при помощи IDistributedCache и Redis,
* Реализовать структурное логирование сервиса генерации,
* Настроить оркестрацию Aspire.

</details>
<details>
<summary>2. «Балансировка нагрузки» - Реализация апи гейтвея, настройка его работы</summary>
<br>

В рамках второй лабораторной работы необходимо:
* Настроить оркестрацию на запуск нескольких реплик сервиса генерации,
* Реализовать апи гейтвей на основе Ocelot,
* Имплементировать алгоритм балансировки нагрузки согласно варианту.
Реализован сервис генерации данных о программных проектах с кэшированием ответов в Redis и оркестрацией через .NET Aspire

<br>
</details>
<details>
<summary>3. «Интеграционное тестирование» - Реализация файлового сервиса и объектного хранилища, интеграционное тестирование бекенда</summary>
<br>
## Что реализовано

В рамках третьей лабораторной работы необходимо:
* Добавить в оркестрацию объектное хранилище,
* Реализовать файловый сервис, сериализующий сгенерированные данные в файлы и сохраняющий их в объектном хранилище,
* Реализовать отправку генерируемых данных в файловый сервис посредством брокера,
* Реализовать интеграционные тесты, проверяющие корректность работы всех сервисов бекенда вместе.
### Генерация данных (Bogus)
- Класс `SoftwareProjectFaker` с `RuleFor` для каждого поля
- Генерация ФИО менеджера с отчеством, образованным от мужского имени с учётом пола (окончания «ович/овна», «евич/евна»)
- Локаль `ru` для русскоязычных имён

<br>
</details>
<details>
<summary>4. (Опционально) «Переход на облачную инфраструктуру» - Перенос бекенда в Yandex Cloud</summary>
<br>

В рамках четвертой лабораторной работы необходимо перенестиервисы на облако все ранее разработанные сервисы:
* Клиент - в хостинг через отдельный бакет Object Storage,
* Сервис генерации - в Cloud Function,
* Апи гейтвей - в Serverless Integration как API Gateway,
* Брокер сообщений - в Message Queue,
* Файловый сервис - в Cloud Function,
* Объектное хранилище - в отдельный бакет Object Storage,
### Кэширование (Redis + IDistributedCache)
- Сервис `SoftwareProjectService` с интерфейсом `ISoftwareProjectService`

<br>
</details>
### Структурное логирование
- Логирование на английском языке через `ILogger<T>`
- Структурные параметры `{ProjectId}` для корреляции
- Отдельные уровни: `Information` для успешных операций, `Warning` для ошибок кэша, `Error` для ошибок генерации

## Задание. Общая часть
**Обязательно**:
* Реализация серверной части на [.NET 8](https://learn.microsoft.com/ru-ru/dotnet/core/whats-new/dotnet-8/overview).
* Оркестрация проектов при помощи [.NET Aspire](https://learn.microsoft.com/ru-ru/dotnet/aspire/get-started/aspire-overview).
* Реализация сервиса генерации данных при помощи [Bogus](https://github.com/bchavez/Bogus).
* Реализация тестов с использованием [xUnit](https://xunit.net/?tabs=cs).
* Создание минимальной документации к проекту: страница на GitHub с информацией о задании, скриншоты приложения и прочая информация.
### CORS
- Разрешён только `GET`-запрос
- Доверенные URL вынесены в `appsettings.json` (`TrustedOrigins`)

**Факультативно**:
* Перенос бекенда на облачную инфраструктуру Yandex Cloud

Внимательно прочитайте [дискуссии](https://github.com/itsecd/cloud-development/discussions/1) о том, как работает автоматическое распределение на ревью.
Сразу корректно называйте свои pr, чтобы они попали на ревью нужному преподавателю.

По итогу работы в семестре должна получиться следующая информационная система:
<details>
<summary>C4 диаграмма</summary>
<img width="1584" height="771" alt="Современные_технологии_разработки_ПО_drawio" src="https://github.com/user-attachments/assets/71d6356f-7eb4-463d-b9f3-c953e5312993" />
</details>

## Варианты заданий
Номер варианта задания присваивается в начале семестра. Изменить его нельзя. Каждый вариант имеет уникальную комбинацию из предметной области, базы данных и технологии для общения сервиса генерации данных и сервера апи.

[Список вариантов](https://docs.google.com/document/d/1WGmLYwffTTaAj4TgFCk5bUyW3XKbFMiBm-DHZrfFWr4/edit?usp=sharing)
[Список предметных областей и алгоритмов балансировки](https://docs.google.com/document/d/1PLn2lKe4swIdJDZhwBYzxqFSu0AbY2MFY1SUPkIKOM4/edit?usp=sharing)

## Схема сдачи

На каждую из лабораторных работ необходимо сделать отдельный [Pull Request (PR)](https://docs.github.com/en/pull-requests).

Общая схема:
1. Сделать форк данного репозитория
2. Выполнить задание
3. Сделать PR в данный репозиторий
4. Исправить замечания после code review
5. Получить approve

## Критерии оценивания

Конкурентный принцип.
Так как задания в первой лабораторной будут повторяться между студентами, то выделяются следующие показатели для оценки:
1. Скорость разработки
2. Качество разработки
3. Полнота выполнения задания

Быстрее делаете PR - у вас преимущество.
Быстрее получаете Approve - у вас преимущество.
Выполните нечто немного выходящее за рамки проекта - у вас преимущество.
Не укладываетесь в дедлайн - получаете минимально возможный балл.

### Шкала оценивания

- **3 балла** за качество кода, из них:
- 2 балла - базовая оценка
- 1 балл (но не более) можно получить за выполнение любого из следующих пунктов:
- Реализация факультативного функционала
- Выполнение работы раньше других: первые 5 человек из каждой группы, которые сделали PR и получили approve, получают дополнительный балл

## Вопросы и обратная связь по курсу

Чтобы задать вопрос по лабораторной, воспользуйтесь [соответствующим разделом дискуссий](https://github.com/itsecd/cloud-development/discussions/categories/questions) или заведите [ишью](https://github.com/itsecd/cloud-development/issues/new).
Если у вас появились идеи/пожелания/прочие полезные мысли по преподаваемой дисциплине, их можно оставить [здесь](https://github.com/itsecd/cloud-development/discussions/categories/ideas).
### Оркестрация (.NET Aspire)
- Redis с RedisInsight
- API сервис ждёт Redis (`WaitFor(cache)`)
- Клиент WASM ждёт API сервис (`WaitFor(softwareProjectsApi)`)

### API
- Единственный эндпоинт: `GET /api/software-projects?id={id}`
- Minimal API
57 changes: 57 additions & 0 deletions SoftwareProjects.Api/Entities/SoftwareProject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
namespace SoftwareProjects.Api.Entities;

/// <summary>
/// Программный проект с информацией о бюджете, сроках и прогрессе
/// </summary>
public class SoftwareProject
{
/// <summary>
/// Идентификатор в системе
/// </summary>
public int Id { get; set; }

/// <summary>
/// Название проекта
/// </summary>
public required string ProjectName { get; set; }

/// <summary>
/// Заказчик проекта
/// </summary>
public required string CustomerCompany { get; set; }

/// <summary>
/// Менеджер проекта (Фамилия Имя Отчество)
/// </summary>
public required string ProjectManager { get; set; }

/// <summary>
/// Дата начала
/// </summary>
public DateOnly StartDate { get; set; }

/// <summary>
/// Плановая дата завершения
/// </summary>
public DateOnly PlannedEndDate { get; set; }

/// <summary>
/// Фактическая дата завершения
/// </summary>
public DateOnly? ActualEndDate { get; set; }

/// <summary>
/// Бюджет
/// </summary>
public decimal Budget { get; set; }

/// <summary>
/// Фактические затраты
/// </summary>
public decimal ActualCosts { get; set; }

/// <summary>
/// Процент выполнения (0-100)
/// </summary>
public int CompletionPercentage { get; set; }
}
32 changes: 32 additions & 0 deletions SoftwareProjects.Api/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using SoftwareProjects.Api.Services;

var builder = WebApplication.CreateBuilder(args);

builder.AddServiceDefaults();
builder.AddRedisDistributedCache("cache");

builder.Services.AddScoped<ISoftwareProjectService, SoftwareProjectService>();

var trustedOrigins = builder.Configuration
.GetSection("TrustedOrigins")
.Get<string[]>() ?? [];

builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.WithOrigins(trustedOrigins)
.WithMethods("GET")
.AllowAnyHeader();
});
});

var app = builder.Build();

app.MapDefaultEndpoints();
app.UseCors();

app.MapGet("/api/software-projects", async (int id, ISoftwareProjectService service) =>
Results.Ok(await service.GetById(id)));

app.Run();
38 changes: 38 additions & 0 deletions SoftwareProjects.Api/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:20046",
"sslPort": 44320
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5299",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7166;http://localhost:5299",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
14 changes: 14 additions & 0 deletions SoftwareProjects.Api/Services/ISoftwareProjectService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using SoftwareProjects.Api.Entities;

namespace SoftwareProjects.Api.Services;

/// <summary>
/// Сервис получения программного проекта с поддержкой кэширования
/// </summary>
public interface ISoftwareProjectService
{
/// <summary>
/// Получает программный проект по идентификатору из кэша или генерирует новый
/// </summary>
public Task<SoftwareProject> GetById(int id);
}
Loading
Loading