Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 3 additions & 3 deletions Client.Wasm/Components/DataCard.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<CardDeck>
<Card>
<CardHeader>
<Heading Size="HeadingSize.Is5"><Icon Name="IconName.Table" /> Характеристики текущего объекта</Heading>
<Heading Size="HeadingSize.Is5"><Blazorise.Icons.FontAwesome.Icon Name="IconName.Table" /> Характеристики текущего объекта</Heading>
</CardHeader>
<CardBody>
<Table Bordered >
Expand Down Expand Up @@ -43,7 +43,7 @@

<Card Margin="Margin.Is3.OnY">
<CardHeader>
<Heading Size="HeadingSize.Is5"><Icon Name="IconName.Send" /> Запросить новый объект</Heading>
<Heading Size="HeadingSize.Is5"><Blazorise.Icons.FontAwesome.Icon Name="IconName.Send" /> Запросить новый объект</Heading>
</CardHeader>
<CardBody>
<Row>
Expand All @@ -54,7 +54,7 @@
<NumericEdit TValue="int" @bind-Value="@Id"/>
</Column>
<Column ColumnSize="ColumnSize.Is4">
<Button Clicked=RequestNewData Color="Color.Primary">Запросить данные <Icon Name="IconName.ArrowRight" /></Button>
<Button Clicked=RequestNewData Color="Color.Primary">Запросить данные <Blazorise.Icons.FontAwesome.Icon Name="IconName.ArrowRight" /></Button>
</Column>
</Row>
</CardBody>
Expand Down
10 changes: 5 additions & 5 deletions Client.Wasm/Components/StudentCard.razor
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<Card>
<CardHeader>
<Heading Size="HeadingSize.Is5"><Icon Name="IconName.User" /> Лабораторная работа</Heading>
<Heading Size="HeadingSize.Is5"><Blazorise.Icons.FontAwesome.Icon Name="IconName.User" /> Лабораторная работа</Heading>
</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>№30 "Кредитная заявка"</Strong></UnorderedListItem>
<UnorderedListItem>Выполнена <Strong>Панкеевым Глебом 6512</Strong> </UnorderedListItem>
<UnorderedListItem><Link To="https://github.com/Pancake2021/cloud-development/tree/lab1/pankeev-gleb">Ссылка на мой форк</Link></UnorderedListItem>
</UnorderedList>
</CardBody>
</Card>
5 changes: 3 additions & 2 deletions Client.Wasm/_Imports.razor
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
@using Microsoft.JSInterop
@using Client.Wasm.Layout
@using Client.Wasm.Components
@using Blazorise
@using Blazorise.Components
@using Blazorise
@using Blazorise.Bootstrap
@using Blazorise.Icons.FontAwesome
@using System.Text.Json
@using System.Text.Json.Nodes
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:5179/api/creditapplication"
}
27 changes: 25 additions & 2 deletions CloudDevelopment.sln
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36811.4
VisualStudioVersion = 17.13.35931.197
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}") = "ProjectApp.Api", "ProjectApp.Api\ProjectApp.Api.csproj", "{E7D4CA8B-53EA-9676-D96D-BE2F0CB11054}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectApp.Domain", "ProjectApp.Domain\ProjectApp.Domain.csproj", "{CC5A9873-4CC3-4B71-83AF-E4FD09F7B1AD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectApp.ServiceDefaults", "ProjectApp.ServiceDefaults\ProjectApp.ServiceDefaults.csproj", "{B2C3D4E5-F6A7-8901-BCDE-F12345678901}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectApp.AppHost", "ProjectApp.AppHost\ProjectApp.AppHost.csproj", "{2A5FB573-9376-4FEB-9289-A8387F435C13}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -15,6 +22,22 @@ 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
{E7D4CA8B-53EA-9676-D96D-BE2F0CB11054}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E7D4CA8B-53EA-9676-D96D-BE2F0CB11054}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E7D4CA8B-53EA-9676-D96D-BE2F0CB11054}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E7D4CA8B-53EA-9676-D96D-BE2F0CB11054}.Release|Any CPU.Build.0 = Release|Any CPU
{CC5A9873-4CC3-4B71-83AF-E4FD09F7B1AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CC5A9873-4CC3-4B71-83AF-E4FD09F7B1AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CC5A9873-4CC3-4B71-83AF-E4FD09F7B1AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CC5A9873-4CC3-4B71-83AF-E4FD09F7B1AD}.Release|Any CPU.Build.0 = Release|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Release|Any CPU.Build.0 = Release|Any CPU
{2A5FB573-9376-4FEB-9289-A8387F435C13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A5FB573-9376-4FEB-9289-A8387F435C13}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A5FB573-9376-4FEB-9289-A8387F435C13}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A5FB573-9376-4FEB-9289-A8387F435C13}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
21 changes: 21 additions & 0 deletions CreditSystem.Api/Controllers/LoansController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Mvc;
using CreditSystem.Api.Services;
using CreditSystem.Domain.Entities;

