Move using statements to globalusing file
This commit is contained in:
		
							parent
							
								
									5fd90e8cb6
								
							
						
					
					
						commit
						9d73669d86
					
				| @ -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 |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -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(); | ||||||
| 
 | 
 | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -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; | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -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); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -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); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -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(); |         }); | ||||||
|                 } |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user