Browse Source

No Autofac

pull/170/head
Sebastian Stehle 9 years ago
parent
commit
b41cec579e
  1. 2
      src/Squidex.Domain.Apps.Read.MongoDb/Apps/MongoAppRepository.cs
  2. 2
      src/Squidex.Domain.Apps.Read.MongoDb/Assets/MongoAssetRepository.cs
  3. 2
      src/Squidex.Domain.Apps.Read.MongoDb/Assets/MongoAssetStatsRepository.cs
  4. 2
      src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository.cs
  5. 16
      src/Squidex.Domain.Apps.Read/Apps/IAppEventConsumer.cs
  6. 16
      src/Squidex.Domain.Apps.Read/Assets/IAssetEventConsumer.cs
  7. 16
      src/Squidex.Domain.Apps.Read/Schemas/ISchemaEventConsumer.cs
  8. 17
      src/Squidex.Infrastructure/CQRS/Events/CompoundEventConsumer.cs
  9. 10
      src/Squidex.Infrastructure/CollectionExtensions.cs
  10. 51
      src/Squidex/Config/Domain/AssetServices.cs
  11. 91
      src/Squidex/Config/Domain/AssetStoreModule.cs
  12. 28
      src/Squidex/Config/Domain/EventPublishersServices.cs
  13. 18
      src/Squidex/Config/Domain/EventStoreExtensions.cs
  14. 112
      src/Squidex/Config/Domain/EventStoreModule.cs
  15. 64
      src/Squidex/Config/Domain/EventStoreServices.cs
  16. 155
      src/Squidex/Config/Domain/InfrastructureModule.cs
  17. 116
      src/Squidex/Config/Domain/InfrastructureServices.cs
  18. 69
      src/Squidex/Config/Domain/PubSubModule.cs
  19. 41
      src/Squidex/Config/Domain/PubSubServices.cs
  20. 139
      src/Squidex/Config/Domain/ReadModule.cs
  21. 114
      src/Squidex/Config/Domain/ReadServices.cs
  22. 8
      src/Squidex/Config/Domain/SerializationServices.cs
  23. 44
      src/Squidex/Config/Domain/StoreModule.cs
  24. 208
      src/Squidex/Config/Domain/StoreMongoDbModule.cs
  25. 122
      src/Squidex/Config/Domain/StoreServices.cs
  26. 30
      src/Squidex/Config/Domain/SystemExtensions.cs
  27. 113
      src/Squidex/Config/Domain/WriteModule.cs
  28. 79
      src/Squidex/Config/Domain/WriteServices.cs
  29. 4
      src/Squidex/Config/Identity/AuthenticationExtensions.cs
  30. 6
      src/Squidex/Config/Identity/AuthenticationServices.cs
  31. 4
      src/Squidex/Config/Identity/IdentityExtensions.cs
  32. 103
      src/Squidex/Config/Identity/IdentityServerServices.cs
  33. 130
      src/Squidex/Config/Identity/IdentityServices.cs
  34. 21
      src/Squidex/Config/Options.cs
  35. 94
      src/Squidex/Config/ServiceExtensions.cs
  36. 6
      src/Squidex/Config/Swagger/SwaggerExtensions.cs
  37. 2
      src/Squidex/Config/Web/WebExtensions.cs
  38. 35
      src/Squidex/Config/Web/WebModule.cs
  39. 8
      src/Squidex/Config/Web/WebServices.cs
  40. 4
      src/Squidex/Config/Web/WebpackExtensions.cs
  41. 2
      src/Squidex/Squidex.csproj
  42. 50
      src/Squidex/Startup.cs

2
src/Squidex.Domain.Apps.Read.MongoDb/Apps/MongoAppRepository.cs