namespace CreditSystem.Api.Controllers;

[ApiController]
[Route("api/v1/[controller]")]
public class LoansController(LoanService loanService, ILogger<LoansController> logger) : ControllerBase
{
/// <summary>
/// Получить данные по кредитной заявке (с генерацией при отсутствии)
/// </summary>
[HttpGet("{id:guid}")]
public async Task<ActionResult<LoanApplication>> Get(Guid id, CancellationToken ct)
{
logger.LogInformation("Запрос на получение данных по заявке: {Id}", id);
var result = await loanService.GetApplicationAsync(id, ct);
return Ok(result);
}
}
19 changes: 19 additions & 0 deletions CreditSystem.Api/CreditSystem.Api.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Bogus" Version="35.5.0" />
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CreditSystem.Domain\CreditSystem.Domain.csproj" />
<ProjectReference Include="..\CreditSystem.ServiceDefaults\CreditSystem.ServiceDefaults.csproj" />
</ItemGroup>

</Project>
29 changes: 29 additions & 0 deletions CreditSystem.Api/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
var builder = WebApplication.CreateBuilder(args);

// Подключаем стандартные настройки (ServiceDefaults)
builder.AddServiceDefaults();

// Наши сервисы
builder.Services.AddSingleton<CreditSystem.Api.Services.LoanDataGenerator>();
builder.Services.AddScoped<CreditSystem.Api.Services.LoanService>();

// Кэш (Redis подхватится через Aspire)
builder.AddRedisDistributedCache("cache");

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

app.MapDefaultEndpoints();

if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.MapControllers();

app.Run();
34 changes: 34 additions & 0 deletions CreditSystem.Api/Services/LoanDataGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Bogus;
using CreditSystem.Domain.Entities;

namespace CreditSystem.Api.Services;

/// <summary>
/// Генератор тестовых данных для кредитных заявок
/// </summary>
public class LoanDataGenerator
{
private readonly Faker<LoanApplication> _faker;

public LoanDataGenerator()
{
// Используем русскую локаль для правдоподобности
_faker = new Faker<LoanApplication>("ru")
.RuleFor(l => l.Id, f => f.Random.Guid())
.RuleFor(l => l.ApplicantName, f => f.Name.FullName())
.RuleFor(l => l.RequestedAmount, f => f.Finance.Amount(50000, 5000000, 0))
.RuleFor(l => l.TermMonths, f => f.Random.Int(6, 120))
.RuleFor(l => l.MonthlyIncome, f => f.Finance.Amount(30000, 300000, 0))
.RuleFor(l => l.CreditScore, f => f.Random.Int(300, 850))
.RuleFor(l => l.CreatedAt, f => f.Date.Recent(30))
.RuleFor(l => l.Status, (f, l) =>
{
// Простая логика: если рейтинг совсем плохой — сразу отказ
return l.CreditScore < 400 ? "Rejected" : "Pending";
});
}

public LoanApplication Generate() => _faker.Generate();

public IEnumerable<LoanApplication> Generate(int count) => _faker.Generate(count);
}
45 changes: 45 additions & 0 deletions CreditSystem.Api/Services/LoanService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Microsoft.Extensions.Caching.Distributed;
using System.Text.Json;
using CreditSystem.Domain.Entities;
using CreditSystem.Api.Services;

