Skip to content
Open
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
Binary file added 4,1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 4,2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 4,3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 4,4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 4,5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 4,6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 4,7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions TaskHub/Api/Api.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Expand All @@ -12,7 +12,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.2">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
8 changes: 8 additions & 0 deletions TaskHub/Api/Controllers/Tasks/Request/CreateTaskRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Api.Controllers.Tasks.Request
{
public class CreateTaskRequest
{
public string? Title { get; set; }
public Guid UserId { get; set; }
}
}
7 changes: 7 additions & 0 deletions TaskHub/Api/Controllers/Tasks/Request/SetTaskTitleRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Api.Controllers.Tasks.Request
{
public class SetTaskTitleRequest
{
public string? Title { get; set; }
}
}
18 changes: 18 additions & 0 deletions TaskHub/Api/Controllers/Tasks/Response/TaskResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Api.Controllers.Tasks.Response
{
public class TaskResponse
{
public Guid Id { get; }
public string? Title { get; }
public Guid CreatedByUserId { get; }
public DateTimeOffset CreatedUtc { get; }

public TaskResponse(Guid id, string? title, Guid createdByUserId, DateTimeOffset createdUtc)
{
Id = id;
Title = title;
CreatedByUserId = createdByUserId;
CreatedUtc = createdUtc;
}
}
}
60 changes: 60 additions & 0 deletions TaskHub/Api/Controllers/Tasks/TasksController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Api.Controllers.Tasks.Request;
using Api.Controllers.Tasks.Response;
using Api.UseCases.Tasks.Interfaces;
using Microsoft.AspNetCore.Mvc;

namespace Api.Controllers.Tasks;

[ApiController]
[Route("tasks")]
public class TasksController : ControllerBase
{
private readonly IManageTaskUseCase _useCase;

public TasksController(IManageTaskUseCase useCase)
{
_useCase = useCase;
}

[HttpPost]
public async Task<ActionResult<TaskResponse>> Create(CreateTaskRequest request, CancellationToken ct)
{
var result = await _useCase.CreateTaskAsync(request.Title, request.UserId, ct);
return Created("", result);
}

[HttpGet]
public async Task<ActionResult<IEnumerable<TaskResponse>>> GetAll(CancellationToken ct)
{
return Ok(await _useCase.GetAllTasksAsync(ct));
}

[HttpGet("{id:guid}")]
public async Task<ActionResult<TaskResponse>> Get(Guid id, CancellationToken ct)
{
var result = await _useCase.GetTaskByIdAsync(id, ct);
if (result == null) return NotFound();
return Ok(result);
}

[HttpPut("{id:guid}/title")]
public async Task<IActionResult> SetTitle(Guid id, SetTaskTitleRequest request, CancellationToken ct)
{
await _useCase.SetTaskTitleAsync(id, request.Title!, ct);
return NoContent();
}

[HttpDelete("{id:guid}")]
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
{
var deleted = await _useCase.DeleteTaskByIdAsync(id, ct);
return deleted ? NoContent() : NotFound();
}

[HttpDelete]
public async Task<IActionResult> DeleteAll(CancellationToken ct)
{
await _useCase.DeleteAllTasksAsync(ct);
return NoContent();
}
}
5 changes: 5 additions & 0 deletions TaskHub/Api/Controllers/Users/UsersController.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using Api.Filters;
using Api.Controllers.Users.Request;
using Api.Controllers.Users.Response;
using Api.UseCases.Users.Interfaces;
using Microsoft.AspNetCore.Mvc;

namespace Api.Controllers.Users;

[ResponseTimeHeader]
[StudentInfoHeaders]

/// <summary>
/// Контроллер работы с пользователями
/// </summary>
Expand All @@ -29,6 +33,7 @@ public UsersController(IManageUserUseCase userUseCase)
/// <param name="cancellationToken">Токен отмены</param>
/// <returns>Созданный пользователь</returns>
[HttpPost]
[SetName]
public async Task<ActionResult<UserResponse>> CreateUserAsync(
[FromBody] CreateUserRequest? request,
CancellationToken cancellationToken)
Expand Down
23 changes: 23 additions & 0 deletions TaskHub/Api/Filters/ResponseTimeHeaderAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Microsoft.AspNetCore.Mvc.Filters;
using System.Diagnostics;

