Browse Source

Better orleans integration.

pull/345/head
Sebastian Stehle 7 years ago
parent
commit
897aacd66d
  1. 1
      src/Squidex.Domain.Apps.Entities/EntityMapper.cs
  2. 79
      src/Squidex/AppServices.cs
  3. 1
      src/Squidex/Config/Domain/EventStoreServices.cs
  4. 14
      src/Squidex/Config/Domain/LoggingServices.cs
  5. 87
      src/Squidex/Config/Domain/SystemExtensions.cs
  6. 27
      src/Squidex/Config/Orleans/Extensions.cs
  7. 99
      src/Squidex/Config/Orleans/OrleansServices.cs
  8. 51
      src/Squidex/Config/Orleans/SiloHost.cs
  9. 42
      src/Squidex/Config/Orleans/SiloServices.cs
  10. 190
      src/Squidex/Config/Orleans/SiloWrapper.cs
  11. 38
      src/Squidex/Config/Startup/InitializerHost.cs
  12. 31
      src/Squidex/Config/Startup/MigratorHost.cs
  13. 59
      src/Squidex/Config/Startup/SafeHostedService.cs
  14. 74
      src/Squidex/WebStartup.cs
  15. 2
      src/Squidex/app/features/content/shared/content-item.component.html
  16. 4
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts
  17. 4
      src/Squidex/app/features/schemas/pages/schema/types/string-validation.component.ts
  18. 4
      src/Squidex/app/framework/angular/modals/tooltip.component.ts
  19. 4
      src/Squidex/app/framework/angular/routers/parent-link.directive.ts
  20. 4
      src/Squidex/app/framework/angular/user-report.component.ts
  21. 4
      src/Squidex/app/shared/components/comments.component.ts
  22. 4
      src/Squidex/app/shared/components/permission.directive.ts
  23. 4
      src/Squidex/app/shell/pages/internal/internal-area.component.ts
  24. 1
      tests/Squidex.Domain.Apps.Core.Tests/Operations/EventSynchronization/AssertHelper.cs

1
src/Squidex.Domain.Apps.Entities/EntityMapper.cs

@ -6,7 +6,6 @@
// ==========================================================================
using System;
using NodaTime;
using Squidex.Domain.Apps.Events;
using Squidex.Infrastructure.EventSourcing;

79
src/Squidex/AppServices.cs

@ -1,79 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Areas.Api.Config.Swagger;
using Squidex.Areas.Api.Controllers.Contents;
using Squidex.Areas.IdentityServer.Config;
using Squidex.Config;
using Squidex.Config.Authentication;
using Squidex.Config.Domain;
using Squidex.Config.Web;
using Squidex.Domain.Apps.Entities.Assets;
using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Extensions.Actions.Twitter;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Diagnostics;
using Squidex.Pipeline;
using Squidex.Pipeline.Robots;
namespace Squidex
{
public static class AppServices
{
public static void AddAppServices(this IServiceCollection services, IConfiguration config)
{
services.AddHttpClient();
services.AddLogging();
services.AddMemoryCache();
services.AddOptions();
services.AddMyAssetServices(config);
services.AddMyAuthentication(config);
services.AddMyEntitiesServices(config);
services.AddMyEventPublishersServices(config);
services.AddMyEventStoreServices(config);
services.AddMyIdentityServer();
services.AddMyInfrastructureServices();
services.AddMyLoggingServices(config);
services.AddMyMigrationServices();
services.AddMyMvc();
services.AddMyRuleServices();
services.AddMySerializers();
services.AddMyStoreServices(config);
services.AddMySwaggerSettings();
services.AddMySubscriptionServices(config);
services.Configure<ContentOptions>(
config.GetSection("contents"));
services.Configure<AssetOptions>(
config.GetSection("assets"));
services.Configure<ReadonlyOptions>(
config.GetSection("mode"));
services.Configure<TwitterOptions>(
config.GetSection("twitter"));
services.Configure<RobotsTxtOptions>(
config.GetSection("robots"));
services.Configure<GCHealthCheckOptions>(
config.GetSection("healthz:gc"));
services.Configure<ETagOptions>(
config.GetSection("etags"));
services.Configure<MyContentsControllerOptions>(
config.GetSection("contentsController"));
services.Configure<MyUrlsOptions>(
config.GetSection("urls"));
services.Configure<MyIdentityOptions>(
config.GetSection("identity"));
services.Configure<MyUIOptions>(
config.GetSection("ui"));
services.Configure<MyUsageOptions>(
config.GetSection("usage"));
}
}
}

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

