Move using statements to globalusing file

This commit is contained in:
Sumit Ghosh 2021-10-13 17:37:01 +05:30
parent 5fd90e8cb6
commit 9d73669d86
6 changed files with 172 additions and 206 deletions

View File

@ -1,10 +1,10 @@
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
public enum EventStateEnum
{
public enum EventStateEnum
{
NotPublished = 0,
InProgress = 1,
Published = 2,
PublishedFailed = 3
}
NotPublished = 0,
InProgress = 1,
Published = 2,
PublishedFailed = 3
}

View File

@ -1,45 +1,41 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF
public class IntegrationEventLogContext : DbContext
{
public class IntegrationEventLogContext : DbContext
public IntegrationEventLogContext(DbContextOptions<IntegrationEventLogContext> options) : base(options)
{
public IntegrationEventLogContext(DbContextOptions<IntegrationEventLogContext> options) : base(options)
{
}
}
public DbSet<IntegrationEventLogEntry> IntegrationEventLogs { get; set; }
public DbSet<IntegrationEventLogEntry> IntegrationEventLogs { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<IntegrationEventLogEntry>(ConfigureIntegrationEventLogEntry);
}
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<IntegrationEventLogEntry>(ConfigureIntegrationEventLogEntry);
}
void ConfigureIntegrationEventLogEntry(EntityTypeBuilder<IntegrationEventLogEntry> builder)
{
builder.ToTable("IntegrationEventLog");
void ConfigureIntegrationEventLogEntry(EntityTypeBuilder<IntegrationEventLogEntry> builder)
{
builder.ToTable("IntegrationEventLog");
builder.HasKey(e => e.EventId);
builder.HasKey(e => e.EventId);
builder.Property(e => e.EventId)
.IsRequired();
builder.Property(e => e.EventId)
.IsRequired();
builder.Property(e => e.Content)
.IsRequired();
builder.Property(e => e.Content)
.IsRequired();
builder.Property(e => e.CreationTime)
.IsRequired();
builder.Property(e => e.CreationTime)
.IsRequired();
builder.Property(e => e.State)
.IsRequired();
builder.Property(e => e.State)
.IsRequired();
builder.Property(e => e.TimesSent)
.IsRequired();
builder.Property(e => e.TimesSent)
.IsRequired();
builder.Property(e => e.EventTypeName)
.IsRequired();
builder.Property(e => e.EventTypeName)
.IsRequired();
}
}
}

View File

@ -1,43 +1,36 @@
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
using System;
using System.Text.Json;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF
public class IntegrationEventLogEntry
{
public class IntegrationEventLogEntry
private IntegrationEventLogEntry() { }
public IntegrationEventLogEntry(IntegrationEvent @event, Guid transactionId)
{
private IntegrationEventLogEntry() { }
public IntegrationEventLogEntry(IntegrationEvent @event, Guid transactionId)
EventId = @event.Id;
CreationTime = @event.CreationDate;
EventTypeName = @event.GetType().FullName;
Content = JsonSerializer.Serialize(@event, @event.GetType(), new JsonSerializerOptions
{
EventId = @event.Id;
CreationTime = @event.CreationDate;
EventTypeName = @event.GetType().FullName;
Content = JsonSerializer.Serialize(@event, @event.GetType(), new JsonSerializerOptions
{
WriteIndented = true
});
State = EventStateEnum.NotPublished;
TimesSent = 0;
TransactionId = transactionId.ToString();
}
public Guid EventId { get; private set; }
public string EventTypeName { get; private set; }
[NotMapped]
public string EventTypeShortName => EventTypeName.Split('.')?.Last();
[NotMapped]
public IntegrationEvent IntegrationEvent { get; private set; }
public EventStateEnum State { get; set; }
public int TimesSent { get; set; }
public DateTime CreationTime { get; private set; }
public string Content { get; private set; }
public string TransactionId { get; private set; }
WriteIndented = true
});
State = EventStateEnum.NotPublished;
TimesSent = 0;
TransactionId = transactionId.ToString();
}
public Guid EventId { get; private set; }
public string EventTypeName { get; private set; }
[NotMapped]
public string EventTypeShortName => EventTypeName.Split('.')?.Last();
[NotMapped]
public IntegrationEvent IntegrationEvent { get; private set; }
public EventStateEnum State { get; set; }
public int TimesSent { get; set; }
public DateTime CreationTime { get; private set; }
public string Content { get; private set; }
public string TransactionId { get; private set; }
public IntegrationEventLogEntry DeserializeJsonContent(Type type)
{
IntegrationEvent = JsonSerializer.Deserialize(Content, type, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }) as IntegrationEvent;
return this;
}
public IntegrationEventLogEntry DeserializeJsonContent(Type type)
{
IntegrationEvent = JsonSerializer.Deserialize(Content, type, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }) as IntegrationEvent;
return this;
}
}

