ΠΡΠ³Π΅Ρ ΠΏΠ°ΠΊΠ΅Ρ Ρ ΡΠΈΠΏΠΎΠ²ΡΠΌΠΈ ΡΠ΅ΡΠ΅Π½ΠΈΡΠΌΠΈ Π΄Π»Ρ ΡΡΠΊΠΎΡΠ΅Π½ΠΈΡ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠΈ.
Π‘ΠΎΠ΄Π΅ΡΠΆΠΈΡ Π² ΡΠ΅Π±Π΅ Π±Π°Π·ΠΎΠ²ΡΠ΅ ΠΊΠ»Π°ΡΡΡ, ΠΊΠΎΡΠΎΡΡΠ΅ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΡ ΠΏΡΠΈ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠ΅ ΠΏΠΎ DDD + CQRS + Event Sourcing (immediate consistency). ΠΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ° ΡΠΎΠ²ΠΌΠ΅ΡΡΠΈΠΌΠ° ΡΠΎ ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡΠΌΠΈ ΠΈΠ· open source Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ Force (https://github.com/hightechgroup/force). ΠΠΌΠ΅Π΅Ρ ΠΏΡΡΠΌΡΠ΅ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΠΊ Entity Framework.
Π Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Ρ ΠΏΠΎ ΠΏΡΠΈΠ½ΡΠΈΠΏΡ "is a", Π° Π½Π΅ "can do".
ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅:
public class Animal : Entitypublic class Address : ValueObjectΠ Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Ρ Ρ ΠΏΠΎΠΌΠΎΡΡΡ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ MediatR.
public class AddProductCommand : Commandpublic class ProductAddedEvent : EventStartup.cs
services.AddMediatR(typeof(Startup));
// Π₯ΡΠ°Π½ΠΈΠ»ΠΈΡΠ΅ Events
services.AddScoped<IEventStore, EventStore>();
// Π¨ΠΈΠ½Π° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ ΡΠΎΠ±ΡΡΠΈΠΉ
services.AddScoped<IMediatorHandler, InMemoryBus>();
// Domain - Events
services.AddScoped<INotificationHandler<ProductAddedEvent>, ProductAddedEventHandler>();
// Domain - Commands
services.AddScoped<IRequestHandler<AddProductCommand, bool>, ProductCommandHandler>();ProductCommandHandler.cs
public class ProductCommandHandler : CommandHandlerBase, IRequestHandler<ProductAddCommand, bool>
...
public async Task<bool> Handle(ProductAddCommand command, CancellationToken ct)
{
bool isValidOperation;
// ΠΠ°Π»ΠΈΠ΄Π°ΡΠΈΡ
if (!isValidOperation)
{
await Mediator.RaiseEventAsync(
new DomainNotification(nameof(DomainNotification), Resources.NotValidOperation), ct);
return false;
}
// ΠΠΈΠ·Π½Π΅Ρ Π»ΠΎΠ³ΠΈΠΊΠ°
if (!await CommitAsync())
return false;
await _mediator.RaiseEventAsync(
new ProductAddedEvent(
product.Id,
product.Price,
// ΠΡΡΠ³ΠΈΠ΅ ΠΏΠΎΠ»Ρ
), ct);
return true;ProductsController.cs
var command = _mapper.Map<ProductAddCommand>(model);
await Mediator.SendCommandAsync(command);
if (!IsValidOperation())
return BadRequest(Errors);
return Ok();ΠΠ»ΠΎΠ±Π°Π»ΡΠ½Π°Ρ ΡΠΈΠ½Π° Π΄Π»Ρ ΡΡΠ½ΠΊΡΠΈΠΎΠ½ΠΈΡΠΎΠ²Π°Π½ΠΈΡ MediatR. ΠΠ°ΡΡΡΠΎΠ΅Π½ Π½Π° ΡΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ Π²ΡΠ΅Ρ
Π½Π°ΡΠ»Π΅Π΄Π½ΠΈΠΊΠΎΠ² Event Π² EventStore, ΠΊΡΠΎΠΌΠ΅ DomainNotification.
Startup.cs
services.AddScoped<IMediatorHandler, InMemoryBus>();ProductsController.cs
public class ProductsController : FormattedApiControllerBase
{
private readonly IMediatorHandler _mediator;
public ProductsController(IMediatorHandler mediator)
{
_mediator = mediator;
}
...
[HttpGet]
public IActionResult Post(AddProduct model)
{
...
await _mediator.SendCommandAsync(command);InMemoryBus.cs
public virtual async Task RaiseEventAsync<T>(T @event, CancellationToken ct = default)
where T : Event
{
if (!@event.MessageType.Equals("DomainNotification"))
// ΠΠ°ΠΏΠΈΡΡΠ²Π°Π΅ΠΌ Π½Π°ΡΠ»Π΅Π΄Π½ΠΈΠΊΠΎΠ² Event ΠΈ Ρ ΡΠΈΠΏΠΎΠΌ Π½Π΅ DomainNotification.
await EventStore.SaveAsync(@event, ct);
// ΠΠ°Π±Π»ΠΈΡΠΈΠΌ ΠΈΠ²Π΅Π½ΡΡ. ΠΠ½ΠΈ Π±ΡΠ΄ΡΡ Π΄ΠΎΡΡΡΠΏΠ½Ρ ΠΏΡΠΈ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ INotificationHandler<T>, Π³Π΄Π΅ T = Event
await Mediator.Publish(@event, ct);
}ΠΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊ, Ρ ΠΏΠΎΠΌΠΎΡΡΡ ΠΊΠΎΡΠΎΡΠΎΠ³ΠΎ ΠΏΠΎΡΡΡΠΎΠ΅Π½Π° Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠ° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ ΠΎΡΠΈΠ±ΠΎΠΊ ΡΠ΅ΡΠ΅Π· INotification Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ MediatR.
Startup.cs
services.AddScoped<INotificationHandler<DomainNotification>, DomainNotificationHandler>();ProductCommandHandler.cs
public class ProductCommandHandler : CommandHandlerBase, IRequestHandler<ProductAddCommand, bool>
...
public async Task<bool> Handle(ProductAddCommand command, CancellationToken ct)
{
bool isValidOperation;
// ΠΠ°Π»ΠΈΠ΄Π°ΡΠΈΡ
if (!isValidOperation)
{
await Mediator.RaiseEventAsync(
new DomainNotification(nameof(DomainNotification), Resources.InvalidOperation), ct);
// ΠΡΠΈΠ±ΠΊΠ° ΡΠΈΠΏΠ° DomainNotification ΠΏΠΎΠΏΠ°Π»Π° Π² InMemoryBus ΠΈ ΡΠΎΡ
ΡΠ°Π½ΠΈΠ»Π°ΡΡ Π² ΠΏΠ°ΠΌΡΡΠΈ.
// Π’Π΅ΠΏΠ΅ΡΡ ΠΎΠ½Π° Π΄ΠΎΡΡΡΠΏΠ½Π° ΡΠ΅ΡΠ΅Π· DomainNotificationHandler Π΄Π»Ρ Π΄Π°Π»ΡΠ½Π΅ΠΉΡΠ΅ΠΉ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ.
return false;
}ApiControllerBase.cs
public abstract class ApiControllerBase : FormattedApiControllerBase
{
private readonly DomainNotificationHandler _notifications;
protected readonly IMediatorHandler Mediator;
protected ApiControllerBase(IMediatorHandler mediator, INotificationHandler<DomainNotification> notifications)
{
Mediator = mediator;
_notifications = (DomainNotificationHandler)notifications;
}
protected IEnumerable<DomainNotification> Notifications
=> _notifications.Notifications();
protected IEnumerable<string> Errors
=> Notifications.Select(x => x.Value);
protected bool IsValidOperation()
=> !_notifications.HasNotifications();
}Π¨ΠΈΠ½Π° Π΄Π»Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ Π½Π°ΡΠ»Π΅Π΄Π½ΠΈΠΊΠΎΠ² Event, Π΄Π»Ρ ΠΏΠΎΡΠ»Π΅Π΄ΡΡΡΠΈΠ΅Π³ΠΎ ΡΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΡ Π² Π±Π°Π·Ρ. Π‘ΠΎΠ΄Π΅ΡΠΆΠΈΡ Π² ΡΠ΅Π±Π΅ Π°Π³Π³ΡΠ΅Π³Π°Ρ, ΡΠΈΠΏ, Π²ΡΠ΅ΠΌΡ, ΠΈ ΡΠ΅Π»ΠΎ ΡΠΎΠ±ΡΡΠΈΡ Π² ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π½ΠΎΠΌ Π²ΠΈΠ΄Π΅. ΠΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ Π² InMemoryBus.
Startup.cs
services.AddScoped<IEventStore, EventStore>();InMemoryBus.cs
public class InMemoryBus : IMediatorHandler
{
protected readonly IMediator Mediator;
protected readonly IEventStore EventStore;
...
public virtual async Task RaiseEventAsync<T>(T @event, CancellationToken ct = default)
where T : Event
{
if (!@event.MessageType.Equals("DomainNotification"))
await EventStore.SaveAsync(@event, ct);
await Mediator.Publish(@event, ct);
}ΠΠ°Π·ΠΎΠ²ΡΠΉ ΠΊΠ»Π°ΡΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΠ° ΠΊΠΎΠΌΠ°Π½Π΄, ΠΊΠΎΡΠΎΡΡΠΉ ΡΠΎΠ΄Π΅ΡΠΆΠΈΡ Π² ΡΠ΅Π±Π΅ Π±Π°Π·ΠΎΠ²ΡΠ΅ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ, Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΡΠ΅ Π΄Π»Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ Π΄ΠΎΠΌΠ΅Π½Π½ΡΡ
ΠΎΡΠΈΠ±ΠΎΠΊ ΠΈ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ Ρ Π±Π°Π·ΠΎΠΉ Π΄Π°Π½Π½ΡΡ
. Π Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ Commit() ΠΈ CommitAsync() Π½Π΅ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡ Π·Π°ΠΏΠΈΡΠ°ΡΡ Π² Π±Π°Π·Ρ, Π΅ΡΠ»ΠΈ Π½Π°ΠΉΠ΄ΡΡΡΡ Π΄ΠΎΠΌΠ΅Π½Π½ΡΠ΅ ΠΎΡΠΈΠ±ΠΊΠΈ. Π’Π°ΠΊΠΆΠ΅ ΡΠΌΠ΅ΡΡ Π²ΡΠ±ΡΠ°ΡΡΠ²Π°ΡΡ ΡΠ²ΠΎΠΈ ΠΎΡΠΈΠ±ΠΊΠΈ ΠΏΡΠΈ Π½Π°Π»ΠΈΡΠΈΠΈ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠΉ Π²ΠΎ Π²ΡΠ΅ΠΌΡ Π·Π°ΠΏΠΈΡΠΈ, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΌΠΎΠΆΠ½ΠΎ Π² Π±ΡΠ΄ΡΡΠ΅ΠΌ Π°Π³Π³ΡΠ΅Π³ΠΈΡΠΎΠ²Π°ΡΡ ΠΈ Π΄ΠΎΡΡΠ°Π²ΠΈΡΡ Π² ΡΠ΅Π»ΠΎ Bad Request ΠΈΡΠ΄. Π‘ΠΎΠ΄Π΅ΡΠΆΠΈΡ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ IMediatorHandler, DomainNotificationHandler, IUnitOfWork.
ΠΠ»Π°ΡΡ, ΡΠ΅Π°Π»ΠΈΠ·ΡΡΡΠΈΠΉ ΠΏΠ°ΡΡΠ΅ΡΠ½ Unit Of Work. Π Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Ρ Π²ΠΈΡΡΡΠ°Π»ΡΠ½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ Commit() ΠΈ CommitAsync() Ρ Π»ΠΎΠ³ΠΈΠΊΠΎΠΉ ΠΎΡΠ±Π°Π±ΠΎΡΠΊΠΈ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠΎΠ² IHasCreationTime ΠΈ IHasModificationTime. ΠΡΠΈ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎΡΡΠΈ ΠΌΠΎΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ ΡΠ²ΠΎΡ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ, Π½Π°ΡΠ»Π΅Π΄ΠΎΠ²Π°Π²ΡΠΈΡΡ ΠΎΡ ΠΊΠ»Π°ΡΡΠ° ΠΈ ΠΏΠ΅ΡΠ΅Π·Π°ΠΏΠΈΡΠ°ΡΡ ΠΌΠ΅ΡΠΎΠ΄Ρ Commit(), CommitAsync().
ΠΠ°Π±ΠΎΡ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠ², ΡΡΠΊΠΎΡΡΡΡΠΈΡ
ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΡ Application ΡΠ»ΠΎΡ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ.
ΠΠ°Π±ΠΎΡ Π°ΡΡΠΈΠ±ΡΡΠΎΠ² Π΄Π»Ρ ΡΠ°Π±ΠΎΡΡ Ρ ΡΠ°ΠΉΠ»Π°ΠΌΠΈ Π² REST Api.
- AllowedExtensionsAttribute
- MaxFileSize
- HasValidFileName
ΠΡΠΈΠΌΠ΅Ρ.
[HasValidFileName]
[MaxFileSize(500 * 1024 * 1024)] // 500 mb
[AllowedExtensions(new[] {".jpg", ".png", ".mp4", ".jpeg"})]
public IFormFile File { get; set; }- DevelopmentOnly
ΠΡΡΠΈΠ±ΡΡ, ΠΊΠΎΡΠΎΡΡΠΉ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ Π²ΡΠΊΠ»ΡΡΠ°ΡΡ ΠΌΠ΅ΡΠΎΠ΄ Π² Π½Π΅ Development ΠΎΠΊΡΡΠΆΠ΅Π½ΠΈΠΈ. ΠΡΠΈΠΌΠ΅Ρ.
[HttpDelete]
[DevelopmentOnly]
[ApiExplorerSettings(IgnoreApi = true)]
public async Task<IActionResult> Delete([FromQuery] DeleteRequest request)ΠΠ½ΡΡΡΡΠΌΠ΅Π½Ρ, Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΡΠΉ Π΄Π»Ρ ΡΠΎΡΠΌΠ°ΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΎΡΠ²Π΅ΡΠ° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ ΠΈ ΠΏΡΠΈΠ²Π΅Π΄Π΅Π½ΠΈΡ ΠΎΡΠ²Π΅ΡΠ° Π² Π΅Π΄ΠΈΠ½ΡΡ ΡΡΠΈΠ»ΠΈΡΡΠΈΠΊΡ.
ΠΠΎΠ»ΠΎΠΆΠΈΡΠ΅Π»ΡΠ½ΡΠΉ ΡΠΎΡΠΌΠ°Ρ ΠΎΡΠ²Π΅ΡΠ°:
{
"content": {
"key": "value"
},
"debugData": "string"
}ΠΡΡΠΈΡΠ°ΡΠ΅Π»ΡΠ½ΡΠΉ ΡΠΎΡΠΌΠ°Ρ ΠΎΡΠ²Π΅ΡΠ°:
{
"subStatus": "string",
"errorContent": [
"string"
],
"debugData": "string"
}Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ.
Startup.cs
services
.AddControllers()
.SetCompatibilityVersion(CompatibilityVersion.Latest)
.AddResponseOutputFormatter();
services.Configure<ApiBehaviorOptions>(options =>
{
options.InvalidModelStateResponseFactory =
actionContext =>
InvalidModelStateResponseFactory.CreateFrom(Resources.InvalidModel, actionContext.ModelState);
});ApiControllerBase.cs
public abstract class ApiControllerBase : FormattedApiControllerBase
{ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅.
/// <summary>
/// ΠΡΠ²ΠΎΠ΄ ΡΠΏΠΈΡΠΊΠ° ΠΏΡΠΎΠ΄ΡΠΊΡΠΎΠ².
/// </summary>
[HttpGet]
[SwaggerResponse(200, SwaggerResponseMessages.Ok + " ΠΠΎΠ·Π²ΡΠ°ΡΠ°Π΅ΡΡΡ ΡΠΏΠΈΡΠΎΠΊ ΠΏΡΠΎΠ΄ΡΠΊΡΠΎΠ².",
typeof(SwaggerSuccessApiResponse<PagedResponse<ProductItemModel>>))]
public IActionResult Get([FromQuery] PagingQueryModel query)
{
var products = _context
.Set<Domain.Entities.Products>()
.OrderByDescending(x => x.Rating)
.ProjectTo<ProductItemModel>(_mapper.ConfigurationProvider)
.Paginate(query.Page, query.Size);
return Ok(products);
}ΠΡΠ²Π΅Ρ.
{
"pagination": {
"itemsTotal": 0,
"page": 0,
"total": 0,
"size": 0,
"hasPrevious": true,
"hasNext": true
},
"items": [
{
"id": 0,
"name": "string",
"price": 0,
"rating": 0
}
]
}Π£ΠΏΡΠΎΡΠ΅Π½ΠΈΠ΅ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠΈ swagger Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΠΈ. ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ Π΄ΠΎΠΏΠΎΠ»Π½ΡΠ΅Ρ ΠΎΡΠ²Π΅Ρ ΠΎΡΠΈΠ±ΠΊΠΎΠΉ 500, Π° ΡΠ°ΠΊΠΆΠ΅ 401 ΠΈ 403 Π΅ΡΠ»ΠΈ ΠΌΠ΅ΡΠΎΠ΄ ΠΏΠΎΠΊΡΡΡ Π°Π²ΡΠΎΡΠΈΠ·Π°ΡΠΈΠ΅ΠΉ. ΠΠ»Ρ ΡΠΏΡΠΎΡΠ΅Π½ΠΈΡ Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΡΠ°Π·Π»ΠΈΡΠ½ΡΡ
ΠΎΡΠ²Π΅ΡΠΎΠ² ΠΏΡΠΈΡΡΡΡΡΠ²ΡΠ΅Ρ Π½Π°Π±ΠΎΡ ΡΠ°Π±Π»ΠΎΠ½Π½ΡΡ
ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠΉ SwaggerResponseMessages. SwaggerErrorApiResponse ΠΈ SwaggerSuccessApiResponse Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Ρ Π΄Π»Ρ ΠΏΠΎΡΡΡΠΎΠ΅Π½ΠΈΡ ΡΠ΅Π» ΠΎΡΠ²Π΅ΡΠΎΠ² Π½Π° swagger ΡΡΡΠ°Π½ΠΈΡΠ΅ ΠΏΡΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠΈ Π² ΡΠ²ΡΠ·ΠΊΠ΅ Ρ Response Formatter.
Π Π΅Π³ΠΈΡΡΡΠ°ΡΠΈΡ.
services.AddSwaggerGen(options =>
{
// ΠΠ°Ρ ΠΊΠΎΠ½ΡΠΈΠ³
options.OperationFilter<ResponseOperationFilter>();
}
);ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅. 500, 403, 401 ΠΎΡΠΈΠ±ΠΊΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ.
/// <summary>
/// Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ ΠΏΡΠΎΠ΄ΡΠΊΡΠ°.
/// </summary>
[HttpDelete("{id}")]
[Authorize]
[SwaggerResponse(204, SwaggerResponseMessages.NoContent, typeof(void))]
[SwaggerResponse(400, SwaggerResponseMessages.BadRequest, typeof(SwaggerErrorApiResponse<IEnumerable<string>>))]
public async Task<IActionResult> Delete(long id)ΠΠ΅ΡΠΎΠ΄Ρ Π΄Π»Ρ ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ Π΄Π°Π½Π½ΡΡ Π² ΠΠ.
- MigrationsInitializer - ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ Π΄Π»Ρ Π°Π²ΡΠΎΠΌΠΈΠ³ΡΠ°ΡΠΈΠΈ ΠΏΡΠΈ ΡΡΠ°ΡΡΠ΅.
- DataInitializerBase - Π±Π°Π·ΠΎΠ²ΡΠΉ ΠΌΠ΅ΡΠΎΠ΄ Π΄Π»Ρ ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ Π΄Π°Π½Π½ΡΡ Π² Π±Π°Π·Ρ. ΠΠΌΠ΅Π΅Ρ ΡΠ°Π±ΡΠΈΡΠ½ΡΠΉ ΠΌΠ΅ΡΠΎΠ΄ InitializeAsync, ΠΊΠΎΡΠΎΡΡΠΉ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²Π°ΡΡ.
ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅.
Program.cs
public static async Task Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
await host.InitAsync();
await host.RunAsync();
}Startup.cs
services.AddAsyncInitializer<MigrationsInitializer>();
services.AddAsyncInitializer<AdminsInitializer>();Π Π½Π°ΡΠ°Π»Π΅ ΡΠΎΠ²Π΅ΡΡΠ΅ΡΡΡ Π·Π°ΠΏΡΡΠΊΠ°ΡΡ MigrationsInitializer, ΡΠ°ΠΊ ΠΊΠ°ΠΊ ΡΠ½Π°ΡΠ°Π»Π° Π΄ΠΎΠ»ΠΆΠ½Π° ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡΡΡ Π°ΠΊΡΡΠ°Π»ΡΠ½Π°Ρ ΡΡ Π΅ΠΌΠ°, Π° ΠΏΠΎΡΠΎΠΌ ΡΠΆΠ΅ Π²ΡΠ΅ ΠΎΡΡΠ°Π»ΡΠ½ΠΎΠ΅.