Skip to content
Merged
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
47 changes: 47 additions & 0 deletions Shared.EventStore/EventStore/AggregateRepositoryManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace Shared.EventStore.EventStore
{
using System;
using DomainDrivenDesign.EventStore;

public class AggregateRepositoryManager : IAggregateRepositoryManager
{
#region Fields

/// <summary>
/// The event store context manager
/// </summary>
private readonly IEventStoreContextManager EventStoreContextManager;

#endregion

#region Constructors

/// <summary>
/// Initializes a new instance of the <see cref="AggregateRepositoryManager" /> class.
/// </summary>
/// <param name="eventStoreContextManager">The event store context manager.</param>
public AggregateRepositoryManager(IEventStoreContextManager eventStoreContextManager)
{
this.EventStoreContextManager = eventStoreContextManager;
}

#endregion

#region Methods

/// <summary>
/// Gets the aggregate repository.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="identifier">The identifier.</param>
/// <returns></returns>
public IAggregateRepository<T> GetAggregateRepository<T>(Guid identifier) where T : Aggregate, new()
{
IEventStoreContext context = this.EventStoreContextManager.GetEventStoreContext(identifier.ToString());

return new AggregateRepository<T>(context);
}

#endregion
}
}
23 changes: 23 additions & 0 deletions Shared.EventStore/EventStore/IAggregateRepositoryManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Shared.EventStore.EventStore
{
using DomainDrivenDesign.EventStore;

public interface IAggregateRepositoryManager
{
#region Methods

/// <summary>
/// Gets the aggregate repository.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="identifier">The identifier.</param>
/// <returns></returns>
IAggregateRepository<T> GetAggregateRepository<T>(Guid identifier) where T : Aggregate, new();

#endregion
}
}
137 changes: 137 additions & 0 deletions Shared.EventStore/EventStore/IEventStoreContextManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Shared.EventStore.EventStore
{
using System.Diagnostics;
using System.Threading;
using DomainDrivenDesign.EventStore;
using Microsoft.Extensions.Logging;
using Shared.Repositories;

public interface IEventStoreContextManager
{
IEventStoreContext GetEventStoreContext(String connectionIdentifier);
}

public class EventStoreContextManager : IEventStoreContextManager
{
#region Fields

/// <summary>
/// The event store context function
/// </summary>
private readonly Func<String, IEventStoreContext> EventStoreContextFunc;

private readonly IConnectionStringConfigurationRepository ConnectionStringConfigurationRepository;

/// <summary>
/// The event store contexts
/// </summary>
private readonly Dictionary<String, IEventStoreContext> EventStoreContexts;

/// <summary>
/// The context
/// </summary>
private readonly IEventStoreContext Context;

//TODO static?
/// <summary>
/// The padlock
/// </summary>
private readonly Object padlock = new Object();

/// <summary>
/// Occurs when [trace generated].
/// </summary>
public event TraceHandler TraceGenerated;

#endregion

#region Constructors

/// <summary>
/// Initializes a new instance of the <see cref="EventStoreContextManager" /> class.
/// </summary>
/// <param name="eventStoreContextFunc">The event store context function.</param>
public EventStoreContextManager(Func<String, IEventStoreContext> eventStoreContextFunc,
IConnectionStringConfigurationRepository connectionStringConfigurationRepository)
{
this.EventStoreContexts = new Dictionary<String, IEventStoreContext>();
this.EventStoreContextFunc = eventStoreContextFunc;
this.ConnectionStringConfigurationRepository = connectionStringConfigurationRepository;
}

/// <summary>
/// Initializes a new instance of the <see cref="EventStoreContextManager"/> class.
/// </summary>
/// <param name="eventStoreContext">The event store context.</param>
public EventStoreContextManager(IEventStoreContext eventStoreContext)
{
this.Context = eventStoreContext;
}

#endregion

#region Methods

public IEventStoreContext GetEventStoreContext(String connectionIdentifier)
{
if (this.Context != null)
{
return this.Context;
}

this.WriteTrace($"No resolved context found, about to resolve one using connectionIdentifier {connectionIdentifier}");

if (this.EventStoreContexts.ContainsKey(connectionIdentifier))
{
return this.EventStoreContexts[connectionIdentifier.ToString()];
}

this.WriteTrace($"Creating a new EventStoreContext for connectionIdentifier {connectionIdentifier}");

lock (this.padlock)
{
if (!this.EventStoreContexts.ContainsKey(connectionIdentifier))
{
// This will need to now look up the ES Connection string from persistence
String connectionString = this.ConnectionStringConfigurationRepository.GetConnectionString(connectionIdentifier, ConnectionStringType.EventStore, CancellationToken.None).Result;

//this.WriteTrace($"Connection String is {connectionString}");

//IEventStoreContext eventStoreContext = this.EventStoreContextFunc(connectionString);

//this.EventStoreContexts.Add(connectionStringId, eventStoreContext);
}

return this.EventStoreContexts[connectionIdentifier];
}
}


/// <summary>
/// Writes the trace.
/// </summary>
/// <param name="trace">The trace.</param>
private void WriteTrace(String trace)
{
if (this.TraceGenerated != null)
{
this.TraceGenerated(trace, LogLevel.Information);
}
}

private void GuardAgainstNoConnectionIdentifier(String connectionIdentifier)
{
//Check if the connectionStringIdentifier is present
if (String.IsNullOrEmpty(connectionIdentifier))
{
throw new ArgumentException("Value cannot be empty.", nameof(connectionIdentifier));
}
}

#endregion
}
}
1 change: 1 addition & 0 deletions Shared.EventStore/Shared.EventStore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