@ -18,7 +18,7 @@ using Squidex.Infrastructure.MongoDb;
namespace Squidex.Domain.Apps.Read.MongoDb.Apps
{
public partial class MongoAppRepository : MongoRepositoryBase<MongoAppEntity>, IAppRepository, IEventConsumer
public partial class MongoAppRepository : MongoRepositoryBase<MongoAppEntity>, IAppRepository, IAppEventConsumer
{
public MongoAppRepository(IMongoDatabase database)
: base(database)

2
src/Squidex.Domain.Apps.Read.MongoDb/Assets/MongoAssetRepository.cs

@ -19,7 +19,7 @@ using Squidex.Infrastructure.MongoDb;
namespace Squidex.Domain.Apps.Read.MongoDb.Assets
{
public partial class MongoAssetRepository : MongoRepositoryBase<MongoAssetEntity>, IAssetRepository, IEventConsumer
public partial class MongoAssetRepository : MongoRepositoryBase<MongoAssetEntity>, IAssetRepository, IAssetEventConsumer
{
public MongoAssetRepository(IMongoDatabase database)
: base(database)

2
src/Squidex.Domain.Apps.Read.MongoDb/Assets/MongoAssetStatsRepository.cs

@ -19,7 +19,7 @@ using Squidex.Infrastructure.MongoDb;
namespace Squidex.Domain.Apps.Read.MongoDb.Assets
{
public partial class MongoAssetStatsRepository : MongoRepositoryBase<MongoAssetStatsEntity>, IAssetStatsRepository, IEventConsumer
public partial class MongoAssetStatsRepository : MongoRepositoryBase<MongoAssetStatsEntity>, IAssetStatsRepository, IAssetEventConsumer
{
public MongoAssetStatsRepository(IMongoDatabase database)
: base(database)

2
src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository.cs

@ -20,7 +20,7 @@ using Squidex.Infrastructure.MongoDb;
namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
{
public partial class MongoSchemaRepository : MongoRepositoryBase<MongoSchemaEntity>, ISchemaRepository, IEventConsumer
public partial class MongoSchemaRepository : MongoRepositoryBase<MongoSchemaEntity>, ISchemaRepository, ISchemaEventConsumer
{
private readonly FieldRegistry registry;

16
src/Squidex.Domain.Apps.Read/Apps/IAppEventConsumer.cs

@ -0,0 +1,16 @@
// ==========================================================================
// IAppEventConsumer.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Squidex.Infrastructure.CQRS.Events;
namespace Squidex.Domain.Apps.Read.Apps
{
public interface IAppEventConsumer : IEventConsumer
{
}
}

16
src/Squidex.Domain.Apps.Read/Assets/IAssetEventConsumer.cs

@ -0,0 +1,16 @@
// ==========================================================================
// IAssetEventConsumer.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Squidex.Infrastructure.CQRS.Events;
namespace Squidex.Domain.Apps.Read.Assets
{
public interface IAssetEventConsumer : IEventConsumer
{
}
}

16
src/Squidex.Domain.Apps.Read/Schemas/ISchemaEventConsumer.cs

@ -0,0 +1,16 @@
// ==========================================================================
// ISchemaEventConsumer.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Squidex.Infrastructure.CQRS.Events;
namespace Squidex.Domain.Apps.Read.Schemas
{
public interface ISchemaEventConsumer : IEventConsumer
{
}
}

17
src/Squidex.Infrastructure/CQRS/Events/CompoundEventConsumer.cs

@ -6,6 +6,7 @@
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -24,6 +25,22 @@ namespace Squidex.Infrastructure.CQRS.Events
{
}
public CompoundEventConsumer(IEventConsumer[] inners)
{
Guard.NotNull(inners, nameof(inners));
Guard.NotEmpty(inners, nameof(inners));
this.inners = inners;
Name = inners.First().Name;
var innerFilters =
this.inners.Where(x => !string.IsNullOrWhiteSpace(x.EventsFilter))
.Select(x => $"({x.EventsFilter})");
EventsFilter = string.Join("|", innerFilters);
}
public CompoundEventConsumer(string name, IEventConsumer first, params IEventConsumer[] inners)
{
Guard.NotNull(first, nameof(first));

10
src/Squidex.Infrastructure/CollectionExtensions.cs

@ -30,6 +30,16 @@ namespace Squidex.Infrastructure
}
}
public static IEnumerable<T> OrEmpty<T>(this IEnumerable<T> source)
{
return source ?? Enumerable.Empty<T>();
}
public static IEnumerable<T> Concat<T>(this IEnumerable<T> source, T value)
{
return source.Concat(Enumerable.Repeat(value, 1));
}
public static int SequentialHashCode<T>(this IEnumerable<T> collection)
{
return collection.SequentialHashCode(EqualityComparer<T>.Default);

51
src/Squidex/Config/Domain/AssetServices.cs

@ -0,0 +1,51 @@
// ==========================================================================
// AssetServices.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Assets;
using Squidex.Infrastructure.Log;
namespace Squidex.Config.Domain
{
public static class AssetServices
{
public static void AddMyAssetServices(this IServiceCollection services, IConfiguration config)
{
config.ConfigureByOption("assetStore:type", new Options
{
["Folder"] = () =>
{
var path = config.GetRequiredValue("assetStore:folder:path");
services.AddSingleton(c => new FolderAssetStore(path, c.GetRequiredService<ISemanticLog>()))
.As<IAssetStore>()
.As<IExternalSystem>();
},
["GoogleCloud"] = () =>
{
var bucketName = config.GetRequiredValue("assetStore:googleCloud:bucket");
services.AddSingleton(c => new GoogleCloudAssetStore(bucketName))
.As<IAssetStore>()
.As<IExternalSystem>();
},
["AzureBlob"] = () =>
{
var connectionString = config.GetRequiredValue("assetStore:azureBlob:connectionString");
var containerName = config.GetRequiredValue("assetStore:azureBlob:containerName");
services.AddSingleton(c => new AzureBlobAssetStore(connectionString, containerName))
.As<IAssetStore>()
.As<IExternalSystem>();
}
});
}
}
}

91
src/Squidex/Config/Domain/AssetStoreModule.cs

@ -1,91 +0,0 @@
// ==========================================================================
// AssetStoreModule.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Autofac;
using Microsoft.Extensions.Configuration;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Assets;
using Squidex.Infrastructure.Log;
namespace Squidex.Config.Domain
{
public sealed class AssetStoreModule : Module
{
private IConfiguration Configuration { get; }
public AssetStoreModule(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void Load(ContainerBuilder builder)
{
var assetStoreType = Configuration.GetValue<string>("assetStore:type");
if (string.IsNullOrWhiteSpace(assetStoreType))
{
throw new ConfigurationException("Configure the AssetStore type with 'assetStore:type'.");
}
if (string.Equals(assetStoreType, "Folder", StringComparison.OrdinalIgnoreCase))
{
var path = Configuration.GetValue<string>("assetStore:folder:path");
if (string.IsNullOrWhiteSpace(path))
{
throw new ConfigurationException("Configure AssetStore Folder path with 'assetStore:folder:path'.");
}
builder.Register(c => new FolderAssetStore(path, c.Resolve<ISemanticLog>()))
.As<IAssetStore>()
.As<IExternalSystem>()
.SingleInstance();
}
else if (string.Equals(assetStoreType, "GoogleCloud", StringComparison.OrdinalIgnoreCase))
{
var bucketName = Configuration.GetValue<string>("assetStore:googleCloud:bucket");
if (string.IsNullOrWhiteSpace(bucketName))
{
throw new ConfigurationException("Configure AssetStore GoogleCloud bucket with 'assetStore:googleCloud:bucket'.");
}
builder.Register(c => new GoogleCloudAssetStore(bucketName))
.As<IAssetStore>()
.As<IExternalSystem>()
.SingleInstance();
}
else if (string.Equals(assetStoreType, "AzureBlob", StringComparison.OrdinalIgnoreCase))
{
var connectionString = Configuration.GetValue<string>("assetStore:azureBlob:connectionString");
if (string.IsNullOrWhiteSpace(connectionString))
{
throw new ConfigurationException("Configure AssetStore AzureBlob connection string with 'assetStore:azureBlob:connectionString'.");
}
var containerName = Configuration.GetValue<string>("assetStore:azureBlob:containerName");
if (string.IsNullOrWhiteSpace(containerName))
{
throw new ConfigurationException("Configure AssetStore AzureBlob container with 'assetStore:azureBlob:containerName'.");
}
builder.Register(c => new AzureBlobAssetStore(connectionString, containerName))
.As<IAssetStore>()
.As<IExternalSystem>()
.SingleInstance();
}
else
{
throw new ConfigurationException($"Unsupported value '{assetStoreType}' for 'assetStore:type', supported: AzureBlob, Folder, GoogleCloud.");
}
}
}
}

28
src/Squidex/Config/Domain/EventPublishersModule.cs → src/Squidex/Config/Domain/EventPublishersServices.cs

@ -1,5 +1,5 @@
// ==========================================================================
// EventPublishersModule.cs
// EventPublishersServices.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
@ -7,26 +7,19 @@
// ==========================================================================
using System;
using Autofac;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Events;
namespace Squidex.Config.Domain
{
public sealed class EventPublishersModule : Module
public static class EventPublishersServices
{
private IConfiguration Configuration { get; }
public EventPublishersModule(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void Load(ContainerBuilder builder)
public static void AddMyEventPublishersServices(this IServiceCollection services, IConfiguration configuration)
{
var eventPublishers = Configuration.GetSection("eventPublishers");
var eventPublishers = configuration.GetSection("eventPublishers");
foreach (var child in eventPublishers.GetChildren())
{
@ -37,15 +30,15 @@ namespace Squidex.Config.Domain
throw new ConfigurationException($"Configure EventPublisher type with 'eventPublishers:{child.Key}:type'.");
}
var eventsFilter = Configuration.GetValue<string>("eventsFilter");
var eventsFilter = configuration.GetValue<string>("eventsFilter");
var enabled = child.GetValue<bool>("enabled");
if (string.Equals(eventPublisherType, "RabbitMq", StringComparison.OrdinalIgnoreCase))
{
var configuration = child.GetValue<string>("configuration");
var publisherConfig = child.GetValue<string>("configuration");
if (string.IsNullOrWhiteSpace(configuration))
if (string.IsNullOrWhiteSpace(publisherConfig))
{
throw new ConfigurationException($"Configure EventPublisher RabbitMq configuration with 'eventPublishers:{child.Key}:configuration'.");
}
@ -61,10 +54,9 @@ namespace Squidex.Config.Domain
if (enabled)
{
builder.Register(c => new RabbitMqEventConsumer(c.Resolve<JsonSerializerSettings>(), name, configuration, exchange, eventsFilter))
services.AddSingleton(c => new RabbitMqEventConsumer(c.GetRequiredService<JsonSerializerSettings>(), name, publisherConfig, exchange, eventsFilter))
.As<IEventConsumer>()
.As<IExternalSystem>()
.SingleInstance();
.As<IExternalSystem>();
}
}
else

18
src/Squidex/Config/Domain/Usages.cs → src/Squidex/Config/Domain/EventStoreExtensions.cs

@ -1,22 +1,20 @@
// ==========================================================================
// Usages.cs
// EventStoreUsages.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Actors;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.CQRS.Events.Actors;
namespace Squidex.Config.Domain
{
public static class Usages
public static class EventStoreExtensions
{
public static IApplicationBuilder UseMyEventStore(this IApplicationBuilder app)
{
@ -40,17 +38,5 @@ namespace Squidex.Config.Domain
return app;
}
public static IApplicationBuilder TestExternalSystems(this IApplicationBuilder app)
{
var systems = app.ApplicationServices.GetRequiredService<IEnumerable<IExternalSystem>>();
foreach (var system in systems)
{
system.Connect();
}
return app;
}
}
}

112
src/Squidex/Config/Domain/EventStoreModule.cs

@ -1,112 +0,0 @@
// ==========================================================================
// EventStoreModule.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Autofac;
using Autofac.Core;
using EventStore.ClientAPI;
using Microsoft.Extensions.Configuration;
using MongoDB.Driver;
using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.CQRS.Events.Actors;
namespace Squidex.Config.Domain
{
public sealed class EventStoreModule : Module
{
private const string MongoClientRegistration = "EventStoreMongoClient";
private const string MongoDatabaseRegistration = "EventStoreMongoDatabase";
private IConfiguration Configuration { get; }
public EventStoreModule(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void Load(ContainerBuilder builder)
{
var consumeEvents = Configuration.GetValue<bool>("eventStore:consume");
if (consumeEvents)
{
builder.RegisterType<EventConsumerActor>()
.AsSelf()
.InstancePerDependency();
}
var eventStoreType = Configuration.GetValue<string>("eventStore:type");
if (string.IsNullOrWhiteSpace(eventStoreType))
{
throw new ConfigurationException("Configure EventStore type with 'eventStore:type'.");
}
if (string.Equals(eventStoreType, "MongoDb", StringComparison.OrdinalIgnoreCase))
{
var configuration = Configuration.GetValue<string>("eventStore:mongoDb:configuration");
if (string.IsNullOrWhiteSpace(configuration))
{
throw new ConfigurationException("Configure EventStore MongoDb configuration with 'eventStore:mongoDb:configuration'.");
}
var database = Configuration.GetValue<string>("eventStore:mongoDb:database");
if (string.IsNullOrWhiteSpace(database))
{
throw new ConfigurationException("Configure EventStore MongoDb Database name with 'eventStore:mongoDb:database'.");
}
builder.Register(c => Singletons<IMongoClient>.GetOrAdd(configuration, s => new MongoClient(s)))
.Named<IMongoClient>(MongoClientRegistration)
.SingleInstance();
builder.Register(c => c.ResolveNamed<IMongoClient>(MongoClientRegistration).GetDatabase(database))
.Named<IMongoDatabase>(MongoDatabaseRegistration)
.SingleInstance();
builder.RegisterType<MongoEventStore>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IExternalSystem>()
.As<IEventStore>()
.SingleInstance();
}
else if (string.Equals(eventStoreType, "GetEventStore", StringComparison.OrdinalIgnoreCase))
{
var configuration = Configuration.GetValue<string>("eventStore:getEventStore:configuration");
if (string.IsNullOrWhiteSpace(configuration))
{
throw new ConfigurationException("Configure GetEventStore EventStore configuration with 'eventStore:getEventStore:configuration'.");
}
var projectionHost = Configuration.GetValue<string>("eventStore:getEventStore:projectionHost");
if (string.IsNullOrWhiteSpace(projectionHost))
{
throw new ConfigurationException("Configure GetEventStore EventStore projection host with 'eventStore:getEventStore:projectionHost'.");
}
var prefix = Configuration.GetValue<string>("eventStore:getEventStore:prefix");
var connection = EventStoreConnection.Create(configuration);
builder.Register(c => new GetEventStore(connection, prefix, projectionHost))
.As<IExternalSystem>()
.As<IEventStore>()
.SingleInstance();
}
else
{
throw new ConfigurationException($"Unsupported value '{eventStoreType}' for 'eventStore:type', supported: MongoDb, GetEventStore.");
}
}
}
}

64
src/Squidex/Config/Domain/EventStoreServices.cs

@ -0,0 +1,64 @@
// ==========================================================================
// EventStoreServices.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using EventStore.ClientAPI;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using MongoDB.Driver;
using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.CQRS.Events.Actors;
namespace Squidex.Config.Domain
{
public static class EventStoreServices
{
public static void AddMyEventStoreServices(this IServiceCollection services, IConfiguration config)
{
var consumeEvents = config.GetOptionalValue("eventStore:consume", false);
if (!consumeEvents)
{
return;
}
config.ConfigureByOption("eventStore:type", new Options
{
["MongoDb"] = () =>
{
var mongoConfiguration = config.GetRequiredValue("eventStore:mongoDb:configuration");
var mongoDatabaseName = config.GetRequiredValue("eventStore:mongoDb:database");
services.AddSingleton(c =>
{
var mongoClient = Singletons<IMongoClient>.GetOrAdd(mongoConfiguration, s => new MongoClient(s));
var mongDatabase = mongoClient.GetDatabase(mongoDatabaseName);
return new MongoEventStore(mongDatabase, c.GetRequiredService<IEventNotifier>());
})
.As<IExternalSystem>()
.As<IEventStore>();
},
["GetEventStore"] = () =>
{
var eventStoreConfiguration = config.GetRequiredValue("eventStore:getEventStore:configuration");
var eventStoreProjectionHost = config.GetRequiredValue("eventStore:getEventStore:projectionHost");
var eventStorePrefix = config.GetValue<string>("eventStore:getEventStore:prefix");
var connection = EventStoreConnection.Create(eventStoreConfiguration);
services.AddSingleton(c => new GetEventStore(connection, eventStorePrefix, eventStoreProjectionHost))
.As<IExternalSystem>()
.As<IEventStore>();
}
});
services.AddSingleton<EventConsumerActor>();
}
}
}

155
src/Squidex/Config/Domain/InfrastructureModule.cs

@ -1,155 +0,0 @@
// ==========================================================================
// InfrastructureModule.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Autofac;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using NodaTime;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Actors;
using Squidex.Infrastructure.Assets;
using Squidex.Infrastructure.Assets.ImageSharp;
using Squidex.Infrastructure.Caching;
using Squidex.Infrastructure.CQRS.Commands;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.UsageTracking;
using Squidex.Pipeline;
namespace Squidex.Config.Domain
{
public sealed class InfrastructureModule : Module
{
private IConfiguration Configuration { get; }
public InfrastructureModule(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void Load(ContainerBuilder builder)
{
if (Configuration.GetValue<bool>("logging:human"))
{
builder.Register(c => new Func<IObjectWriter>(() => new JsonLogWriter(Formatting.Indented, true)))
.AsSelf()
.SingleInstance();
}
else
{
builder.Register(c => new Func<IObjectWriter>(() => new JsonLogWriter()))
.AsSelf()
.SingleInstance();
}
var loggingFile = Configuration.GetValue<string>("logging:file");
if (!string.IsNullOrWhiteSpace(loggingFile))
{
builder.RegisterInstance(new FileChannel(loggingFile))
.As<ILogChannel>()
.As<IExternalSystem>()
.SingleInstance();
}
builder.Register(c => new ApplicationInfoLogAppender(GetType(), Guid.NewGuid()))
.As<ILogAppender>()
.SingleInstance();
builder.RegisterType<ActionContextLogAppender>()
.As<ILogAppender>()
.SingleInstance();
builder.RegisterType<TimestampLogAppender>()
.As<ILogAppender>()
.SingleInstance();
builder.RegisterType<DebugLogChannel>()
.As<ILogChannel>()
.SingleInstance();
builder.RegisterType<ConsoleLogChannel>()
.As<ILogChannel>()
.SingleInstance();
builder.RegisterType<SemanticLog>()
.As<ISemanticLog>()
.SingleInstance();
builder.Register(c => SystemClock.Instance)
.As<IClock>()
.SingleInstance();
builder.RegisterType<BackgroundUsageTracker>()
.As<IUsageTracker>()
.SingleInstance();
builder.RegisterType<HttpContextAccessor>()
.As<IHttpContextAccessor>()
.SingleInstance();
builder.RegisterType<ActionContextAccessor>()
.As<IActionContextAccessor>()
.SingleInstance();
builder.RegisterType<DefaultDomainObjectRepository>()
.As<IDomainObjectRepository>()
.SingleInstance();
builder.RegisterType<DefaultDomainObjectFactory>()
.As<IDomainObjectFactory>()
.SingleInstance();
builder.RegisterType<AggregateHandler>()
.As<IAggregateHandler>()
.SingleInstance();
builder.RegisterType<InMemoryCommandBus>()
.As<ICommandBus>()
.SingleInstance();
builder.RegisterType<DefaultEventNotifier>()
.As<IEventNotifier>()
.SingleInstance();
builder.RegisterType<DefaultStreamNameResolver>()
.As<IStreamNameResolver>()
.SingleInstance();
builder.RegisterType<ImageSharpAssetThumbnailGenerator>()
.As<IAssetThumbnailGenerator>()
.SingleInstance();
builder.Register(c => new InvalidatingMemoryCache(new MemoryCache(c.Resolve<IOptions<MemoryCacheOptions>>()), c.Resolve<IPubSub>()))
.As<IMemoryCache>()
.SingleInstance();
builder.RegisterType<DefaultRemoteActorChannel>()
.As<IRemoteActorChannel>()
.SingleInstance();
builder.RegisterType<RemoteActors>()
.As<IActors>()
.AsSelf()
.SingleInstance();
builder.RegisterType<EventConsumerCleaner>()
.AsSelf()
.SingleInstance();
builder.RegisterType<EventDataFormatter>()
.AsSelf()
.SingleInstance();
}
}
}

116
src/Squidex/Config/Domain/InfrastructureServices.cs

@ -0,0 +1,116 @@
// ==========================================================================
// InfrastructureServices.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using NodaTime;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Actors;
using Squidex.Infrastructure.Assets;
using Squidex.Infrastructure.Assets.ImageSharp;
using Squidex.Infrastructure.Caching;
using Squidex.Infrastructure.CQRS.Commands;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.UsageTracking;
using Squidex.Pipeline;
namespace Squidex.Config.Domain
{
public static class InfrastructureServices
{
public static void AddMyInfrastructureServices(this IServiceCollection services, IConfiguration config)
{
if (config.GetValue<bool>("logging:human"))
{
services.AddSingleton(c => new Func<IObjectWriter>(() => new JsonLogWriter(Formatting.Indented, true)));
}
else
{
services.AddSingleton(c => new Func<IObjectWriter>(() => new JsonLogWriter()));
}
var loggingFile = config.GetValue<string>("logging:file");
if (!string.IsNullOrWhiteSpace(loggingFile))
{
services.AddSingleton(new FileChannel(loggingFile))
.As<ILogChannel>()
.As<IExternalSystem>();
}
services.AddSingleton(c => new ApplicationInfoLogAppender(typeof(Startup).Assembly, Guid.NewGuid()))
.As<ILogAppender>();
services.AddSingleton<ActionContextLogAppender>()
.As<ILogAppender>();
services.AddSingleton<TimestampLogAppender>()
.As<ILogAppender>();
services.AddSingleton<DebugLogChannel>()
.As<ILogChannel>();
services.AddSingleton<ConsoleLogChannel>()
.As<ILogChannel>();
services.AddSingleton<SemanticLog>()
.As<ISemanticLog>();
services.AddSingleton(SystemClock.Instance)
.As<IClock>();
services.AddSingleton<BackgroundUsageTracker>()
.As<IUsageTracker>();
services.AddSingleton<HttpContextAccessor>()
.As<IHttpContextAccessor>();
services.AddSingleton<ActionContextAccessor>()
.As<IActionContextAccessor>();
services.AddSingleton<DefaultDomainObjectRepository>()
.As<IDomainObjectRepository>();
services.AddSingleton<DefaultDomainObjectFactory>()
.As<IDomainObjectFactory>();
services.AddSingleton<AggregateHandler>()
.As<IAggregateHandler>();
services.AddSingleton<InMemoryCommandBus>()
.As<ICommandBus>();
services.AddSingleton<DefaultEventNotifier>()
.As<IEventNotifier>();
services.AddSingleton<DefaultStreamNameResolver>()
.As<IStreamNameResolver>();
services.AddSingleton<ImageSharpAssetThumbnailGenerator>()
.As<IAssetThumbnailGenerator>();
services.AddSingleton<InvalidatingMemoryCache>()
.As<IMemoryCache>();
services.AddSingleton<DefaultRemoteActorChannel>()
.As<IRemoteActorChannel>();
services.AddSingleton<RemoteActors>()
.As<IActors>();
services.AddSingleton<EventConsumerCleaner>();
services.AddSingleton<EventDataFormatter>();
}
}
}

69
src/Squidex/Config/Domain/PubSubModule.cs

@ -1,69 +0,0 @@
// ==========================================================================
// PubSubModule.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Autofac;
using Autofac.Core;
using Microsoft.Extensions.Configuration;
using Squidex.Infrastructure;
using StackExchange.Redis;
namespace Squidex.Config.Domain
{
public sealed class PubSubModule : Module
{
private const string RedisRegistration = "PubSubRedis";
private IConfiguration Configuration { get; }
public PubSubModule(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void Load(ContainerBuilder builder)
{
var pubSubType = Configuration.GetValue<string>("pubSub:type");
if (string.IsNullOrWhiteSpace(pubSubType))
{
throw new ConfigurationException("Configure the PubSub type with 'pubSub:type'.");
}
if (string.Equals(pubSubType, "Redis", StringComparison.OrdinalIgnoreCase))
{
var configuration = Configuration.GetValue<string>("pubsub:redis:configuration");
if (string.IsNullOrWhiteSpace(configuration))
{
throw new ConfigurationException("Configure PubSub Redis configuration with 'pubSub:redis:configuration'.");
}
builder.Register(c => Singletons<IConnectionMultiplexer>.GetOrAddLazy(configuration, s => ConnectionMultiplexer.Connect(s)))
.Named<Lazy<IConnectionMultiplexer>>(RedisRegistration)
.SingleInstance();
builder.RegisterType<RedisPubSub>()
.WithParameter(ResolvedParameter.ForNamed<Lazy<IConnectionMultiplexer>>(RedisRegistration))
.As<IPubSub>()
.As<IExternalSystem>()
.SingleInstance();
}
else if (string.Equals(pubSubType, "InMemory", StringComparison.OrdinalIgnoreCase))
{
builder.RegisterType<InMemoryPubSub>()
.As<IPubSub>()
.SingleInstance();
}
else
{
throw new ConfigurationException($"Unsupported value '{pubSubType}' for 'pubSub:type', supported: Redis, InMemory.");
}
}
}
}

41
src/Squidex/Config/Domain/PubSubServices.cs

@ -0,0 +1,41 @@
// ==========================================================================
// PubSubServices.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Log;
using StackExchange.Redis;
namespace Squidex.Config.Domain
{
public static class PubSubServices
{
public static void AddMyPubSubServices(this IServiceCollection services, IConfiguration config)
{
config.ConfigureByOption("pubSub:type", new Options
{
["InMemory"] = () =>
{
services.AddSingleton<InMemoryPubSub>()
.As<IPubSub>();
},
["Redis"] = () =>
{
var configuration = config.GetRequiredValue("pubsub:redis:configuration");
var redis = Singletons<IConnectionMultiplexer>.GetOrAddLazy(configuration, s => ConnectionMultiplexer.Connect(s));
services.AddSingleton(c => new RedisPubSub(redis, c.GetRequiredService<ISemanticLog>()))
.As<IPubSub>()
.As<IExternalSystem>();
}
});
}
}
}

139
src/Squidex/Config/Domain/ReadModule.cs

@ -1,139 +0,0 @@
// ==========================================================================
// ReadModule.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using Autofac;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Squidex.Domain.Apps.Core.HandleRules;
using Squidex.Domain.Apps.Core.HandleRules.ActionHandlers;
using Squidex.Domain.Apps.Core.HandleRules.Triggers;
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Apps.Services;
using Squidex.Domain.Apps.Read.Apps.Services.Implementations;
using Squidex.Domain.Apps.Read.Contents;
using Squidex.Domain.Apps.Read.Contents.Edm;
using Squidex.Domain.Apps.Read.Contents.GraphQL;
using Squidex.Domain.Apps.Read.History;
using Squidex.Domain.Apps.Read.Rules;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Domain.Apps.Read.Schemas.Services;
using Squidex.Domain.Apps.Read.Schemas.Services.Implementations;
using Squidex.Domain.Users;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Assets;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Pipeline;
namespace Squidex.Config.Domain
{
public sealed class ReadModule : Module
{
private IConfiguration Configuration { get; }
public ReadModule(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void Load(ContainerBuilder builder)
{
builder.Register(c => c.Resolve<IOptions<MyUsageOptions>>().Value?.Plans ?? Enumerable.Empty<ConfigAppLimitsPlan>())
.As<IEnumerable<ConfigAppLimitsPlan>>()
.AsSelf()
.SingleInstance();
builder.Register(c => new GraphQLUrlGenerator(
c.Resolve<IOptions<MyUrlsOptions>>(),
c.Resolve<IAssetStore>(),
Configuration.GetValue<bool>("assetStore:exposeSourceUrl")))
.As<IGraphQLUrlGenerator>()
.AsSelf()
.SingleInstance();
builder.RegisterType<CachingGraphQLService>()
.As<IGraphQLService>()
.AsSelf()
.InstancePerDependency();
builder.RegisterType<ContentQueryService>()
.As<IContentQueryService>()
.AsSelf()
.SingleInstance();
builder.RegisterType<CachingAppProvider>()
.As<IAppProvider>()
.AsSelf()
.SingleInstance();
builder.RegisterType<ConfigAppPlansProvider>()
.As<IAppPlansProvider>()
.AsSelf()
.SingleInstance();
builder.RegisterType<CachingSchemaProvider>()
.As<ISchemaProvider>()
.AsSelf()
.SingleInstance();
builder.RegisterType<AssetUserPictureStore>()
.As<IUserPictureStore>()
.AsSelf()
.SingleInstance();
builder.RegisterType<AppHistoryEventsCreator>()
.As<IHistoryEventsCreator>()
.AsSelf()
.SingleInstance();
builder.RegisterType<ContentHistoryEventsCreator>()
.As<IHistoryEventsCreator>()
.AsSelf()
.SingleInstance();
builder.RegisterType<SchemaHistoryEventsCreator>()
.As<IHistoryEventsCreator>()
.AsSelf()
.SingleInstance();
builder.RegisterType<NoopAppPlanBillingManager>()
.As<IAppPlanBillingManager>()
.AsSelf()
.InstancePerDependency();
builder.RegisterType<RuleDequeuer>()
.As<IExternalSystem>()
.AsSelf()
.InstancePerDependency();
builder.RegisterType<RuleEnqueuer>()
.As<IEventConsumer>()
.AsSelf()
.InstancePerDependency();
builder.RegisterType<ContentChangedTriggerHandler>()
.As<IRuleTriggerHandler>()
.AsSelf()
.SingleInstance();
builder.RegisterType<WebhookActionHandler>()
.As<IRuleActionHandler>()
.AsSelf()
.SingleInstance();
builder.RegisterType<RuleService>()
.AsSelf()
.SingleInstance();
builder.RegisterType<EdmModelBuilder>()
.AsSelf()
.SingleInstance();
}
}
}

114
src/Squidex/Config/Domain/ReadServices.cs

@ -0,0 +1,114 @@
// ==========================================================================
// ReadServices.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Squidex.Domain.Apps.Core.HandleRules;
using Squidex.Domain.Apps.Core.HandleRules.ActionHandlers;
using Squidex.Domain.Apps.Core.HandleRules.Triggers;
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Apps.Services;
using Squidex.Domain.Apps.Read.Apps.Services.Implementations;
using Squidex.Domain.Apps.Read.Assets;
using Squidex.Domain.Apps.Read.Contents;
using Squidex.Domain.Apps.Read.Contents.Edm;
using Squidex.Domain.Apps.Read.Contents.GraphQL;
using Squidex.Domain.Apps.Read.History;
using Squidex.Domain.Apps.Read.Rules;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Domain.Apps.Read.Schemas.Services;
using Squidex.Domain.Apps.Read.Schemas.Services.Implementations;
using Squidex.Domain.Users;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Assets;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Pipeline;
namespace Squidex.Config.Domain
{
public static class ReadServices
{
public static void AddMyReadServices(this IServiceCollection services, IConfiguration config)
{
var exposeSourceUrl = config.GetOptionalValue("assetStore:exposeSourceUrl", true);
services.AddSingleton(c => new GraphQLUrlGenerator(
c.GetRequiredService<IOptions<MyUrlsOptions>>(),
c.GetRequiredService<IAssetStore>(),
exposeSourceUrl))
.As<IGraphQLUrlGenerator>();
services.AddSingleton(c => c.GetService<IOptions<MyUsageOptions>>()?.Value?.Plans.OrEmpty())
.As<IEnumerable<ConfigAppLimitsPlan>>();
services.AddSingleton<CachingGraphQLService>()
.As<IGraphQLService>();
services.AddSingleton<ContentQueryService>()
.As<IContentQueryService>();
services.AddSingleton<CachingAppProvider>()
.As<IAppProvider>();
services.AddSingleton<ConfigAppPlansProvider>()
.As<IAppPlansProvider>();
services.AddSingleton<CachingSchemaProvider>()
.As<ISchemaProvider>();
services.AddSingleton<AssetUserPictureStore>()
.As<IUserPictureStore>();
services.AddSingleton<AppHistoryEventsCreator>()
.As<IHistoryEventsCreator>();
services.AddSingleton<ContentHistoryEventsCreator>()
.As<IHistoryEventsCreator>();
services.AddSingleton<SchemaHistoryEventsCreator>()
.As<IHistoryEventsCreator>();
services.AddSingleton<NoopAppPlanBillingManager>()
.As<IAppPlanBillingManager>();
services.AddSingleton<RuleDequeuer>()
.As<IExternalSystem>();
services.AddSingleton<RuleEnqueuer>()
.As<IEventConsumer>();
services.AddSingleton<ContentChangedTriggerHandler>()
.As<IRuleTriggerHandler>();
services.AddSingleton<WebhookActionHandler>()
.As<IRuleActionHandler>();
services.AddSingleton(c => new CompoundEventConsumer(c.GetServices<IAssetEventConsumer>().ToArray()))
.As<IEventConsumer>();
services.AddSingleton(c =>
new CompoundEventConsumer(
c.GetServices<IAppEventConsumer>().OfType<IEventConsumer>()
.Concat(c.GetRequiredService<CachingAppProvider>()).ToArray()))
.As<IEventConsumer>();
services.AddSingleton(c =>
new CompoundEventConsumer(
c.GetServices<ISchemaEventConsumer>().OfType<IEventConsumer>()
.Concat(c.GetRequiredService<CachingGraphQLService>())
.Concat(c.GetRequiredService<CachingSchemaProvider>()).ToArray()))
.As<IEventConsumer>();
services.AddSingleton<RuleService>();
services.AddSingleton<EdmModelBuilder>();
}
}
}

8
src/Squidex/Config/Domain/Serializers.cs → src/Squidex/Config/Domain/SerializationServices.cs

@ -1,5 +1,5 @@
// ==========================================================================
// Serializers.cs
// SerializationServices.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
@ -23,7 +23,7 @@ using Squidex.Infrastructure.MongoDb;
namespace Squidex.Config.Domain
{
public static class Serializers
public static class SerializationServices
{
private static readonly TypeNameRegistry TypeNameRegistry = new TypeNameRegistry();
private static readonly JsonSerializerSettings SerializerSettings = new JsonSerializerSettings();
@ -61,7 +61,7 @@ namespace Squidex.Config.Domain
return settings;
}
static Serializers()
static SerializationServices()
{
TypeNameRegistry.MapUnmapped(typeof(SquidexCoreModel).Assembly);
TypeNameRegistry.MapUnmapped(typeof(SquidexEvents).Assembly);
@ -72,7 +72,7 @@ namespace Squidex.Config.Domain
BsonJsonConvention.Register(JsonSerializer.Create(SerializerSettings));
}
public static IServiceCollection AddMyEventFormatter(this IServiceCollection services)
public static IServiceCollection AddMySerializers(this IServiceCollection services)
{
services.AddSingleton(t => TypeNameRegistry);
services.AddSingleton(t => FieldRegistry);

44
src/Squidex/Config/Domain/StoreModule.cs

@ -1,44 +0,0 @@
// ==========================================================================
// StoreModule.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Autofac;
using Microsoft.Extensions.Configuration;
using Squidex.Infrastructure;
namespace Squidex.Config.Domain
{
public class StoreModule : Module
{
private IConfiguration Configuration { get; }
public StoreModule(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void Load(ContainerBuilder builder)
{
var storeType = Configuration.GetValue<string>("store:type");
if (string.IsNullOrWhiteSpace(storeType))
{
throw new ConfigurationException("Configure the Store type with 'store:type'.");
}
if (string.Equals(storeType, "MongoDB", StringComparison.OrdinalIgnoreCase))
{
builder.RegisterModule(new StoreMongoDbModule(Configuration));
}
else
{
throw new ConfigurationException($"Unsupported value '{storeType}' for 'stores:type', supported: MongoDb.");
}
}
}
}

208
src/Squidex/Config/Domain/StoreMongoDbModule.cs

@ -1,208 +0,0 @@
// ==========================================================================
// StoreMongoDbModule.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Autofac;
using Autofac.Core;
using IdentityServer4.Stores;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using MongoDB.Driver;
using Squidex.Domain.Apps.Read.Apps.Repositories;
using Squidex.Domain.Apps.Read.Apps.Services.Implementations;
using Squidex.Domain.Apps.Read.Assets.Repositories;
using Squidex.Domain.Apps.Read.Contents.GraphQL;
using Squidex.Domain.Apps.Read.Contents.Repositories;
using Squidex.Domain.Apps.Read.History.Repositories;
using Squidex.Domain.Apps.Read.MongoDb.Apps;
using Squidex.Domain.Apps.Read.MongoDb.Assets;
using Squidex.Domain.Apps.Read.MongoDb.Contents;
using Squidex.Domain.Apps.Read.MongoDb.History;
using Squidex.Domain.Apps.Read.MongoDb.Rules;
using Squidex.Domain.Apps.Read.MongoDb.Schemas;
using Squidex.Domain.Apps.Read.Rules.Repositories;
using Squidex.Domain.Apps.Read.Schemas.Repositories;
using Squidex.Domain.Apps.Read.Schemas.Services.Implementations;
using Squidex.Domain.Users;
using Squidex.Domain.Users.MongoDb;
using Squidex.Domain.Users.MongoDb.Infrastructure;
using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.UsageTracking;
using Squidex.Shared.Users;
namespace Squidex.Config.Domain
{
public class StoreMongoDbModule : Module
{
private const string MongoClientRegistration = "StoreMongoClient";
private const string MongoDatabaseRegistration = "StoreMongoDatabaseName";
private const string MongoContentDatabaseRegistration = "StoreMongoDatabaseNameContent";
private IConfiguration Configuration { get; }
public StoreMongoDbModule(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void Load(ContainerBuilder builder)
{
var configuration = Configuration.GetValue<string>("store:mongoDb:configuration");
if (string.IsNullOrWhiteSpace(configuration))
{
throw new ConfigurationException("Configure the Store MongoDb configuration with 'store:mongoDb:configuration'.");
}
var database = Configuration.GetValue<string>("store:mongoDb:database");
if (string.IsNullOrWhiteSpace(database))
{
throw new ConfigurationException("Configure the Store MongoDb database with 'store:mongoDb:database'.");
}
var contentDatabase = Configuration.GetValue<string>("store:mongoDb:contentDatabase");
if (string.IsNullOrWhiteSpace(contentDatabase))
{
contentDatabase = database;
}
builder.Register(c => Singletons<IMongoClient>.GetOrAdd(configuration, s => new MongoClient(s)))
.Named<IMongoClient>(MongoClientRegistration)
.SingleInstance();
builder.Register(c => c.ResolveNamed<IMongoClient>(MongoClientRegistration).GetDatabase(database))
.Named<IMongoDatabase>(MongoDatabaseRegistration)
.SingleInstance();
builder.Register(c => c.ResolveNamed<IMongoClient>(MongoClientRegistration).GetDatabase(contentDatabase))
.Named<IMongoDatabase>(MongoContentDatabaseRegistration)
.SingleInstance();
builder.RegisterType<MongoUserStore>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IUserStore<IUser>>()
.As<IUserFactory>()
.As<IUserResolver>()
.AsSelf()
.SingleInstance();
builder.RegisterType<MongoRoleStore>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IRoleStore<IRole>>()
.As<IRoleFactory>()
.AsSelf()
.SingleInstance();
builder.RegisterType<MongoPersistedGrantStore>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IPersistedGrantStore>()
.As<IExternalSystem>()
.AsSelf()
.SingleInstance();
builder.RegisterType<MongoUsageStore>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IUsageStore>()
.As<IExternalSystem>()
.AsSelf()
.SingleInstance();
builder.RegisterType<MongoHistoryEventRepository>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IHistoryEventRepository>()
.As<IEventConsumer>()
.As<IExternalSystem>()
.AsSelf()
.SingleInstance();
builder.RegisterType<MongoEventConsumerInfoRepository>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IEventConsumerInfoRepository>()
.As<IExternalSystem>()
.AsSelf()
.SingleInstance();
builder.RegisterType<MongoContentRepository>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoContentDatabaseRegistration))
.As<IContentRepository>()
.As<IEventConsumer>()
.AsSelf()
.SingleInstance();
builder.RegisterType<MongoRuleEventRepository>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IRuleEventRepository>()
.As<IExternalSystem>()
.AsSelf()
.SingleInstance();
builder.RegisterType<MongoAppRepository>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IAppRepository>()
.As<IExternalSystem>()
.AsSelf()
.SingleInstance();
builder.RegisterType<MongoSchemaRepository>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<ISchemaRepository>()
.As<IExternalSystem>()
.AsSelf()
.SingleInstance();
builder.RegisterType<MongoAssetStatsRepository>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IAssetStatsRepository>()
.As<IExternalSystem>()
.AsSelf()
.SingleInstance();
builder.RegisterType<MongoAssetRepository>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IAssetRepository>()
.As<IExternalSystem>()
.AsSelf()
.SingleInstance();
builder.RegisterType<MongoRuleRepository>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IRuleRepository>()
.As<IEventConsumer>()
.As<IExternalSystem>()
.AsSelf()
.SingleInstance();
builder.Register(c =>
new CompoundEventConsumer(
c.Resolve<MongoAssetRepository>(),
c.Resolve<MongoAssetStatsRepository>()))
.As<IEventConsumer>()
.AsSelf()
.SingleInstance();
builder.Register(c =>
new CompoundEventConsumer(
c.Resolve<MongoSchemaRepository>(),
c.Resolve<CachingGraphQLService>(),
c.Resolve<CachingSchemaProvider>()))
.As<IEventConsumer>()
.AsSelf()
.SingleInstance();
builder.Register(c =>
new CompoundEventConsumer(
c.Resolve<MongoAppRepository>(),
c.Resolve<CachingAppProvider>()))
.As<IEventConsumer>()
.AsSelf()
.SingleInstance();
}
}
}

122
src/Squidex/Config/Domain/StoreServices.cs

@ -0,0 +1,122 @@
// ==========================================================================
// StoreServices.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using IdentityServer4.Stores;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using MongoDB.Driver;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Apps.Repositories;
using Squidex.Domain.Apps.Read.Assets;
using Squidex.Domain.Apps.Read.Assets.Repositories;
using Squidex.Domain.Apps.Read.Contents.Repositories;
using Squidex.Domain.Apps.Read.History;
using Squidex.Domain.Apps.Read.History.Repositories;
using Squidex.Domain.Apps.Read.MongoDb.Apps;
using Squidex.Domain.Apps.Read.MongoDb.Assets;
using Squidex.Domain.Apps.Read.MongoDb.Contents;
using Squidex.Domain.Apps.Read.MongoDb.History;
using Squidex.Domain.Apps.Read.MongoDb.Rules;
using Squidex.Domain.Apps.Read.MongoDb.Schemas;
using Squidex.Domain.Apps.Read.Rules.Repositories;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Domain.Apps.Read.Schemas.Repositories;
using Squidex.Domain.Apps.Read.Schemas.Services;
using Squidex.Domain.Users;
using Squidex.Domain.Users.MongoDb;
using Squidex.Domain.Users.MongoDb.Infrastructure;
using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.UsageTracking;
using Squidex.Shared.Users;
namespace Squidex.Config.Domain
{
public static class StoreServices
{
public static void AddMyStoreServices(this IServiceCollection services, IConfiguration config)
{
config.ConfigureByOption("store:type", new Options
{
["MongoDB"] = () =>
{
var mongoConfiguration = config.GetRequiredValue("store:mongoDb:configuration");
var mongoDatabaseName = config.GetRequiredValue("store:mongoDb:database");
var mongoContentDatabaseName = config.GetOptionalValue("store:mongoDb:contentDatabase", mongoDatabaseName);
var mongoClient = Singletons<IMongoClient>.GetOrAdd(mongoConfiguration, s => new MongoClient(s));
var mongoDatabase = mongoClient.GetDatabase(mongoDatabaseName);
var mongoContentDatabase = mongoClient.GetDatabase(mongoContentDatabaseName);
services.AddSingleton(c => new MongoUserStore(mongoDatabase))
.As<IUserStore<IUser>>()
.As<IUserFactory>()
.As<IUserResolver>()
.As<IExternalSystem>();
services.AddSingleton(c => new MongoRoleStore(mongoDatabase))
.As<IRoleStore<IRole>>()
.As<IRoleFactory>()
.As<IExternalSystem>();
services.AddSingleton(c => new MongoPersistedGrantStore(mongoDatabase))
.As<IPersistedGrantStore>()
.As<IExternalSystem>();
services.AddSingleton(c => new MongoUsageStore(mongoDatabase))
.As<IUsageStore>()
.As<IExternalSystem>();
services.AddSingleton(c => new MongoEventConsumerInfoRepository(mongoDatabase))
.As<IEventConsumerInfoRepository>()
.As<IExternalSystem>();
services.AddSingleton(c => new MongoContentRepository(mongoContentDatabase, c.GetService<ISchemaProvider>()))
.As<IContentRepository>()
.As<IEventConsumer>();
services.AddSingleton(c => new MongoRuleEventRepository(mongoDatabase))
.As<IRuleEventRepository>()
.As<IExternalSystem>();
services.AddSingleton(c => new MongoHistoryEventRepository(mongoDatabase, c.GetServices<IHistoryEventsCreator>()))
.As<IHistoryEventRepository>()
.As<IEventConsumer>()
.As<IExternalSystem>();
services.AddSingleton(c => new MongoAppRepository(mongoDatabase))
.As<IAppRepository>()
.As<IAppEventConsumer>()
.As<IExternalSystem>();
services.AddSingleton(c => new MongoSchemaRepository(mongoDatabase, c.GetRequiredService<FieldRegistry>()))
.As<ISchemaRepository>()
.As<ISchemaEventConsumer>()
.As<IExternalSystem>();
services.AddSingleton(c => new MongoAssetStatsRepository(mongoDatabase))
.As<IAssetStatsRepository>()
.As<IAssetEventConsumer>()
.As<IExternalSystem>();
services.AddSingleton(c => new MongoAssetRepository(mongoDatabase))
.As<IAssetRepository>()
.As<IAssetEventConsumer>()
.As<IExternalSystem>();
services.AddSingleton(c => new MongoAssetRepository(mongoDatabase))
.As<IRuleRepository>()
.As<IEventConsumer>()
.As<IExternalSystem>();
}
});
}
}
}

30
src/Squidex/Config/Domain/SystemExtensions.cs

@ -0,0 +1,30 @@
// ==========================================================================
// SystemExtensions.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Infrastructure;
namespace Squidex.Config.Domain
{
public static class SystemExtensions
{
public static IApplicationBuilder TestExternalSystems(this IApplicationBuilder app)
{
var systems = app.ApplicationServices.GetRequiredService<IEnumerable<IExternalSystem>>();
foreach (var system in systems)
{
system.Connect();
}
return app;
}
}
}

113
src/Squidex/Config/Domain/WriteModule.cs

@ -1,113 +0,0 @@
// ==========================================================================
// WriteModule.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Autofac;
using Microsoft.Extensions.Configuration;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Write.Apps;
using Squidex.Domain.Apps.Write.Assets;
using Squidex.Domain.Apps.Write.Contents;
using Squidex.Domain.Apps.Write.Rules;
using Squidex.Domain.Apps.Write.Schemas;
using Squidex.Domain.Users;
using Squidex.Infrastructure.CQRS.Commands;
using Squidex.Pipeline.CommandMiddlewares;
namespace Squidex.Config.Domain
{
public class WriteModule : Module
{
private IConfiguration Configuration { get; }
public WriteModule(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<NoopUserEvents>()
.As<IUserEvents>()
.SingleInstance();
builder.RegisterType<JintScriptEngine>()
.As<IScriptEngine>()
.SingleInstance();
builder.RegisterType<ContentVersionLoader>()
.As<IContentVersionLoader>()
.SingleInstance();
builder.RegisterType<ETagCommandMiddleware>()
.As<ICommandMiddleware>()
.SingleInstance();
builder.RegisterType<EnrichWithTimestampCommandMiddleware>()
.As<ICommandMiddleware>()
.SingleInstance();
builder.RegisterType<EnrichWithActorCommandMiddleware>()
.As<ICommandMiddleware>()
.SingleInstance();
builder.RegisterType<EnrichWithAppIdCommandMiddleware>()
.As<ICommandMiddleware>()
.SingleInstance();
builder.RegisterType<EnrichWithSchemaIdCommandMiddleware>()
.As<ICommandMiddleware>()
.SingleInstance();
builder.RegisterType<AppCommandMiddleware>()
.As<ICommandMiddleware>()
.SingleInstance();
builder.RegisterType<AssetCommandMiddleware>()
.As<ICommandMiddleware>()
.SingleInstance();
builder.RegisterType<ContentCommandMiddleware>()
.As<ICommandMiddleware>()
.SingleInstance();
builder.RegisterType<SchemaCommandMiddleware>()
.As<ICommandMiddleware>()
.SingleInstance();
builder.RegisterType<RuleCommandMiddleware>()
.As<ICommandMiddleware>()
.SingleInstance();
builder.Register<DomainObjectFactoryFunction<AppDomainObject>>(c => (id => new AppDomainObject(id, -1)))
.AsSelf()
.SingleInstance();
builder.Register<DomainObjectFactoryFunction<AssetDomainObject>>(c => (id => new AssetDomainObject(id, -1)))
.AsSelf()
.SingleInstance();
builder.Register<DomainObjectFactoryFunction<ContentDomainObject>>(c => (id => new ContentDomainObject(id, -1)))
.AsSelf()
.SingleInstance();
builder.Register<DomainObjectFactoryFunction<RuleDomainObject>>(c => (id => new RuleDomainObject(id, -1)))
.AsSelf()
.SingleInstance();
builder.Register<DomainObjectFactoryFunction<SchemaDomainObject>>(c =>
{
var fieldRegistry = c.Resolve<FieldRegistry>();
return id => new SchemaDomainObject(id, -1, fieldRegistry);
})
.AsSelf()
.SingleInstance();
}
}
}

79
src/Squidex/Config/Domain/WriteServices.cs

@ -0,0 +1,79 @@
// ==========================================================================
// WriteServices.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Microsoft.Extensions.DependencyInjection;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Write.Apps;
using Squidex.Domain.Apps.Write.Assets;
using Squidex.Domain.Apps.Write.Contents;
using Squidex.Domain.Apps.Write.Rules;
using Squidex.Domain.Apps.Write.Schemas;
using Squidex.Domain.Users;
using Squidex.Infrastructure.CQRS.Commands;
using Squidex.Pipeline.CommandMiddlewares;
namespace Squidex.Config.Domain
{
public static class WriteServices
{
public static void AddMyWriteServices(this IServiceCollection services)
{
services.AddSingleton<NoopUserEvents>()
.As<IUserEvents>();
services.AddSingleton<JintScriptEngine>()
.As<IScriptEngine>();
services.AddSingleton<ContentVersionLoader>()
.As<IContentVersionLoader>();
services.AddSingleton<ETagCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddSingleton<EnrichWithTimestampCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddSingleton<EnrichWithActorCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddSingleton<EnrichWithAppIdCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddSingleton<EnrichWithSchemaIdCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddSingleton<AppCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddSingleton<AssetCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddSingleton<ContentCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddSingleton<SchemaCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddSingleton<RuleCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddSingleton<DomainObjectFactoryFunction<AppDomainObject>>(c => (id => new AppDomainObject(id, -1)));
services.AddSingleton<DomainObjectFactoryFunction<RuleDomainObject>>(c => (id => new RuleDomainObject(id, -1)));
services.AddSingleton<DomainObjectFactoryFunction<AssetDomainObject>>(c => (id => new AssetDomainObject(id, -1)));
services.AddSingleton<DomainObjectFactoryFunction<ContentDomainObject>>(c => (id => new ContentDomainObject(id, -1)));
services.AddSingleton<DomainObjectFactoryFunction<SchemaDomainObject>>(c =>
{
var fieldRegistry = c.GetRequiredService<FieldRegistry>();
return id => new SchemaDomainObject(id, -1, fieldRegistry);
});
}
}
}

4
src/Squidex/Config/Identity/AuthenticationUsage.cs → src/Squidex/Config/Identity/AuthenticationExtensions.cs

@ -1,5 +1,5 @@
// ==========================================================================
// AuthenticationUsage.cs
// AuthenticationExtensions.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Builder;
namespace Squidex.Config.Identity
{
public static class AuthenticationUsage
public static class AuthenticationExtensions
{
public static IApplicationBuilder UseMyAuthentication(this IApplicationBuilder app)
{

6
src/Squidex/Config/Identity/AuthenticationServices.cs

@ -16,14 +16,14 @@ namespace Squidex.Config.Identity
{
public static class AuthenticationServices
{
public static IServiceCollection AddMyAuthentication(this IServiceCollection services, IConfiguration configuration)
public static IServiceCollection AddMyAuthentication(this IServiceCollection services, IConfiguration config)
{
var identityOptions = configuration.GetSection("identity").Get<MyIdentityOptions>();
var identityOptions = config.GetSection("identity").Get<MyIdentityOptions>();
services.AddAuthentication()
.AddMyGoogleAuthentication(identityOptions)
.AddMyMicrosoftAuthentication(identityOptions)
.AddMyApiProtection(identityOptions, configuration);
.AddMyApiProtection(identityOptions, config);
return services;
}

4
src/Squidex/Config/Identity/IdentityUsage.cs → src/Squidex/Config/Identity/IdentityExtensions.cs

@ -1,5 +1,5 @@
// ==========================================================================
// IdentityUsage.cs
// IdentityExtensions.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
@ -20,7 +20,7 @@ using Squidex.Shared.Users;
namespace Squidex.Config.Identity
{
public static class IdentityUsage
public static class IdentityExtensions
{
public static IApplicationBuilder UseMyIdentityServer(this IApplicationBuilder app)
{

103
src/Squidex/Config/Identity/IdentityServerServices.cs

@ -0,0 +1,103 @@
// ==========================================================================
// IdentityServerServices.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using IdentityModel;
using IdentityServer4.Models;
using IdentityServer4.Stores;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Domain.Users;
using Squidex.Shared.Identity;
using Squidex.Shared.Users;
namespace Squidex.Config.Identity
{
public static class IdentityServerServices
{
public static IServiceCollection AddMyIdentityServer(this IServiceCollection services)
{
X509Certificate2 certificate;
var assembly = typeof(IdentityServices).GetTypeInfo().Assembly;
using (var certStream = assembly.GetManifestResourceStream("Squidex.Config.Identity.Cert.IdentityCert.pfx"))
{
var certData = new byte[certStream.Length];
certStream.Read(certData, 0, certData.Length);
certificate = new X509Certificate2(certData, "password",
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.Exportable);
}
services.AddSingleton(
GetApiResources());
services.AddSingleton(
GetIdentityResources());
services.AddSingleton<IUserClaimsPrincipalFactory<IUser>,
UserClaimsPrincipalFactoryWithEmail>();
services.AddSingleton<IClientStore,
LazyClientStore>();
services.AddSingleton<IResourceStore,
InMemoryResourcesStore>();
services.AddIdentityServer(options =>
{
options.UserInteraction.ErrorUrl = "/error/";
})
.AddAspNetIdentity<IUser>()
.AddInMemoryApiResources(GetApiResources())
.AddInMemoryIdentityResources(GetIdentityResources())
.AddSigningCredential(certificate);
return services;
}
public static IServiceCollection AddMyIdentity(this IServiceCollection services)
{
services.AddIdentity<IUser, IRole>()
.AddDefaultTokenProviders();
return services;
}
private static IEnumerable<ApiResource> GetApiResources()
{
yield return new ApiResource(Constants.ApiScope)
{
UserClaims = new List<string>
{
JwtClaimTypes.Email,
JwtClaimTypes.Role
}
};
}
private static IEnumerable<IdentityResource> GetIdentityResources()
{
yield return new IdentityResources.OpenId();
yield return new IdentityResources.Profile();
yield return new IdentityResources.Email();
yield return new IdentityResource(Constants.RoleScope,
new[]
{
JwtClaimTypes.Role
});
yield return new IdentityResource(Constants.ProfileScope,
new[]
{
SquidexClaimTypes.SquidexDisplayName,
SquidexClaimTypes.SquidexPictureUrl
});
}
}
}

130
src/Squidex/Config/Identity/IdentityServices.cs

@ -6,22 +6,11 @@
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using IdentityModel;
using IdentityServer4.Models;
using IdentityServer4.Stores;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Domain.Users;
using Squidex.Infrastructure;
using Squidex.Shared.Identity;
using Squidex.Shared.Users;
using StackExchange.Redis;
namespace Squidex.Config.Identity
@ -32,121 +21,26 @@ namespace Squidex.Config.Identity
{
var dataProtection = services.AddDataProtection().SetApplicationName("Squidex");
var keyStoreType = configuration.GetValue<string>("identity:keysStore:type");
if (string.IsNullOrWhiteSpace(keyStoreType))
{
throw new ConfigurationException("Configure KeyStore type with 'identity:keysStore:type'.");
}
if (string.Equals(keyStoreType, "Redis", StringComparison.OrdinalIgnoreCase))
configuration.ConfigureByOption("identity:keyStore:type", new Options
{
var redisConfiguration = configuration.GetValue<string>("identity:keysStore:redis:configuration");
if (string.IsNullOrWhiteSpace(redisConfiguration))
{
throw new ConfigurationException("Configure KeyStore Redis configuration with 'identity:keysStore:redis:configuration'.");
}
var connectionMultiplexer = Singletons<ConnectionMultiplexer>.GetOrAdd(redisConfiguration, s => ConnectionMultiplexer.Connect(s));
dataProtection.PersistKeysToRedis(connectionMultiplexer);
}
else if (string.Equals(keyStoreType, "Folder", StringComparison.OrdinalIgnoreCase))
{
var folderPath = configuration.GetValue<string>("identity:keysStore:folder:path");
if (string.IsNullOrWhiteSpace(folderPath))
["Redis"] = () =>
{
throw new ConfigurationException("Configure KeyStore Folder path with 'identity:keysStore:folder:path'.");
}
dataProtection.PersistKeysToFileSystem(new DirectoryInfo(folderPath));
}
else if (!string.Equals(keyStoreType, "InMemory", StringComparison.OrdinalIgnoreCase))
{
throw new ConfigurationException($"Unsupported value '{keyStoreType}' for 'identity:keysStore:type', supported: Redis, Folder, InMemory.");
}
return services;
}
public static IServiceCollection AddMyIdentityServer(this IServiceCollection services)
{
X509Certificate2 certificate;
var assembly = typeof(IdentityServices).GetTypeInfo().Assembly;
var redisConfiguration = configuration.GetRequiredValue("identity:keysStore:redis:configuration");
using (var certStream = assembly.GetManifestResourceStream("Squidex.Config.Identity.Cert.IdentityCert.pfx"))
{
var certData = new byte[certStream.Length];
certStream.Read(certData, 0, certData.Length);
certificate = new X509Certificate2(certData, "password",
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.Exportable);
}
services.AddSingleton(
GetApiResources());
services.AddSingleton(
GetIdentityResources());
services.AddSingleton<IUserClaimsPrincipalFactory<IUser>,
UserClaimsPrincipalFactoryWithEmail>();
services.AddSingleton<IClientStore,
LazyClientStore>();
services.AddSingleton<IResourceStore,
InMemoryResourcesStore>();
var connectionMultiplexer = Singletons<ConnectionMultiplexer>.GetOrAdd(redisConfiguration, s => ConnectionMultiplexer.Connect(s));
services.AddIdentityServer(options =>
dataProtection.PersistKeysToRedis(connectionMultiplexer);
},
["Folder"] = () =>
{
options.UserInteraction.ErrorUrl = "/error/";
})
.AddAspNetIdentity<IUser>()
.AddInMemoryApiResources(GetApiResources())
.AddInMemoryIdentityResources(GetIdentityResources())
.AddSigningCredential(certificate);
var folderPath = configuration.GetRequiredValue("identity:keysStore:folder:path");
return services;
}
public static IServiceCollection AddMyIdentity(this IServiceCollection services)
{
services.AddIdentity<IUser, IRole>()
.AddDefaultTokenProviders();
dataProtection.PersistKeysToFileSystem(new DirectoryInfo(folderPath));
},
["InMemory"] = () => { }
});
return services;
}
private static IEnumerable<ApiResource> GetApiResources()
{
yield return new ApiResource(Constants.ApiScope)
{
UserClaims = new List<string>
{
JwtClaimTypes.Email,
JwtClaimTypes.Role
}
};
}
private static IEnumerable<IdentityResource> GetIdentityResources()
{
yield return new IdentityResources.OpenId();
yield return new IdentityResources.Profile();
yield return new IdentityResources.Email();
yield return new IdentityResource(Constants.RoleScope,
new[]
{
JwtClaimTypes.Role
});
yield return new IdentityResource(Constants.ProfileScope,
new[]
{
SquidexClaimTypes.SquidexDisplayName,
SquidexClaimTypes.SquidexPictureUrl
});
}
}
}

21
src/Squidex/Config/Options.cs

@ -0,0 +1,21 @@
// ==========================================================================
// Options.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
namespace Squidex.Config
{
public sealed class Options : Dictionary<string, Action>
{
public Options()
: base(StringComparer.OrdinalIgnoreCase)
{
}
}
}

94
src/Squidex/Config/ServiceExtensions.cs

@ -0,0 +1,94 @@
// ==========================================================================
// ServiceExtensions.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Infrastructure;
namespace Squidex.Config
{
public static class ServiceExtensions
{
public sealed class InterfaceRegistrator<T>
{
private readonly IServiceCollection services;
public InterfaceRegistrator(IServiceCollection services)
{
this.services = services;
}
public InterfaceRegistrator<T> As<TInterface>()
{
this.services.AddSingleton(typeof(TInterface), c => c.GetRequiredService<T>());
return this;
}
}
public static InterfaceRegistrator<T> AddSingleton<T>(this IServiceCollection services, Func<IServiceProvider, T> factory)
{
services.AddSingleton(typeof(T), factory);
return new InterfaceRegistrator<T>(services);
}
public static InterfaceRegistrator<T> AddSingleton<T>(this IServiceCollection services, T instance)
{
services.AddSingleton(instance);
return new InterfaceRegistrator<T>(services);
}
public static InterfaceRegistrator<T> AddSingleton<T>(this IServiceCollection services)
{
services.AddSingleton(typeof(T));
return new InterfaceRegistrator<T>(services);
}
public static T GetOptionalValue<T>(this IConfiguration config, string path, T defaultValue = default(T))
{
var value = config.GetValue<T>(path, defaultValue);
return value;
}
public static string GetRequiredValue(this IConfiguration config, string path)
{
var value = config.GetValue<string>(path);
if (string.IsNullOrWhiteSpace(value))
{
var name = string.Join(' ', path.Split(':').Select(x => x.ToPascalCase()));
throw new ConfigurationException($"Configure the {name} with '{path}'.");
}
return value;
}
public static string ConfigureByOption(this IConfiguration config, string path, Options options)
{
var value = config.GetRequiredValue(path);
if (options.TryGetValue(value, out var action))
{
action();
}
else
{
throw new ConfigurationException($"Unsupported value '{value}' for '{path}', supported: {string.Join(' ', options.Keys)}.");
}
return value;
}
}
}

6
src/Squidex/Config/Swagger/SwaggerUsage.cs → src/Squidex/Config/Swagger/SwaggerExtensions.cs

@ -1,5 +1,5 @@
// ==========================================================================
// SwaggerUsage.cs
// SwaggerExtensions.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
@ -13,13 +13,13 @@ using NSwag.AspNetCore;
namespace Squidex.Config.Swagger
{
public static class SwaggerUsage
public static class SwaggerExtensions
{
public static void UseMySwagger(this IApplicationBuilder app)
{
var settings = app.ApplicationServices.GetService<SwaggerSettings>();
app.UseSwagger(typeof(SwaggerUsage).GetTypeInfo().Assembly, settings);
app.UseSwagger(typeof(SwaggerExtensions).GetTypeInfo().Assembly, settings);
}
}
}

2
src/Squidex/Config/Web/WebUsages.cs → src/Squidex/Config/Web/WebExtensions.cs

@ -15,7 +15,7 @@ using Squidex.Pipeline;
namespace Squidex.Config.Web
{
public static class WebUsages
public static class WebExtensions
{
public static void UseMyCors(this IApplicationBuilder app)
{

35
src/Squidex/Config/Web/WebModule.cs

@ -1,35 +0,0 @@
// ==========================================================================
// WebModule.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Autofac;
using Microsoft.Extensions.Configuration;
using Squidex.Pipeline;
namespace Squidex.Config.Web
{
public class WebModule : Module
{
private IConfiguration Configuration { get; }
public WebModule(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<AppApiFilter>()
.AsSelf()
.SingleInstance();
builder.RegisterType<FileCallbackResultExecutor>()
.AsSelf()
.SingleInstance();
}
}
}

8
src/Squidex/Config/Web/WebDependencies.cs → src/Squidex/Config/Web/WebServices.cs

@ -8,14 +8,20 @@
using Microsoft.Extensions.DependencyInjection;
using Squidex.Config.Domain;
using Squidex.Pipeline;
namespace Squidex.Config.Web
{
public static class WebDependencies
public static class WebServices
{
public static void AddMyMvc(this IServiceCollection services)
{
services.AddSingleton<AppApiFilter>();
services.AddSingleton<FileCallbackResultExecutor>();
services.AddMvc().AddMySerializers();
services.AddCors();
services.AddRouting();
}
}
}

4
src/Squidex/Config/Web/WebpackUsages.cs → src/Squidex/Config/Web/WebpackExtensions.cs

@ -1,5 +1,5 @@
// ==========================================================================
// WebpackUsages.cs
// WebpackExtensions.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
@ -11,7 +11,7 @@ using Squidex.Pipeline;
namespace Squidex.Config.Web
{
public static class WebpackUsages
public static class WebpackExtensions
{
public static IApplicationBuilder UseWebpackProxy(this IApplicationBuilder app)
{

2
src/Squidex/Squidex.csproj

@ -48,8 +48,6 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac" Version="4.6.2" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.0" />
<PackageReference Include="EventStore.ClientAPI.NetCore" Version="4.0.2-rc" />
<PackageReference Include="IdentityServer4" Version="2.0.1" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.0.0" />

50
src/Squidex/Startup.cs

@ -6,11 +6,8 @@
// All rights reserved.
// ==========================================================================
using System;
using System.IO;
using System.Linq;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
@ -50,21 +47,27 @@ namespace Squidex
Configuration = config;
}
public IServiceProvider ConfigureServices(IServiceCollection services)
public void ConfigureServices(IServiceCollection services)
{
services.AddMySwaggerSettings();
services.AddMyEventFormatter();
services.AddMyDataProtectection(Configuration);
services.AddLogging();
services.AddMemoryCache();
services.AddOptions();
services.AddMyAssetServices(Configuration);
services.AddMyAuthentication(Configuration);
services.AddMyDataProtectection(Configuration);
services.AddMyEventPublishersServices(Configuration);
services.AddMyEventStoreServices(Configuration);
services.AddMyIdentity();
services.AddMyIdentityServer();
services.AddMyInfrastructureServices(Configuration);
services.AddMyMvc();
services.AddCors();
services.AddLogging();
services.AddMemoryCache();
services.AddOptions();
services.AddRouting();
services.AddMyPubSubServices(Configuration);
services.AddMyReadServices(Configuration);
services.AddMySerializers();
services.AddMyStoreServices(Configuration);
services.AddMySwaggerSettings();
services.AddMyWriteServices();
services.Configure<MyUrlsOptions>(
Configuration.GetSection("urls"));
@ -74,27 +77,6 @@ namespace Squidex
Configuration.GetSection("ui"));
services.Configure<MyUsageOptions>(
Configuration.GetSection("usage"));
var builder = new ContainerBuilder();
builder.Populate(services);
builder.RegisterModule(new AssetStoreModule(Configuration));
builder.RegisterModule(new EventPublishersModule(Configuration));
builder.RegisterModule(new EventStoreModule(Configuration));
builder.RegisterModule(new InfrastructureModule(Configuration));
builder.RegisterModule(new PubSubModule(Configuration));
builder.RegisterModule(new ReadModule(Configuration));
builder.RegisterModule(new StoreModule(Configuration));
builder.RegisterModule(new WebModule(Configuration));
builder.RegisterModule(new WriteModule(Configuration));
var container = builder.Build();
container.Resolve<IApplicationLifetime>().ApplicationStopping.Register(() =>
{
container.Dispose();
});
return new AutofacServiceProvider(container);
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)

Loading…
Cancel
Save