View File

@ -1,17 +1,10 @@
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services
public interface IIntegrationEventLogService
{
public interface IIntegrationEventLogService
{
Task<IEnumerable<IntegrationEventLogEntry>> RetrieveEventLogsPendingToPublishAsync(Guid transactionId);
Task SaveEventAsync(IntegrationEvent @event, IDbContextTransaction transaction);
Task MarkEventAsPublishedAsync(Guid eventId);
Task MarkEventAsInProgressAsync(Guid eventId);
Task MarkEventAsFailedAsync(Guid eventId);
}
Task<IEnumerable<IntegrationEventLogEntry>> RetrieveEventLogsPendingToPublishAsync(Guid transactionId);
Task SaveEventAsync(IntegrationEvent @event, IDbContextTransaction transaction);
Task MarkEventAsPublishedAsync(Guid eventId);
Task MarkEventAsInProgressAsync(Guid eventId);
Task MarkEventAsFailedAsync(Guid eventId);
}

View File

@ -1,110 +1,99 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services
public class IntegrationEventLogService : IIntegrationEventLogService, IDisposable
{
public class IntegrationEventLogService : IIntegrationEventLogService, IDisposable
private readonly IntegrationEventLogContext _integrationEventLogContext;
private readonly DbConnection _dbConnection;
private readonly List<Type> _eventTypes;
private volatile bool disposedValue;
public IntegrationEventLogService(DbConnection dbConnection)
{
private readonly IntegrationEventLogContext _integrationEventLogContext;
private readonly DbConnection _dbConnection;
private readonly List<Type> _eventTypes;
private volatile bool disposedValue;
_dbConnection = dbConnection ?? throw new ArgumentNullException(nameof(dbConnection));
_integrationEventLogContext = new IntegrationEventLogContext(
new DbContextOptionsBuilder<IntegrationEventLogContext>()
.UseSqlServer(_dbConnection)
.Options);
public IntegrationEventLogService(DbConnection dbConnection)
_eventTypes = Assembly.Load(Assembly.GetEntryAssembly().FullName)
.GetTypes()
.Where(t => t.Name.EndsWith(nameof(IntegrationEvent)))
.ToList();
}
public async Task<IEnumerable<IntegrationEventLogEntry>> RetrieveEventLogsPendingToPublishAsync(Guid transactionId)
{
var tid = transactionId.ToString();
var result = await _integrationEventLogContext.IntegrationEventLogs
.Where(e => e.TransactionId == tid && e.State == EventStateEnum.NotPublished).ToListAsync();
if (result != null && result.Any())
{
_dbConnection = dbConnection ?? throw new ArgumentNullException(nameof(dbConnection));
_integrationEventLogContext = new IntegrationEventLogContext(
new DbContextOptionsBuilder<IntegrationEventLogContext>()
.UseSqlServer(_dbConnection)
.Options);
_eventTypes = Assembly.Load(Assembly.GetEntryAssembly().FullName)
.GetTypes()
.Where(t => t.Name.EndsWith(nameof(IntegrationEvent)))
.ToList();
return result.OrderBy(o => o.CreationTime)
.Select(e => e.DeserializeJsonContent(_eventTypes.Find(t => t.Name == e.EventTypeShortName)));
}
public async Task<IEnumerable<IntegrationEventLogEntry>> RetrieveEventLogsPendingToPublishAsync(Guid transactionId)
return new List<IntegrationEventLogEntry>();
}
public Task SaveEventAsync(IntegrationEvent @event, IDbContextTransaction transaction)
{
if (transaction == null) throw new ArgumentNullException(nameof(transaction));
var eventLogEntry = new IntegrationEventLogEntry(@event, transaction.TransactionId);
_integrationEventLogContext.Database.UseTransaction(transaction.GetDbTransaction());
_integrationEventLogContext.IntegrationEventLogs.Add(eventLogEntry);
return _integrationEventLogContext.SaveChangesAsync();
}
public Task MarkEventAsPublishedAsync(Guid eventId)
{
return UpdateEventStatus(eventId, EventStateEnum.Published);
}
public Task MarkEventAsInProgressAsync(Guid eventId)
{
return UpdateEventStatus(eventId, EventStateEnum.InProgress);
}
public Task MarkEventAsFailedAsync(Guid eventId)
{
return UpdateEventStatus(eventId, EventStateEnum.PublishedFailed);
}
private Task UpdateEventStatus(Guid eventId, EventStateEnum status)
{
var eventLogEntry = _integrationEventLogContext.IntegrationEventLogs.Single(ie => ie.EventId == eventId);
eventLogEntry.State = status;
if (status == EventStateEnum.InProgress)
eventLogEntry.TimesSent++;
_integrationEventLogContext.IntegrationEventLogs.Update(eventLogEntry);
return _integrationEventLogContext.SaveChangesAsync();
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
var tid = transactionId.ToString();
var result = await _integrationEventLogContext.IntegrationEventLogs
.Where(e => e.TransactionId == tid && e.State == EventStateEnum.NotPublished).ToListAsync();
if (result != null && result.Any())
if (disposing)
{
return result.OrderBy(o => o.CreationTime)
.Select(e => e.DeserializeJsonContent(_eventTypes.Find(t => t.Name == e.EventTypeShortName)));
_integrationEventLogContext?.Dispose();
}
return new List<IntegrationEventLogEntry>();
}
public Task SaveEventAsync(IntegrationEvent @event, IDbContextTransaction transaction)
{
if (transaction == null) throw new ArgumentNullException(nameof(transaction));
var eventLogEntry = new IntegrationEventLogEntry(@event, transaction.TransactionId);
_integrationEventLogContext.Database.UseTransaction(transaction.GetDbTransaction());
_integrationEventLogContext.IntegrationEventLogs.Add(eventLogEntry);
return _integrationEventLogContext.SaveChangesAsync();
}
public Task MarkEventAsPublishedAsync(Guid eventId)
{
return UpdateEventStatus(eventId, EventStateEnum.Published);
}
public Task MarkEventAsInProgressAsync(Guid eventId)
{
return UpdateEventStatus(eventId, EventStateEnum.InProgress);
}
public Task MarkEventAsFailedAsync(Guid eventId)
{
return UpdateEventStatus(eventId, EventStateEnum.PublishedFailed);
}
private Task UpdateEventStatus(Guid eventId, EventStateEnum status)
{
var eventLogEntry = _integrationEventLogContext.IntegrationEventLogs.Single(ie => ie.EventId == eventId);
eventLogEntry.State = status;
if (status == EventStateEnum.InProgress)
eventLogEntry.TimesSent++;
_integrationEventLogContext.IntegrationEventLogs.Update(eventLogEntry);
return _integrationEventLogContext.SaveChangesAsync();
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
_integrationEventLogContext?.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}

View File

@ -1,31 +1,26 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities;
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities
public class ResilientTransaction
{
public class ResilientTransaction
private DbContext _context;
private ResilientTransaction(DbContext context) =>
_context = context ?? throw new ArgumentNullException(nameof(context));
public static ResilientTransaction New(DbContext context) =>
new ResilientTransaction(context);
public async Task ExecuteAsync(Func<Task> action)
{
private DbContext _context;
private ResilientTransaction(DbContext context) =>
_context = context ?? throw new ArgumentNullException(nameof(context));
public static ResilientTransaction New(DbContext context) =>
new ResilientTransaction(context);
public async Task ExecuteAsync(Func<Task> action)
//Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction():
//See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
var strategy = _context.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
//Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction():
//See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
var strategy = _context.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
using (var transaction = _context.Database.BeginTransaction())
{
using (var transaction = _context.Database.BeginTransaction())
{
await action();
transaction.Commit();
}
});
}
await action();
transaction.Commit();
}
});
}
}