<ItemGroup>
<ProjectReference Include="..\Shared.DomainDrivenDesign\Shared.DomainDrivenDesign.csproj" />
<ProjectReference Include="..\Shared\Shared.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;

namespace Shared.EntityFramework.ConnectionStringConfiguration
{
using System.ComponentModel.DataAnnotations.Schema;

public class ConnectionStringConfiguration
{
/// <summary>
/// Gets or sets the identifier.
/// </summary>
/// <value>
/// The identifier.
/// </value>
[Key]
public Guid Id { get; set; }

/// <summary>
/// Gets or sets the connection string identifier.
/// </summary>
/// <value>
/// The connection string identifier.
/// </value>
[Required]
[Column("externalIdentifier")]
public String ExternalIdentifier { get; set; }

/// <summary>
/// Gets or sets the connection string type identifier.
/// </summary>
/// <value>
/// The connection string type identifier.
/// </value>
public Int32 ConnectionStringTypeId { get; set; }

/// <summary>
/// Gets or sets the type of the connection string.
/// </summary>
/// <value>
/// The type of the connection string.
/// </value>
[ForeignKey(nameof(ConnectionStringTypeId))]
public virtual ConnectionStringType ConnectionStringType { get; set; }


/// <summary>
/// Gets or sets the connection string.
/// </summary>
/// <value>
/// The connection string.
/// </value>
[Required]
[Column("connectionString")]
public String ConnectionString { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;

namespace Shared.EntityFramework.ConnectionStringConfiguration
{
public class ConnectionStringConfigurationContext : DbContext
{
#region Fields

/// <summary>
/// The connection string
/// </summary>
private readonly String ConnectionString;

#endregion

#region Constructors

/// <summary>
/// Initializes a new instance of the <see cref="ConnectionStringConfigurationContext" /> class using the connection string called ReadModelContext in the app.config file.
/// </summary>
public ConnectionStringConfigurationContext()
{
// Paramaterless constructor required for migrations.
}

/// <summary>
/// Initializes a new instance of the <see cref="ConnectionStringConfigurationContext" /> class using the connection string passed in.
/// </summary>
/// <param name="connectionString">The connection string.</param>
public ConnectionStringConfigurationContext(String connectionString)
{
this.ConnectionString = connectionString;
}

/// <summary>
/// Initializes a new instance of the <see cref="ConnectionStringConfigurationContext"/> class.
/// </summary>
/// <param name="dbContextOptions">The database context options.</param>
public ConnectionStringConfigurationContext(DbContextOptions dbContextOptions) : base(dbContextOptions)
{
}

#endregion

/// <summary>
/// Gets or sets the connection string configuration.
/// </summary>
/// <value>
/// The connection string configuration.
/// </value>
public DbSet<ConnectionStringConfiguration> ConnectionStringConfiguration { get; set; }

/// <summary>
/// Gets or sets the type of the connection string.
/// </summary>
/// <value>
/// The type of the connection string.
/// </value>
public DbSet<ConnectionStringType> ConnectionStringType { get; set; }

/// <summary>
/// <para>
/// Override this method to configure the database (and other options) to be used for this context.
/// This method is called for each instance of the context that is created.
/// </para>
/// <para>
/// In situations where an instance of <see cref="T:Microsoft.Data.Entity.Infrastructure.DbContextOptions" /> may or may not have been passed
/// to the constructor, you can use <see cref="P:Microsoft.Data.Entity.DbContextOptionsBuilder.IsConfigured" /> to determine if
/// the options have already been set, and skip some or all of the logic in
/// <see cref="M:Microsoft.Data.Entity.DbContext.OnConfiguring(Microsoft.Data.Entity.DbContextOptionsBuilder)" />.
/// </para>
/// </summary>
/// <param name="optionsBuilder">A builder used to create or modify options for this context. Databases (and other extensions)
/// typically define extension methods on this object that allow you to configure the context.</param>
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!string.IsNullOrWhiteSpace(this.ConnectionString))
{
optionsBuilder.UseSqlServer(this.ConnectionString);
}

base.OnConfiguring(optionsBuilder);
}

/// <summary>
/// Override this method to further configure the model that was discovered by convention from the entity types
/// exposed in <see cref="T:Microsoft.EntityFrameworkCore.DbSet`1" /> properties on your derived context. The resulting model may be cached
/// and re-used for subsequent instances of your derived context.
/// </summary>
/// <param name="modelBuilder">The builder being used to construct the model for this context. Databases (and other extensions) typically
/// define extension methods on this object that allow you to configure aspects of the model that are specific
/// to a given database.</param>
/// <remarks>
/// If a model is explicitly set on the options for this context (via <see cref="M:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.UseModel(Microsoft.EntityFrameworkCore.Metadata.IModel)" />)
/// then this method will not be run.
/// </remarks>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ConnectionStringConfiguration>().HasIndex(c => new
{
c.ExternalIdentifier,
c.ConnectionStringTypeId
}).IsUnique();
}
}
}
Loading