namespace Api.Filters
{
public class ResponseTimeHeaderAttribute : ActionFilterAttribute
{
private Stopwatch _stopwatch;

public override void OnActionExecuting(ActionExecutingContext context)
{
_stopwatch = Stopwatch.StartNew();
}

public override void OnActionExecuted(ActionExecutedContext context)
{
_stopwatch.Stop();

context.HttpContext.Response.Headers["X-Response-Time-Ms"] =
_stopwatch.ElapsedMilliseconds.ToString();
}
}
}
6 changes: 6 additions & 0 deletions TaskHub/Api/Filters/SetNameAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Api.Filters
{
public class SetNameAttribute : ValidateUserRequestAttribute
{
}
}
15 changes: 15 additions & 0 deletions TaskHub/Api/Filters/StudentInfoHeadersAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Microsoft.AspNetCore.Mvc.Filters;

namespace Api.Filters
{
public class StudentInfoHeadersAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext context)
{
var headers = context.HttpContext.Request.Headers;

headers["X-Student-Name"] = "Tumashova Marina";
headers["X-Student-Group"] = "RI-240912";
}
}
}
34 changes: 34 additions & 0 deletions TaskHub/Api/Filters/ValidateUserRequestAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Reflection;

namespace Api.Filters
{
public class ValidateUserRequestAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var request = context.ActionArguments.Values.FirstOrDefault();

if (request == null)
{
context.Result = new BadRequestObjectResult("нет тела запроса");
return;
}

var nameProperty = request.GetType().GetProperty("Name");

if (nameProperty == null)
{
return;
}

var nameValue = nameProperty.GetValue(request)?.ToString();

if (string.IsNullOrWhiteSpace(nameValue))
{
context.Result = new BadRequestObjectResult("нет имени");
}
}
}
}
28 changes: 28 additions & 0 deletions TaskHub/Api/Middleware/ResponseTimeMiddleware.cs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Diagnostics;

namespace Api.Middleware
{
public class ResponseTimeMiddleware
{
private readonly RequestDelegate _next;

public ResponseTimeMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task InvokeAsync(HttpContext context)
{
var stopwatch = Stopwatch.StartNew();

context.Response.OnStarting(() =>
{
stopwatch.Stop();
context.Response.Headers["X-Response-Time-Ms"] = stopwatch.ElapsedMilliseconds.ToString();
return Task.CompletedTask;
});

await _next(context);
}
}
}
24 changes: 24 additions & 0 deletions TaskHub/Api/Middleware/StudentInfoMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace Api.Middleware
{
public class StudentInfoMiddleware
{
private readonly RequestDelegate _next;

public StudentInfoMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task InvokeAsync(HttpContext context)
{
context.Response.OnStarting(() =>
{
context.Response.Headers["X-Student-Name"] = "Tumashova Marina";
context.Response.Headers["X-Student-Group"] = "RI-240912";
return Task.CompletedTask;
});

await _next(context);
}
}
}
18 changes: 18 additions & 0 deletions TaskHub/Api/Services/DisposedService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Api.Services
{
public abstract class DisposedService : IHasInstanceId, IDisposable
{
public Guid InstanceId { get; } = Guid.NewGuid();

protected DisposedService()
{
Console.WriteLine($"{GetType().Name} CREATED:{InstanceId}");
}

public void Dispose()
{
Console.WriteLine($"{GetType().Name} DISPOSED: {InstanceId}");
}
}
}

7 changes: 7 additions & 0 deletions TaskHub/Api/Services/IHasInstanceId.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Api.Services
{
public interface IHasInstanceId
{
Guid InstanceId { get; }
}
}
17 changes: 17 additions & 0 deletions TaskHub/Api/Services/ServiceProviderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Api.Services
{
public static class ServiceProviderExtensions
{
public static void CompareServices<T>(this IServiceProvider provider)
where T : IHasInstanceId
{
var first = provider.GetRequiredService<T>();
var second = provider.GetRequiredService<T>();

Console.WriteLine($"Service: {typeof(T).Name}");
Console.WriteLine($"First: {first.InstanceId}");
Console.WriteLine($"Second: {second.InstanceId}");
Console.WriteLine($"Same instance: {ReferenceEquals(first, second)}");
}
}
}
20 changes: 20 additions & 0 deletions TaskHub/Api/Services/Services.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Api.Services
{
public interface ISingletonService1 : IHasInstanceId { }
public interface ISingletonService2 : IHasInstanceId { }

public interface IScopedService1 : IHasInstanceId { }
public interface IScopedService2 : IHasInstanceId { }

public interface ITransientService1 : IHasInstanceId { }
public interface ITransientService2 : IHasInstanceId { }

public class SingletonService1 : DisposedService, ISingletonService1 { }
public class SingletonService2 : DisposedService, ISingletonService2 { }

public class ScopedService1 : DisposedService, IScopedService1 { }
public class ScopedService2 : DisposedService, IScopedService2 { }

public class TransientService1 : DisposedService, ITransientService1 { }
public class TransientService2 : DisposedService, ITransientService2 { }
}
Loading