@ -37,7 +37,6 @@ namespace Squidex.Config.Domain
return new MongoEventStore(mongDatabase, c.GetRequiredService<IEventNotifier>());
})
.As<IInitializable>()
.As<IEventStore>();
},
["GetEventStore"] = () =>

14
src/Squidex/Config/Domain/LoggingServices.cs

@ -12,15 +12,10 @@ using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Infrastructure.Log;
using Squidex.Pipeline;
#pragma warning disable RECS0092 // Convert field to readonly
namespace Squidex.Config.Domain
{
public static class LoggingServices
{
private static ILogChannel console = new ConsoleLogChannel();
private static ILogChannel file;
public static void AddMyLoggingServices(this IServiceCollection services, IConfiguration config)
{
if (config.GetValue<bool>("logging:human"))
@ -38,18 +33,13 @@ namespace Squidex.Config.Domain
if (!string.IsNullOrWhiteSpace(loggingFile))
{
services.AddSingletonAs(file ?? (file = new FileChannel(loggingFile)))
services.AddSingletonAs(new FileChannel(loggingFile))
.As<ILogChannel>();
}
var useColors = config.GetValue<bool>("logging:colors");
if (console == null)
{
console = new ConsoleLogChannel(useColors);
}
services.AddSingletonAs(console)
services.AddSingletonAs(new ConsoleLogChannel(useColors))
.As<ILogChannel>();
services.AddSingletonAs(c => new ApplicationInfoLogAppender(typeof(Program).Assembly, Guid.NewGuid()))

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

@ -1,87 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Migrations;
namespace Squidex.Config.Domain
{
public static class SystemExtensions
{
public sealed class InitializeHostedService : IHostedService
{
private readonly IEnumerable<IInitializable> targets;
private readonly IApplicationLifetime lifetime;
private readonly ISemanticLog log;
public InitializeHostedService(IEnumerable<IInitializable> targets, IApplicationLifetime lifetime, ISemanticLog log)
{
this.targets = targets;
this.lifetime = lifetime;
this.log = log;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
try
{
foreach (var target in targets)
{
await target.InitializeAsync(cancellationToken);
log.LogInformation(w => w.WriteProperty("initializedSystem", target.GetType().Name));
}
}
catch
{
lifetime.StopApplication();
throw;
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
public sealed class MigratorHostedService : IHostedService
{
private readonly IApplicationLifetime lifetime;
private readonly Migrator migrator;
public MigratorHostedService(IApplicationLifetime lifetime, Migrator migrator)
{
this.lifetime = lifetime;
this.migrator = migrator;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
try
{
await migrator.MigrateAsync();
}
catch
{
lifetime.StopApplication();
throw;
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
}
}

27
src/Squidex/Config/Orleans/Extensions.cs

@ -5,9 +5,14 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Orleans;
using Orleans.ApplicationParts;
using Orleans.Configuration;
using Orleans.Hosting;
using OrleansDashboard;
using OrleansDashboard.Client;
using OrleansDashboard.Metrics;
using Squidex.Domain.Apps.Entities;
using Squidex.Infrastructure;
@ -26,5 +31,27 @@ namespace Squidex.Config.Orleans
options.ClusterId = Constants.OrleansClusterId;
options.ServiceId = Constants.OrleansClusterId;
}
public static ISiloHostBuilder UseDashboardEx(this ISiloHostBuilder builder, Action<DashboardOptions> configurator = null)
{
builder.AddStartupTask<Dashboard>();
builder.ConfigureApplicationParts(appParts =>
appParts
.AddFrameworkPart(typeof(Dashboard).Assembly)
.AddFrameworkPart(typeof(DashboardClient).Assembly));
builder.ConfigureServices(services =>
{
services.AddDashboard(options =>
{
options.HostSelf = false;
});
});
builder.AddIncomingGrainCallFilter<GrainProfiler>();
return builder;
}
}
}

99
src/Squidex/Config/Orleans/OrleansServices.cs

@ -1,34 +1,113 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Net;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Orleans;
using Orleans.Configuration;
using Orleans.Hosting;
using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Domain.Apps.Entities.Rules;
using Squidex.Domain.Apps.Entities.Rules.UsageTracking;
using Squidex.Infrastructure.EventSourcing.Grains;
using Squidex.Infrastructure.Orleans;
namespace Squidex.Config.Orleans
{
public static class OrleansServices
{
public static void AddOrleansSilo(this IServiceCollection services)
public static IServiceProvider AddAndBuildOrleans(this IServiceCollection services, IConfiguration config)
{
services.AddSingletonAs<SiloWrapper>()
.As<IHostedService>()
.AsSelf();
services.Configure<ClusterOptions>(options =>
{
options.Configure();
});
services.Configure<ProcessExitHandlingOptions>(options =>
{
options.FastKillOnProcessExit = false;
});
services.AddServicesForSelfHostedDashboard(null, options =>
{
options.HideTrace = true;
});
services.AddSingletonAs(c => c.GetRequiredService<IClusterClient>())
.As<IClusterClient>();
services.AddHostedService<SiloHost>();
var hostBuilder = new SiloHostBuilder()
.UseDashboardEx()
.EnableDirectClient()
.AddIncomingGrainCallFilter<LocalCacheFilter>()
.AddStartupTask<Bootstrap<IContentSchedulerGrain>>()
.AddStartupTask<Bootstrap<IEventConsumerManagerGrain>>()
.AddStartupTask<Bootstrap<IRuleDequeuerGrain>>()
.AddStartupTask<Bootstrap<IUsageTrackerGrain>>()
.ConfigureApplicationParts(builder =>
{
builder.AddMyParts();
});
config.ConfigureByOption("orleans:clustering", new Options
{
["MongoDB"] = () =>
{
hostBuilder.ConfigureEndpoints(Dns.GetHostName(), 11111, 40000, listenOnAnyHostAddress: true);
var mongoConfiguration = config.GetRequiredValue("store:mongoDb:configuration");
var mongoDatabaseName = config.GetRequiredValue("store:mongoDb:database");
hostBuilder.UseMongoDBClustering(options =>
{
options.ConnectionString = mongoConfiguration;
options.CollectionPrefix = "Orleans_";
options.DatabaseName = mongoDatabaseName;
});
},
["Development"] = () =>
{
hostBuilder.UseLocalhostClustering(gatewayPort: 40000, serviceId: Constants.OrleansClusterId, clusterId: Constants.OrleansClusterId);
hostBuilder.Configure<ClusterMembershipOptions>(options => options.ExpectedClusterSize = 1);
}
});
config.ConfigureByOption("store:type", new Options
{
["MongoDB"] = () =>
{
var mongoConfiguration = config.GetRequiredValue("store:mongoDb:configuration");
var mongoDatabaseName = config.GetRequiredValue("store:mongoDb:database");
hostBuilder.UseMongoDBReminders(options =>
{
options.ConnectionString = mongoConfiguration;
options.CollectionPrefix = "Orleans_";
options.DatabaseName = mongoDatabaseName;
});
}
});
IServiceProvider provider = null;
hostBuilder.UseServiceProviderFactory((siloServices) =>
{
foreach (var descriptor in services)
{
siloServices.Add(descriptor);
}
provider = siloServices.BuildServiceProvider();
return provider;
}).Build();
services.AddSingletonAs(c => c.GetRequiredService<SiloWrapper>().Client)
.As<IGrainFactory>();
return provider;
}
}
}

51
src/Squidex/Config/Orleans/SiloHost.cs

@ -0,0 +1,51 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Orleans.Hosting;
using Squidex.Config.Startup;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Log;
namespace Squidex.Config.Orleans
{
public sealed class SiloHost : SafeHostedService
{
private readonly ISiloHost silo;
public SiloHost(ISiloHost silo, ISemanticLog log, IApplicationLifetime lifetime)
: base(lifetime, log)
{
this.silo = silo;
}
protected override async Task StartAsync(ISemanticLog log, CancellationToken ct)
{
var watch = ValueStopwatch.StartNew();
try
{
await silo.StartAsync(ct);
}
finally
{
var elapsedMs = watch.Stop();
log.LogInformation(w => w
.WriteProperty("message", "Silo started")
.WriteProperty("elapsedMs", elapsedMs));
}
}
protected override async Task StopAsync(ISemanticLog log, CancellationToken ct)
{
await silo.StopAsync();
}
}
}

42
src/Squidex/Config/Orleans/SiloServices.cs

@ -1,42 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Orleans.Hosting;
namespace Squidex.Config.Orleans
{
public static class SiloServices
{
public static void AddAppSiloServices(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");
services.AddMongoDBMembershipTable(options =>
{
options.ConnectionString = mongoConfiguration;
options.CollectionPrefix = "Orleans_";
options.DatabaseName = mongoDatabaseName;
});
services.AddMongoDBReminders(options =>
{
options.ConnectionString = mongoConfiguration;
options.CollectionPrefix = "Orleans_";
options.DatabaseName = mongoDatabaseName;
});
}
});
}
}
}

190
src/Squidex/Config/Orleans/SiloWrapper.cs

@ -1,190 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Orleans;
using Orleans.Configuration;
using Orleans.Hosting;
using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Domain.Apps.Entities.Rules;
using Squidex.Domain.Apps.Entities.Rules.UsageTracking;
using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing.Grains;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Log.Adapter;
using Squidex.Infrastructure.Orleans;
namespace Squidex.Config.Orleans
{
public sealed class SiloWrapper : IHostedService
{
private readonly Lazy<ISiloHost> lazySilo;
private readonly ISemanticLog log;
private readonly IApplicationLifetime lifetime;
private bool isStopping;
internal sealed class Source : IConfigurationSource
{
private readonly IConfigurationProvider configurationProvider;
public Source(IConfigurationProvider configurationProvider)
{
this.configurationProvider = configurationProvider;
}
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return configurationProvider;
}
}
public IClusterClient Client
{
get { return lazySilo.Value.Services.GetRequiredService<IClusterClient>(); }
}
public SiloWrapper(IConfiguration config, ISemanticLog log, IApplicationLifetime lifetime)
{
this.lifetime = lifetime;
this.log = log;
lazySilo = new Lazy<ISiloHost>(() =>
{
var hostBuilder = new SiloHostBuilder()
.UseDashboard(options => options.HostSelf = false)
.EnableDirectClient()
.AddIncomingGrainCallFilter<LocalCacheFilter>()
.AddStartupTask<InitializerStartup>()
.AddStartupTask<Bootstrap<IContentSchedulerGrain>>()
.AddStartupTask<Bootstrap<IEventConsumerManagerGrain>>()
.AddStartupTask<Bootstrap<IRuleDequeuerGrain>>()
.AddStartupTask<Bootstrap<IUsageTrackerGrain>>()
.Configure<ClusterOptions>(options =>
{
options.Configure();
})
.ConfigureApplicationParts(builder =>
{
builder.AddMyParts();
})
.ConfigureLogging((hostingContext, builder) =>
{
builder.AddConfiguration(hostingContext.Configuration.GetSection("logging"));
builder.AddSemanticLog();
builder.AddFilter();
})
.ConfigureServices((context, services) =>
{
services.AddAppSiloServices(context.Configuration);
services.AddAppServices(context.Configuration);
services.Configure<ProcessExitHandlingOptions>(options => options.FastKillOnProcessExit = false);
})
.ConfigureAppConfiguration((hostContext, builder) =>
{
if (config is IConfigurationRoot root)
{
foreach (var provider in root.Providers)
{
builder.Add(new Source(provider));
}
}
});
config.ConfigureByOption("orleans:clustering", new Options
{
["MongoDB"] = () =>
{
hostBuilder.ConfigureEndpoints(Dns.GetHostName(), 11111, 40000, listenOnAnyHostAddress: true);
var mongoConfiguration = config.GetRequiredValue("store:mongoDb:configuration");
var mongoDatabaseName = config.GetRequiredValue("store:mongoDb:database");
hostBuilder.UseMongoDBClustering(options =>
{
options.ConnectionString = mongoConfiguration;
options.CollectionPrefix = "Orleans_";
options.DatabaseName = mongoDatabaseName;
});
},
["Development"] = () =>
{
hostBuilder.UseLocalhostClustering(gatewayPort: 40000, serviceId: Constants.OrleansClusterId, clusterId: Constants.OrleansClusterId);
hostBuilder.Configure<ClusterMembershipOptions>(options => options.ExpectedClusterSize = 1);
}
});
config.ConfigureByOption("store:type", new Options
{
["MongoDB"] = () =>
{
var mongoConfiguration = config.GetRequiredValue("store:mongoDb:configuration");
var mongoDatabaseName = config.GetRequiredValue("store:mongoDb:database");
hostBuilder.UseMongoDBReminders(options =>
{
options.ConnectionString = mongoConfiguration;
options.CollectionPrefix = "Orleans_";
options.DatabaseName = mongoDatabaseName;
});
}
});
var silo = hostBuilder.Build();
silo.Stopped.ContinueWith(x =>
{
if (!isStopping)
{
lifetime.StopApplication();
}
});
return silo;
});
}
public async Task StartAsync(CancellationToken cancellationToken)
{
var watch = ValueStopwatch.StartNew();
try
{
await lazySilo.Value.StartAsync(cancellationToken);
}
catch
{
lifetime.StopApplication();
throw;
}
finally
{
var elapsedMs = watch.Stop();
log.LogInformation(w => w
.WriteProperty("message", "Silo started")
.WriteProperty("elapsedMs", elapsedMs));
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
if (lazySilo.IsValueCreated)
{
isStopping = true;
await lazySilo.Value.StopAsync(cancellationToken);
}
}
}
}

38
src/Squidex/Config/Startup/InitializerHost.cs

@ -0,0 +1,38 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Log;
namespace Squidex.Config.Startup
{
public sealed class InitializerHost : SafeHostedService
{
private readonly IEnumerable<IInitializable> targets;
public InitializerHost(IEnumerable<IInitializable> targets, IApplicationLifetime lifetime, ISemanticLog log)
: base(lifetime, log)
{
this.targets = targets;
}
protected override async Task StartAsync(ISemanticLog log, CancellationToken ct)
{
foreach (var target in targets.Distinct())
{
await target.InitializeAsync(ct);
log.LogInformation(w => w.WriteProperty("initializedSystem", target.GetType().Name));
}
}
}
}

31
src/Squidex/Config/Startup/MigratorHost.cs

@ -0,0 +1,31 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Migrations;
namespace Squidex.Config.Startup
{
public sealed class MigratorHost : SafeHostedService
{
private readonly Migrator migrator;
public MigratorHost(Migrator migrator, IApplicationLifetime lifetime, ISemanticLog log)
: base(lifetime, log)
{
this.migrator = migrator;
}
protected override Task StartAsync(ISemanticLog log, CancellationToken ct)
{
return migrator.MigrateAsync();
}
}
}

59
src/Squidex/Config/Startup/SafeHostedService.cs

@ -0,0 +1,59 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Tasks;
namespace Squidex.Config.Startup
{
public abstract class SafeHostedService : IHostedService
{
private readonly IApplicationLifetime lifetime;
private readonly ISemanticLog log;
private bool isStarted;
protected SafeHostedService(IApplicationLifetime lifetime, ISemanticLog log)
{
this.lifetime = lifetime;
this.log = log;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
try
{
await StartAsync(log, cancellationToken);
isStarted = true;
}
catch
{
lifetime.StopApplication();
throw;
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
if (isStarted)
{
await StopAsync(log, cancellationToken);
}
}
protected abstract Task StartAsync(ISemanticLog log, CancellationToken ct);
protected virtual Task StopAsync(ISemanticLog log, CancellationToken ct)
{
return TaskHelper.Done;
}
}
}

74
src/Squidex/WebStartup.cs

@ -5,17 +5,31 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Areas.Api;
using Squidex.Areas.Api.Config.Swagger;
using Squidex.Areas.Api.Controllers.Contents;
using Squidex.Areas.Frontend;
using Squidex.Areas.IdentityServer;
using Squidex.Areas.IdentityServer.Config;
using Squidex.Areas.OrleansDashboard;
using Squidex.Areas.Portal;
using Squidex.Config;
using Squidex.Config.Authentication;
using Squidex.Config.Domain;
using Squidex.Config.Orleans;
using Squidex.Config.Startup;
using Squidex.Config.Web;
using Squidex.Domain.Apps.Entities.Assets;
using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Extensions.Actions.Twitter;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Diagnostics;
using Squidex.Pipeline;
using Squidex.Pipeline.Robots;
namespace Squidex
{
@ -28,13 +42,63 @@ namespace Squidex
this.configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddOrleansSilo();
services.AddAppServices(configuration);
var config = configuration;
services.AddHostedService<SystemExtensions.InitializeHostedService>();
services.AddHostedService<SystemExtensions.MigratorHostedService>();
services.AddHttpClient();
services.AddLogging();
services.AddMemoryCache();
services.AddOptions();
services.AddMyAssetServices(config);
services.AddMyAuthentication(config);
services.AddMyEntitiesServices(config);
services.AddMyEventPublishersServices(config);
services.AddMyEventStoreServices(config);
services.AddMyIdentityServer();
services.AddMyInfrastructureServices();
services.AddMyLoggingServices(config);
services.AddMyMigrationServices();
services.AddMyMvc();
services.AddMyRuleServices();
services.AddMySerializers();
services.AddMyStoreServices(config);
services.AddMySwaggerSettings();
services.AddMySubscriptionServices(config);
services.Configure<ContentOptions>(
config.GetSection("contents"));
services.Configure<AssetOptions>(
config.GetSection("assets"));
services.Configure<ReadonlyOptions>(
config.GetSection("mode"));
services.Configure<TwitterOptions>(
config.GetSection("twitter"));
services.Configure<RobotsTxtOptions>(
config.GetSection("robots"));
services.Configure<GCHealthCheckOptions>(
config.GetSection("healthz:gc"));
services.Configure<ETagOptions>(
config.GetSection("etags"));
services.Configure<MyContentsControllerOptions>(
config.GetSection("contentsController"));
services.Configure<MyUrlsOptions>(
config.GetSection("urls"));
services.Configure<MyIdentityOptions>(
config.GetSection("identity"));
services.Configure<MyUIOptions>(
config.GetSection("ui"));
services.Configure<MyUsageOptions>(
config.GetSection("usage"));
services.AddHostedService<InitializerHost>();
services.AddHostedService<MigratorHost>();
var provider = services.AddAndBuildOrleans(configuration);
return provider;
}
public void Configure(IApplicationBuilder app)

2
src/Squidex/app/features/content/shared/content-item.component.html

@ -16,7 +16,7 @@
</ng-container>
<ng-template #displayTemplate>
{{values[i]}}
<span class="truncate">{{values[i]}}</span>
</ng-template>
</td>

4
src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts

@ -7,7 +7,7 @@
// tslint:disable:no-shadowed-variable
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { onErrorResumeNext } from 'rxjs/operators';
@ -38,7 +38,7 @@ import {
fadeAnimation
]
})
export class SchemaPageComponent extends ResourceOwner implements OnDestroy, OnInit {
export class SchemaPageComponent extends ResourceOwner implements OnInit {
public fieldTypes = fieldTypes;
public schemaExport: any;

4
src/Squidex/app/features/schemas/pages/schema/types/string-validation.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Component, Input, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { Observable } from 'rxjs';
@ -26,7 +26,7 @@ import {
styleUrls: ['string-validation.component.scss'],
templateUrl: 'string-validation.component.html'
})
export class StringValidationComponent extends ResourceOwner implements OnDestroy, OnInit {
export class StringValidationComponent extends ResourceOwner implements OnInit {
@Input()
public editForm: FormGroup;

4
src/Squidex/app/framework/angular/modals/tooltip.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, Renderer2 } from '@angular/core';
import {
fadeAnimation,
@ -22,7 +22,7 @@ import {
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TooltipComponent extends StatefulComponent implements OnDestroy, OnInit {
export class TooltipComponent extends StatefulComponent implements OnInit {
@Input()
public target: any;

4
src/Squidex/app/framework/angular/routers/parent-link.directive.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Directive, ElementRef, HostListener, Input, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { Directive, ElementRef, HostListener, Input, OnInit, Renderer2 } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ResourceOwner } from '@app/framework/internal';
@ -13,7 +13,7 @@ import { ResourceOwner } from '@app/framework/internal';
@Directive({
selector: '[sqxParentLink]'
})
export class ParentLinkDirective extends ResourceOwner implements OnDestroy, OnInit {
export class ParentLinkDirective extends ResourceOwner implements OnInit {
private url: string;
@Input()

4
src/Squidex/app/framework/angular/user-report.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { timer } from 'rxjs';
import {
@ -18,7 +18,7 @@ import {
selector: 'sqx-user-report',
template: ''
})
export class UserReportComponent extends ResourceOwner implements OnDestroy, OnInit {
export class UserReportComponent extends ResourceOwner implements OnInit {
constructor(changeDetector: ChangeDetectorRef,
private readonly config: UserReportConfig,
private readonly resourceLoader: ResourceLoaderService

4
src/Squidex/app/shared/components/comments.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { timer } from 'rxjs';
import { onErrorResumeNext, switchMap } from 'rxjs/operators';
@ -26,7 +26,7 @@ import {
styleUrls: ['./comments.component.scss'],
templateUrl: './comments.component.html'
})
export class CommentsComponent extends ResourceOwner implements OnDestroy, OnInit {
export class CommentsComponent extends ResourceOwner implements OnInit {
public state: CommentsState;
public userId: string;

4
src/Squidex/app/shared/components/permission.directive.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectorRef, Directive, Input, OnChanges, OnDestroy, OnInit, TemplateRef, ViewContainerRef } from '@angular/core';
import { ChangeDetectorRef, Directive, Input, OnChanges, OnInit, TemplateRef, ViewContainerRef } from '@angular/core';
import {
AppDto,
@ -20,7 +20,7 @@ import {
@Directive({
selector: '[sqxPermission]'
})
export class PermissionDirective extends ResourceOwner implements OnChanges, OnInit, OnDestroy {
export class PermissionDirective extends ResourceOwner implements OnChanges, OnInit {
private viewCreated = false;
@Input('sqxPermissionApp')

4
src/Squidex/app/shell/pages/internal/internal-area.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import {
@ -24,7 +24,7 @@ import {
fadeAnimation
]
})
export class InternalAreaComponent extends ResourceOwner implements OnDestroy, OnInit {
export class InternalAreaComponent extends ResourceOwner implements OnInit {
constructor(
public readonly loadingService: LoadingService,
private readonly dialogs: DialogService,

1
tests/Squidex.Domain.Apps.Core.Tests/Operations/EventSynchronization/AssertHelper.cs

@ -8,7 +8,6 @@
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using FluentAssertions.Equivalency;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Orleans;

Loading…
Cancel
Save