namespace CreditSystem.Api.Services;

/// <summary>
/// Сервис управления кредитными заявками (с кэшированием)
/// </summary>
public class LoanService(
IDistributedCache cache,
LoanDataGenerator generator,
ILogger<LoanService> logger)
{
private const int CacheExpirationMinutes = 15;

public async Task<LoanApplication> GetApplicationAsync(Guid id, CancellationToken ct = default)
{
var key = $"loan:app:{id}";

// Пытаемся взять из редиса
var data = await cache.GetStringAsync(key, ct);
if (!string.IsNullOrEmpty(data))
{
logger.LogInformation("Заявка {Id} найдена в кэше", id);
return JsonSerializer.Deserialize<LoanApplication>(data)!;
}

// Если нет — генерим
logger.LogWarning("Заявка {Id} не найдена. Генерируем новую...", id);
var app = generator.Generate();
app.Id = id;

// И кладем обратно
var options = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(CacheExpirationMinutes)
};

await cache.SetStringAsync(key, JsonSerializer.Serialize(app), options, ct);

return app;
}
}
22 changes: 22 additions & 0 deletions CreditSystem.AppHost/CreditSystem.AppHost.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
<UserSecretsId>7f82b7c4-5d5d-4f8a-8b8b-8b8b8b8b8b8b</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.0.0" />
<PackageReference Include="Aspire.Hosting.Redis" Version="8.0.0" />
<PackageReference Include="Aspire.Hosting.LocalStack" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CreditSystem.Api\CreditSystem.Api.csproj" />
</ItemGroup>

</Project>
17 changes: 17 additions & 0 deletions CreditSystem.AppHost/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
var builder = DistributedApplication.CreateBuilder(args);

// Используем Redis для кэширования (согласно общему заданию лабы №1)
var redis = builder.AddRedis("cache");

// Добавляем LocalStack для SQS (согласно варианту №30)
var localstack = builder.AddLocalStack("localstack")
.WithServices("sqs");

// Наш основной API сервис (Query Based)
builder.AddProject<Projects.CreditSystem_Api>("creditsystem-api")
.WithReference(redis)
.WithReference(localstack) // Передаем ссылку на LocalStack/SQS
.WaitFor(redis)
.WaitFor(localstack);

builder.Build().Run();
9 changes: 9 additions & 0 deletions CreditSystem.Domain/CreditSystem.Domain.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
49 changes: 49 additions & 0 deletions CreditSystem.Domain/Entities/LoanApplication.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;

namespace CreditSystem.Domain.Entities;

/// <summary>
/// Сущность кредитной заявки (Вариант 30)
/// </summary>
public class LoanApplication
{
/// <summary>
/// Уникальный номер заявки
/// </summary>
public Guid Id { get; set; }

/// <summary>
/// ФИО заемщика
/// </summary>
public required string ApplicantName { get; set; }

/// <summary>
/// Сумма кредита (в рублях)
/// </summary>
public decimal RequestedAmount { get; set; }

/// <summary>
/// Срок кредитования (в месяцах)
/// </summary>
public int TermMonths { get; set; }

/// <summary>
/// Ежемесячный доход
/// </summary>
public decimal MonthlyIncome { get; set; }

/// <summary>
/// Кредитный рейтинг (0-1000)
/// </summary>
public int CreditScore { get; set; }

/// <summary>
/// Текущий статус заявки
/// </summary>
public string Status { get; set; } = "New";

/// <summary>
/// Дата и время подачи
/// </summary>
public DateTime CreatedAt { get; set; }
}
19 changes: 19 additions & 0 deletions CreditSystem.ServiceDefaults/CreditSystem.ServiceDefaults.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="8.0.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.7.0" />
</ItemGroup>

</Project>
Loading