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,
NotPublished = 0, Published = 2,
InProgress = 1, PublishedFailed = 3
Published = 2,
PublishedFailed = 3
}
} }

View File

@ -1,45 +1,41 @@
using Microsoft.EntityFrameworkCore; namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
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) protected override void OnModelCreating(ModelBuilder builder)
{ {
builder.Entity<IntegrationEventLogEntry>(ConfigureIntegrationEventLogEntry); builder.Entity<IntegrationEventLogEntry>(ConfigureIntegrationEventLogEntry);
} }
void ConfigureIntegrationEventLogEntry(EntityTypeBuilder<IntegrationEventLogEntry> builder) void ConfigureIntegrationEventLogEntry(EntityTypeBuilder<IntegrationEventLogEntry> builder)
{ {
builder.ToTable("IntegrationEventLog"); builder.ToTable("IntegrationEventLog");
builder.HasKey(e => e.EventId); builder.HasKey(e => e.EventId);
builder.Property(e => e.EventId) builder.Property(e => e.EventId)
.IsRequired(); .IsRequired();
builder.Property(e => e.Content) builder.Property(e => e.Content)
.IsRequired(); .IsRequired();
builder.Property(e => e.CreationTime) builder.Property(e => e.CreationTime)
.IsRequired(); .IsRequired();
builder.Property(e => e.State) builder.Property(e => e.State)
.IsRequired(); .IsRequired();
builder.Property(e => e.TimesSent) builder.Property(e => e.TimesSent)
.IsRequired(); .IsRequired();
builder.Property(e => e.EventTypeName) builder.Property(e => e.EventTypeName)
.IsRequired(); .IsRequired();
}
} }
} }

View File

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

View File

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

View File

@ -1,110 +1,99 @@
using Microsoft.EntityFrameworkCore; namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
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 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; _dbConnection = dbConnection ?? throw new ArgumentNullException(nameof(dbConnection));
private readonly DbConnection _dbConnection; _integrationEventLogContext = new IntegrationEventLogContext(
private readonly List<Type> _eventTypes; new DbContextOptionsBuilder<IntegrationEventLogContext>()
private volatile bool disposedValue; .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)); return result.OrderBy(o => o.CreationTime)
_integrationEventLogContext = new IntegrationEventLogContext( .Select(e => e.DeserializeJsonContent(_eventTypes.Find(t => t.Name == e.EventTypeShortName)));
new DbContextOptionsBuilder<IntegrationEventLogContext>()
.UseSqlServer(_dbConnection)
.Options);
_eventTypes = Assembly.Load(Assembly.GetEntryAssembly().FullName)
.GetTypes()
.Where(t => t.Name.EndsWith(nameof(IntegrationEvent)))
.ToList();
} }
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(); if (disposing)
var result = await _integrationEventLogContext.IntegrationEventLogs
.Where(e => e.TransactionId == tid && e.State == EventStateEnum.NotPublished).ToListAsync();
if (result != null && result.Any())
{ {
return result.OrderBy(o => o.CreationTime) _integrationEventLogContext?.Dispose();
.Select(e => e.DeserializeJsonContent(_eventTypes.Find(t => t.Name == e.EventTypeShortName)));
} }
return new List<IntegrationEventLogEntry>();
}
public Task SaveEventAsync(IntegrationEvent @event, IDbContextTransaction transaction) disposedValue = true;
{
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);
} }
} }
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
} }

View File

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