Setup Elsa Server project with Features #1032

Setup Elsa Server project with Features.
This commit is contained in:
axeleron007 2021-06-18 16:22:57 +03:00
parent 48196ec65d
commit eb388caed1
14 changed files with 575 additions and 219 deletions

View file

@ -0,0 +1,14 @@
using Elsa.Attributes;
using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Activities.Console
{
[Feature("Console")]
public class ConsoleStartup
{
public void ConfigureElsa(ElsaOptionsBuilder elsa)
{
elsa.AddConsoleActivities();
}
}
}

View file

@ -0,0 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.ComponentModel;
// ReSharper disable once CheckNamespace
namespace System.Runtime.CompilerServices
{
/// <summary>
/// Reserved to be used by the compiler for tracking metadata.
/// This class should not be used by developers in source code.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
internal static class IsExternalInit
{
}
}

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\common.props" />
<Import Project="..\..\..\..\configureawait.props" />
@ -35,6 +35,11 @@
<ProjectReference Include="..\..\..\server\Elsa.Server.Api\Elsa.Server.Api.csproj" />
<ProjectReference Include="..\..\Elsa.Activities.Http\Elsa.Activities.Http.csproj" />
<ProjectReference Include="..\Elsa.Webhooks.Abstractions\Elsa.Webhooks.Abstractions.csproj" />
<ProjectReference Include="..\Elsa.Webhooks.Persistence.EntityFramework.Core\Elsa.Webhooks.Persistence.EntityFramework.Core.csproj" />
<ProjectReference Include="..\Elsa.Webhooks.Persistence.EntityFramework.MySql\Elsa.Webhooks.Persistence.EntityFramework.MySql.csproj" />
<ProjectReference Include="..\Elsa.Webhooks.Persistence.EntityFramework.PostgreSql\Elsa.Webhooks.Persistence.EntityFramework.PostgreSql.csproj" />
<ProjectReference Include="..\Elsa.Webhooks.Persistence.EntityFramework.Sqlite\Elsa.Webhooks.Persistence.EntityFramework.Sqlite.csproj" />
<ProjectReference Include="..\Elsa.Webhooks.Persistence.EntityFramework.SqlServer\Elsa.Webhooks.Persistence.EntityFramework.SqlServer.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,232 @@
using System;
using Elsa.Runtime;
using Elsa.Webhooks.Persistence.EntityFramework.Core;
using Elsa.Webhooks.Persistence.EntityFramework.Core.Services;
using Elsa.Webhooks.Persistence.EntityFramework.Core.StartupTasks;
using Elsa.Webhooks.Persistence.EntityFramework.Core.Stores;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Elsa.Activities.Webhooks.Extensions
{
public static class WebhookServiceCollectionExtensions
{
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Pooled DB Context instances is a performance optimisation which is documented in more detail at
/// https://docs.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-constant#dbcontext-pooling.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseEntityFrameworkPersistence(this WebhookOptionsBuilder webhookOptions,
Action<DbContextOptionsBuilder> configure,
bool autoRunMigrations = true) =>
webhookOptions.UseEntityFrameworkPersistence<WebhookContext>(configure, autoRunMigrations);
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Pooled DB Context instances is a performance optimisation which is documented in more detail at
/// https://docs.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-constant#dbcontext-pooling.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <typeparam name="TWebhookContext">The concrete type of <see cref="ElsaContext"/> to use.</typeparam>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseEntityFrameworkPersistence<TWebhookContext>(this WebhookOptionsBuilder webhookOptions,
Action<DbContextOptionsBuilder> configure,
bool autoRunMigrations = true) where TWebhookContext : WebhookContext =>
webhookOptions.UseEntityFrameworkPersistence<TWebhookContext>((_, builder) => configure(builder), autoRunMigrations);
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Pooled DB Context instances is a performance optimisation which is documented in more detail at
/// https://docs.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-constant#dbcontext-pooling.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback, which also provides access to a service provider</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseEntityFrameworkPersistence(this WebhookOptionsBuilder webhookOptions,
Action<IServiceProvider, DbContextOptionsBuilder> configure,
bool autoRunMigrations = true) =>
webhookOptions.UseEntityFrameworkPersistence<WebhookContext>(configure, autoRunMigrations);
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Pooled DB Context instances is a performance optimisation which is documented in more detail at
/// https://docs.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-constant#dbcontext-pooling.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback, which also provides access to a service provider</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <typeparam name="TWebhookContext">The concrete type of <see cref="ElsaContext"/> to use.</typeparam>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseEntityFrameworkPersistence<TWebhookContext>(this WebhookOptionsBuilder webhookOptions,
Action<IServiceProvider, DbContextOptionsBuilder> configure,
bool autoRunMigrations = true) where TWebhookContext : WebhookContext =>
UseEntityFrameworkPersistence<TWebhookContext>(webhookOptions, configure, autoRunMigrations, true, ServiceLifetime.Singleton);
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, without using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Use this method when you do not wish to use DB connection pooling, such as when integrating with a multi-tenant
/// application, where re-use of DB Context objects is impractical.
/// </para>
/// <para>
/// Although auto-running of migrations is supported in this scenario, use this with caution. When pooling is not in use and each instance of
/// the DB Context may differ, it is not feasible to try to automatically migrate them.
/// Your application is ultimately responsible for executing the contents of the <see cref="RunMigrations"/> class in a manner
/// which is suitable for your use-case.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback</param>
/// <param name="serviceLifetime">The service lifetime which will be used for each DB Context instance</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseNonPooledEntityFrameworkPersistence(this WebhookOptionsBuilder webhookOptions,
Action<DbContextOptionsBuilder> configure,
ServiceLifetime serviceLifetime = ServiceLifetime.Singleton,
bool autoRunMigrations = false) =>
webhookOptions.UseNonPooledEntityFrameworkPersistence<WebhookContext>(configure, serviceLifetime, autoRunMigrations);
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, without using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Use this method when you do not wish to use DB connection pooling, such as when integrating with a multi-tenant
/// application, where re-use of DB Context objects is impractical.
/// </para>
/// <para>
/// Although auto-running of migrations is supported in this scenario, use this with caution. When pooling is not in use and each instance of
/// the DB Context may differ, it is not feasible to try to automatically migrate them.
/// Your application is ultimately responsible for executing the contents of the <see cref="RunMigrations"/> class in a manner
/// which is suitable for your use-case.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback</param>
/// <param name="serviceLifetime">The service lifetime which will be used for each DB Context instance</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <typeparam name="TWebhookContext">The concrete type of <see cref="ElsaContext"/> to use.</typeparam>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseNonPooledEntityFrameworkPersistence<TWebhookContext>(this WebhookOptionsBuilder webhookOptions,
Action<DbContextOptionsBuilder> configure,
ServiceLifetime serviceLifetime = ServiceLifetime.Singleton,
bool autoRunMigrations = false) where TWebhookContext : WebhookContext =>
webhookOptions.UseNonPooledEntityFrameworkPersistence<TWebhookContext>((_, builder) => configure(builder), serviceLifetime, autoRunMigrations);
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, without using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Use this method when you do not wish to use DB connection pooling, such as when integrating with a multi-tenant
/// application, where re-use of DB Context objects is impractical.
/// </para>
/// <para>
/// Although auto-running of migrations is supported in this scenario, use this with caution. When pooling is not in use and each instance of
/// the DB Context may differ, it is not feasible to try to automatically migrate them.
/// Your application is ultimately responsible for executing the contents of the <see cref="RunMigrations"/> class in a manner
/// which is suitable for your use-case.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback, which also provides access to a service provider</param>
/// <param name="serviceLifetime">The service lifetime which will be used for each DB Context instance</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseNonPooledEntityFrameworkPersistence(this WebhookOptionsBuilder webhookOptions,
Action<IServiceProvider, DbContextOptionsBuilder> configure,
ServiceLifetime serviceLifetime = ServiceLifetime.Singleton,
bool autoRunMigrations = false) =>
webhookOptions.UseNonPooledEntityFrameworkPersistence<WebhookContext>(configure, serviceLifetime, autoRunMigrations);
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, without using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Use this method when you do not wish to use DB connection pooling, such as when integrating with a multi-tenant
/// application, where re-use of DB Context objects is impractical.
/// </para>
/// <para>
/// Although auto-running of migrations is supported in this scenario, use this with caution. When pooling is not in use and each instance of
/// the DB Context may differ, it is not feasible to try to automatically migrate them.
/// Your application is ultimately responsible for executing the contents of the <see cref="RunMigrations"/> class in a manner
/// which is suitable for your use-case.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback, which also provides access to a service provider</param>
/// <param name="serviceLifetime">The service lifetime which will be used for each DB Context instance</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <typeparam name="TWebhookContext">The concrete type of <see cref="ElsaContext"/> to use.</typeparam>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseNonPooledEntityFrameworkPersistence<TWebhookContext>(this WebhookOptionsBuilder webhookOptions,
Action<IServiceProvider, DbContextOptionsBuilder> configure,
ServiceLifetime serviceLifetime = ServiceLifetime.Singleton,
bool autoRunMigrations = false) where TWebhookContext : WebhookContext =>
UseEntityFrameworkPersistence<TWebhookContext>(webhookOptions, configure, autoRunMigrations, false, serviceLifetime);
static WebhookOptionsBuilder UseEntityFrameworkPersistence<TWebhookContext>(WebhookOptionsBuilder webhookOptions,
Action<IServiceProvider, DbContextOptionsBuilder> configure,
bool autoRunMigrations,
bool useContextPooling,
ServiceLifetime serviceLifetime) where TWebhookContext : WebhookContext
{
/* Auto-running migrations is intentionally unavailable when not using context pooling.
* When we aren't using pooling then it probably means that each DB Context is different
* in some manner. That could easily mean the connection strings (IE: Contexts might not
* all connect to the same DB). In that case, without further logic (which can't be
* pre-empted by Elsa), we can't be sure we're connecting to the right DBs when running
* migrations.
*
* It's much more sane just to explicitly not-support it and leave it to the app developer.
* They can run their own migrations in line with their own logic.
*/
if (useContextPooling)
webhookOptions.Services.AddPooledDbContextFactory<TWebhookContext>(configure);
else
webhookOptions.Services.AddDbContextFactory<TWebhookContext>(configure, serviceLifetime);
webhookOptions.Services
.AddSingleton<IWebhookContextFactory, WebhookContextFactory<TWebhookContext>>()
.AddScoped<EntityFrameworkWebhookDefinitionStore>();
if (autoRunMigrations)
webhookOptions.Services.AddStartupTask<RunMigrations>();
webhookOptions.UseWebhookDefinitionStore(sp => sp.GetRequiredService<EntityFrameworkWebhookDefinitionStore>());
return webhookOptions;
}
}
}

View file

@ -0,0 +1,16 @@
using Elsa.Activities.Webhooks.Extensions;
using Elsa.Attributes;
using Elsa.Webhooks.Persistence.EntityFramework.Sqlite;
namespace Elsa.Activities.Webhooks
{
[Feature("Webhook")]
public class WebhookStartup
{
//, IConfiguration configuration
public void ConfigureElsa(ElsaOptionsBuilder elsa)
{
elsa.AddWebhooks(webhooks => webhooks.UseEntityFrameworkPersistence(ef => ef.UseWebhookSqlite()));
}
}
}

View file

@ -19,7 +19,6 @@
<ItemGroup>
<ProjectReference Include="..\..\..\persistence\Elsa.Persistence.EntityFramework\Elsa.Persistence.EntityFramework.Core\Elsa.Persistence.EntityFramework.Core.csproj" />
<ProjectReference Include="..\Elsa.Activities.Webhooks\Elsa.Activities.Webhooks.csproj" />
<ProjectReference Include="..\Elsa.Webhooks.Abstractions\Elsa.Webhooks.Abstractions.csproj" />
</ItemGroup>

View file

@ -1,228 +1,228 @@
using System;
using Elsa.Webhooks.Persistence.EntityFramework.Core.Services;
using Elsa.Webhooks.Persistence.EntityFramework.Core.StartupTasks;
using Elsa.Webhooks.Persistence.EntityFramework.Core.Stores;
using Elsa.Activities.Webhooks;
using Elsa.Runtime;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
//using System;
//using Elsa.Webhooks.Persistence.EntityFramework.Core.Services;
//using Elsa.Webhooks.Persistence.EntityFramework.Core.StartupTasks;
//using Elsa.Webhooks.Persistence.EntityFramework.Core.Stores;
//using Elsa.Activities.Webhooks;
//using Elsa.Runtime;
//using Microsoft.EntityFrameworkCore;
//using Microsoft.Extensions.DependencyInjection;
namespace Elsa.Webhooks.Persistence.EntityFramework.Core.Extensions
{
public static class WebhookServiceCollectionExtensions
{
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Pooled DB Context instances is a performance optimisation which is documented in more detail at
/// https://docs.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-constant#dbcontext-pooling.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseEntityFrameworkPersistence(this WebhookOptionsBuilder webhookOptions,
Action<DbContextOptionsBuilder> configure,
bool autoRunMigrations = true) =>
webhookOptions.UseEntityFrameworkPersistence<WebhookContext>(configure, autoRunMigrations);
//namespace Elsa.Webhooks.Persistence.EntityFramework.Core.Extensions
//{
// public static class WebhookServiceCollectionExtensions
// {
// /// <summary>
// /// Configures Elsa to use Entity Framework Core for persistence, using pooled DB Context instances.
// /// </summary>
// /// <remarks>
// /// <para>
// /// Pooled DB Context instances is a performance optimisation which is documented in more detail at
// /// https://docs.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-constant#dbcontext-pooling.
// /// </para>
// /// </remarks>
// /// <param name="webhookOptions">An Elsa options builder</param>
// /// <param name="configure">A configuration builder callback</param>
// /// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
// /// <returns>The Elsa options builder, so calls may be chained</returns>
// public static WebhookOptionsBuilder UseEntityFrameworkPersistence(this WebhookOptionsBuilder webhookOptions,
// Action<DbContextOptionsBuilder> configure,
// bool autoRunMigrations = true) =>
// webhookOptions.UseEntityFrameworkPersistence<WebhookContext>(configure, autoRunMigrations);
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Pooled DB Context instances is a performance optimisation which is documented in more detail at
/// https://docs.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-constant#dbcontext-pooling.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <typeparam name="TWebhookContext">The concrete type of <see cref="ElsaContext"/> to use.</typeparam>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseEntityFrameworkPersistence<TWebhookContext>(this WebhookOptionsBuilder webhookOptions,
Action<DbContextOptionsBuilder> configure,
bool autoRunMigrations = true) where TWebhookContext : WebhookContext =>
webhookOptions.UseEntityFrameworkPersistence<TWebhookContext>((_, builder) => configure(builder), autoRunMigrations);
// /// <summary>
// /// Configures Elsa to use Entity Framework Core for persistence, using pooled DB Context instances.
// /// </summary>
// /// <remarks>
// /// <para>
// /// Pooled DB Context instances is a performance optimisation which is documented in more detail at
// /// https://docs.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-constant#dbcontext-pooling.
// /// </para>
// /// </remarks>
// /// <param name="webhookOptions">An Elsa options builder</param>
// /// <param name="configure">A configuration builder callback</param>
// /// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
// /// <typeparam name="TWebhookContext">The concrete type of <see cref="ElsaContext"/> to use.</typeparam>
// /// <returns>The Elsa options builder, so calls may be chained</returns>
// public static WebhookOptionsBuilder UseEntityFrameworkPersistence<TWebhookContext>(this WebhookOptionsBuilder webhookOptions,
// Action<DbContextOptionsBuilder> configure,
// bool autoRunMigrations = true) where TWebhookContext : WebhookContext =>
// webhookOptions.UseEntityFrameworkPersistence<TWebhookContext>((_, builder) => configure(builder), autoRunMigrations);
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Pooled DB Context instances is a performance optimisation which is documented in more detail at
/// https://docs.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-constant#dbcontext-pooling.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback, which also provides access to a service provider</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseEntityFrameworkPersistence(this WebhookOptionsBuilder webhookOptions,
Action<IServiceProvider, DbContextOptionsBuilder> configure,
bool autoRunMigrations = true) =>
webhookOptions.UseEntityFrameworkPersistence<WebhookContext>(configure, autoRunMigrations);
// /// <summary>
// /// Configures Elsa to use Entity Framework Core for persistence, using pooled DB Context instances.
// /// </summary>
// /// <remarks>
// /// <para>
// /// Pooled DB Context instances is a performance optimisation which is documented in more detail at
// /// https://docs.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-constant#dbcontext-pooling.
// /// </para>
// /// </remarks>
// /// <param name="webhookOptions">An Elsa options builder</param>
// /// <param name="configure">A configuration builder callback, which also provides access to a service provider</param>
// /// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
// /// <returns>The Elsa options builder, so calls may be chained</returns>
// public static WebhookOptionsBuilder UseEntityFrameworkPersistence(this WebhookOptionsBuilder webhookOptions,
// Action<IServiceProvider, DbContextOptionsBuilder> configure,
// bool autoRunMigrations = true) =>
// webhookOptions.UseEntityFrameworkPersistence<WebhookContext>(configure, autoRunMigrations);
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Pooled DB Context instances is a performance optimisation which is documented in more detail at
/// https://docs.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-constant#dbcontext-pooling.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback, which also provides access to a service provider</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <typeparam name="TWebhookContext">The concrete type of <see cref="ElsaContext"/> to use.</typeparam>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseEntityFrameworkPersistence<TWebhookContext>(this WebhookOptionsBuilder webhookOptions,
Action<IServiceProvider, DbContextOptionsBuilder> configure,
bool autoRunMigrations = true) where TWebhookContext : WebhookContext =>
UseEntityFrameworkPersistence<TWebhookContext>(webhookOptions, configure, autoRunMigrations, true, ServiceLifetime.Singleton);
// /// <summary>
// /// Configures Elsa to use Entity Framework Core for persistence, using pooled DB Context instances.
// /// </summary>
// /// <remarks>
// /// <para>
// /// Pooled DB Context instances is a performance optimisation which is documented in more detail at
// /// https://docs.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-constant#dbcontext-pooling.
// /// </para>
// /// </remarks>
// /// <param name="webhookOptions">An Elsa options builder</param>
// /// <param name="configure">A configuration builder callback, which also provides access to a service provider</param>
// /// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
// /// <typeparam name="TWebhookContext">The concrete type of <see cref="ElsaContext"/> to use.</typeparam>
// /// <returns>The Elsa options builder, so calls may be chained</returns>
// public static WebhookOptionsBuilder UseEntityFrameworkPersistence<TWebhookContext>(this WebhookOptionsBuilder webhookOptions,
// Action<IServiceProvider, DbContextOptionsBuilder> configure,
// bool autoRunMigrations = true) where TWebhookContext : WebhookContext =>
// UseEntityFrameworkPersistence<TWebhookContext>(webhookOptions, configure, autoRunMigrations, true, ServiceLifetime.Singleton);
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, without using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Use this method when you do not wish to use DB connection pooling, such as when integrating with a multi-tenant
/// application, where re-use of DB Context objects is impractical.
/// </para>
/// <para>
/// Although auto-running of migrations is supported in this scenario, use this with caution. When pooling is not in use and each instance of
/// the DB Context may differ, it is not feasible to try to automatically migrate them.
/// Your application is ultimately responsible for executing the contents of the <see cref="RunMigrations"/> class in a manner
/// which is suitable for your use-case.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback</param>
/// <param name="serviceLifetime">The service lifetime which will be used for each DB Context instance</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseNonPooledEntityFrameworkPersistence(this WebhookOptionsBuilder webhookOptions,
Action<DbContextOptionsBuilder> configure,
ServiceLifetime serviceLifetime = ServiceLifetime.Singleton,
bool autoRunMigrations = false) =>
webhookOptions.UseNonPooledEntityFrameworkPersistence<WebhookContext>(configure, serviceLifetime, autoRunMigrations);
// /// <summary>
// /// Configures Elsa to use Entity Framework Core for persistence, without using pooled DB Context instances.
// /// </summary>
// /// <remarks>
// /// <para>
// /// Use this method when you do not wish to use DB connection pooling, such as when integrating with a multi-tenant
// /// application, where re-use of DB Context objects is impractical.
// /// </para>
// /// <para>
// /// Although auto-running of migrations is supported in this scenario, use this with caution. When pooling is not in use and each instance of
// /// the DB Context may differ, it is not feasible to try to automatically migrate them.
// /// Your application is ultimately responsible for executing the contents of the <see cref="RunMigrations"/> class in a manner
// /// which is suitable for your use-case.
// /// </para>
// /// </remarks>
// /// <param name="webhookOptions">An Elsa options builder</param>
// /// <param name="configure">A configuration builder callback</param>
// /// <param name="serviceLifetime">The service lifetime which will be used for each DB Context instance</param>
// /// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
// /// <returns>The Elsa options builder, so calls may be chained</returns>
// public static WebhookOptionsBuilder UseNonPooledEntityFrameworkPersistence(this WebhookOptionsBuilder webhookOptions,
// Action<DbContextOptionsBuilder> configure,
// ServiceLifetime serviceLifetime = ServiceLifetime.Singleton,
// bool autoRunMigrations = false) =>
// webhookOptions.UseNonPooledEntityFrameworkPersistence<WebhookContext>(configure, serviceLifetime, autoRunMigrations);
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, without using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Use this method when you do not wish to use DB connection pooling, such as when integrating with a multi-tenant
/// application, where re-use of DB Context objects is impractical.
/// </para>
/// <para>
/// Although auto-running of migrations is supported in this scenario, use this with caution. When pooling is not in use and each instance of
/// the DB Context may differ, it is not feasible to try to automatically migrate them.
/// Your application is ultimately responsible for executing the contents of the <see cref="RunMigrations"/> class in a manner
/// which is suitable for your use-case.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback</param>
/// <param name="serviceLifetime">The service lifetime which will be used for each DB Context instance</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <typeparam name="TWebhookContext">The concrete type of <see cref="ElsaContext"/> to use.</typeparam>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseNonPooledEntityFrameworkPersistence<TWebhookContext>(this WebhookOptionsBuilder webhookOptions,
Action<DbContextOptionsBuilder> configure,
ServiceLifetime serviceLifetime = ServiceLifetime.Singleton,
bool autoRunMigrations = false) where TWebhookContext : WebhookContext =>
webhookOptions.UseNonPooledEntityFrameworkPersistence<TWebhookContext>((_, builder) => configure(builder), serviceLifetime, autoRunMigrations);
// /// <summary>
// /// Configures Elsa to use Entity Framework Core for persistence, without using pooled DB Context instances.
// /// </summary>
// /// <remarks>
// /// <para>
// /// Use this method when you do not wish to use DB connection pooling, such as when integrating with a multi-tenant
// /// application, where re-use of DB Context objects is impractical.
// /// </para>
// /// <para>
// /// Although auto-running of migrations is supported in this scenario, use this with caution. When pooling is not in use and each instance of
// /// the DB Context may differ, it is not feasible to try to automatically migrate them.
// /// Your application is ultimately responsible for executing the contents of the <see cref="RunMigrations"/> class in a manner
// /// which is suitable for your use-case.
// /// </para>
// /// </remarks>
// /// <param name="webhookOptions">An Elsa options builder</param>
// /// <param name="configure">A configuration builder callback</param>
// /// <param name="serviceLifetime">The service lifetime which will be used for each DB Context instance</param>
// /// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
// /// <typeparam name="TWebhookContext">The concrete type of <see cref="ElsaContext"/> to use.</typeparam>
// /// <returns>The Elsa options builder, so calls may be chained</returns>
// public static WebhookOptionsBuilder UseNonPooledEntityFrameworkPersistence<TWebhookContext>(this WebhookOptionsBuilder webhookOptions,
// Action<DbContextOptionsBuilder> configure,
// ServiceLifetime serviceLifetime = ServiceLifetime.Singleton,
// bool autoRunMigrations = false) where TWebhookContext : WebhookContext =>
// webhookOptions.UseNonPooledEntityFrameworkPersistence<TWebhookContext>((_, builder) => configure(builder), serviceLifetime, autoRunMigrations);
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, without using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Use this method when you do not wish to use DB connection pooling, such as when integrating with a multi-tenant
/// application, where re-use of DB Context objects is impractical.
/// </para>
/// <para>
/// Although auto-running of migrations is supported in this scenario, use this with caution. When pooling is not in use and each instance of
/// the DB Context may differ, it is not feasible to try to automatically migrate them.
/// Your application is ultimately responsible for executing the contents of the <see cref="RunMigrations"/> class in a manner
/// which is suitable for your use-case.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback, which also provides access to a service provider</param>
/// <param name="serviceLifetime">The service lifetime which will be used for each DB Context instance</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseNonPooledEntityFrameworkPersistence(this WebhookOptionsBuilder webhookOptions,
Action<IServiceProvider, DbContextOptionsBuilder> configure,
ServiceLifetime serviceLifetime = ServiceLifetime.Singleton,
bool autoRunMigrations = false) =>
webhookOptions.UseNonPooledEntityFrameworkPersistence<WebhookContext>(configure, serviceLifetime, autoRunMigrations);
// /// <summary>
// /// Configures Elsa to use Entity Framework Core for persistence, without using pooled DB Context instances.
// /// </summary>
// /// <remarks>
// /// <para>
// /// Use this method when you do not wish to use DB connection pooling, such as when integrating with a multi-tenant
// /// application, where re-use of DB Context objects is impractical.
// /// </para>
// /// <para>
// /// Although auto-running of migrations is supported in this scenario, use this with caution. When pooling is not in use and each instance of
// /// the DB Context may differ, it is not feasible to try to automatically migrate them.
// /// Your application is ultimately responsible for executing the contents of the <see cref="RunMigrations"/> class in a manner
// /// which is suitable for your use-case.
// /// </para>
// /// </remarks>
// /// <param name="webhookOptions">An Elsa options builder</param>
// /// <param name="configure">A configuration builder callback, which also provides access to a service provider</param>
// /// <param name="serviceLifetime">The service lifetime which will be used for each DB Context instance</param>
// /// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
// /// <returns>The Elsa options builder, so calls may be chained</returns>
// public static WebhookOptionsBuilder UseNonPooledEntityFrameworkPersistence(this WebhookOptionsBuilder webhookOptions,
// Action<IServiceProvider, DbContextOptionsBuilder> configure,
// ServiceLifetime serviceLifetime = ServiceLifetime.Singleton,
// bool autoRunMigrations = false) =>
// webhookOptions.UseNonPooledEntityFrameworkPersistence<WebhookContext>(configure, serviceLifetime, autoRunMigrations);
/// <summary>
/// Configures Elsa to use Entity Framework Core for persistence, without using pooled DB Context instances.
/// </summary>
/// <remarks>
/// <para>
/// Use this method when you do not wish to use DB connection pooling, such as when integrating with a multi-tenant
/// application, where re-use of DB Context objects is impractical.
/// </para>
/// <para>
/// Although auto-running of migrations is supported in this scenario, use this with caution. When pooling is not in use and each instance of
/// the DB Context may differ, it is not feasible to try to automatically migrate them.
/// Your application is ultimately responsible for executing the contents of the <see cref="RunMigrations"/> class in a manner
/// which is suitable for your use-case.
/// </para>
/// </remarks>
/// <param name="webhookOptions">An Elsa options builder</param>
/// <param name="configure">A configuration builder callback, which also provides access to a service provider</param>
/// <param name="serviceLifetime">The service lifetime which will be used for each DB Context instance</param>
/// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
/// <typeparam name="TWebhookContext">The concrete type of <see cref="ElsaContext"/> to use.</typeparam>
/// <returns>The Elsa options builder, so calls may be chained</returns>
public static WebhookOptionsBuilder UseNonPooledEntityFrameworkPersistence<TWebhookContext>(this WebhookOptionsBuilder webhookOptions,
Action<IServiceProvider, DbContextOptionsBuilder> configure,
ServiceLifetime serviceLifetime = ServiceLifetime.Singleton,
bool autoRunMigrations = false) where TWebhookContext : WebhookContext =>
UseEntityFrameworkPersistence<TWebhookContext>(webhookOptions, configure, autoRunMigrations, false, serviceLifetime);
// /// <summary>
// /// Configures Elsa to use Entity Framework Core for persistence, without using pooled DB Context instances.
// /// </summary>
// /// <remarks>
// /// <para>
// /// Use this method when you do not wish to use DB connection pooling, such as when integrating with a multi-tenant
// /// application, where re-use of DB Context objects is impractical.
// /// </para>
// /// <para>
// /// Although auto-running of migrations is supported in this scenario, use this with caution. When pooling is not in use and each instance of
// /// the DB Context may differ, it is not feasible to try to automatically migrate them.
// /// Your application is ultimately responsible for executing the contents of the <see cref="RunMigrations"/> class in a manner
// /// which is suitable for your use-case.
// /// </para>
// /// </remarks>
// /// <param name="webhookOptions">An Elsa options builder</param>
// /// <param name="configure">A configuration builder callback, which also provides access to a service provider</param>
// /// <param name="serviceLifetime">The service lifetime which will be used for each DB Context instance</param>
// /// <param name="autoRunMigrations">If <c>true</c> then database migrations will be auto-executed on startup</param>
// /// <typeparam name="TWebhookContext">The concrete type of <see cref="ElsaContext"/> to use.</typeparam>
// /// <returns>The Elsa options builder, so calls may be chained</returns>
// public static WebhookOptionsBuilder UseNonPooledEntityFrameworkPersistence<TWebhookContext>(this WebhookOptionsBuilder webhookOptions,
// Action<IServiceProvider, DbContextOptionsBuilder> configure,
// ServiceLifetime serviceLifetime = ServiceLifetime.Singleton,
// bool autoRunMigrations = false) where TWebhookContext : WebhookContext =>
// UseEntityFrameworkPersistence<TWebhookContext>(webhookOptions, configure, autoRunMigrations, false, serviceLifetime);
static WebhookOptionsBuilder UseEntityFrameworkPersistence<TWebhookContext>(WebhookOptionsBuilder webhookOptions,
Action<IServiceProvider, DbContextOptionsBuilder> configure,
bool autoRunMigrations,
bool useContextPooling,
ServiceLifetime serviceLifetime) where TWebhookContext : WebhookContext
{
/* Auto-running migrations is intentionally unavailable when not using context pooling.
* When we aren't using pooling then it probably means that each DB Context is different
* in some manner. That could easily mean the connection strings (IE: Contexts might not
* all connect to the same DB). In that case, without further logic (which can't be
* pre-empted by Elsa), we can't be sure we're connecting to the right DBs when running
* migrations.
*
* It's much more sane just to explicitly not-support it and leave it to the app developer.
* They can run their own migrations in line with their own logic.
*/
// static WebhookOptionsBuilder UseEntityFrameworkPersistence<TWebhookContext>(WebhookOptionsBuilder webhookOptions,
// Action<IServiceProvider, DbContextOptionsBuilder> configure,
// bool autoRunMigrations,
// bool useContextPooling,
// ServiceLifetime serviceLifetime) where TWebhookContext : WebhookContext
// {
// /* Auto-running migrations is intentionally unavailable when not using context pooling.
// * When we aren't using pooling then it probably means that each DB Context is different
// * in some manner. That could easily mean the connection strings (IE: Contexts might not
// * all connect to the same DB). In that case, without further logic (which can't be
// * pre-empted by Elsa), we can't be sure we're connecting to the right DBs when running
// * migrations.
// *
// * It's much more sane just to explicitly not-support it and leave it to the app developer.
// * They can run their own migrations in line with their own logic.
// */
if (useContextPooling)
webhookOptions.Services.AddPooledDbContextFactory<TWebhookContext>(configure);
else
webhookOptions.Services.AddDbContextFactory<TWebhookContext>(configure, serviceLifetime);
// if (useContextPooling)
// webhookOptions.Services.AddPooledDbContextFactory<TWebhookContext>(configure);
// else
// webhookOptions.Services.AddDbContextFactory<TWebhookContext>(configure, serviceLifetime);
webhookOptions.Services
.AddSingleton<IWebhookContextFactory, WebhookContextFactory<TWebhookContext>>()
.AddScoped<EntityFrameworkWebhookDefinitionStore>();
// webhookOptions.Services
// .AddSingleton<IWebhookContextFactory, WebhookContextFactory<TWebhookContext>>()
// .AddScoped<EntityFrameworkWebhookDefinitionStore>();
if (autoRunMigrations)
webhookOptions.Services.AddStartupTask<RunMigrations>();
// if (autoRunMigrations)
// webhookOptions.Services.AddStartupTask<RunMigrations>();
webhookOptions.UseWebhookDefinitionStore(sp => sp.GetRequiredService<EntityFrameworkWebhookDefinitionStore>());
// webhookOptions.UseWebhookDefinitionStore(sp => sp.GetRequiredService<EntityFrameworkWebhookDefinitionStore>());
return webhookOptions;
}
}
}
// return webhookOptions;
// }
// }
//}

View file

@ -0,0 +1,23 @@
using System;
namespace Elsa.Attributes
{
/// <summary>
/// An attribute that can associate a service or component with
/// a specific feature by its name. This component will only
/// be used if the feature is enabled.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class FeatureAttribute : Attribute
{
public FeatureAttribute(string featureName)
{
FeatureName = featureName;
}
/// <summary>
/// The name of the feature to assign the component to.
/// </summary>
public string FeatureName { get; set; }
}
}

View file

@ -10,7 +10,9 @@ namespace Elsa
{
public static IEnumerable<Type> GetAllWithInterface(this Assembly assembly, Type @interface) => assembly.GetTypes().Where(t => t.IsClass && t.IsAbstract == false && t.GetInterfaces().Contains(@interface));
public static IEnumerable<Type> GetAllWithBaseClass(this Assembly assembly, Type baseClass) => assembly.GetTypes().Where(baseClass.IsAssignableFrom);
//public static IEnumerable<Type> GetAllWithAttribute(this Assembly assembly, Type attribute) => assembly.GetTypes().Where(t => t.GetCustomAttributes(typeof(attribute), true).Length > 0);
public static IEnumerable<Type> GetAllWithInterface<TType>(this Assembly assembly) => assembly.GetAllWithInterface(typeof(TType));
public static IEnumerable<Type> GetAllWithBaseClass<TType>(this Assembly assembly) => assembly.GetAllWithBaseClass(typeof(TType));
//public static IEnumerable<Type> GetAllWithAttribute<TType>(this Assembly assembly) => assembly.GetAllWithAttribute(typeof(TType));
}
}

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Elsa.Attributes;
using Elsa.Builders;
using Elsa.Caching;
using Elsa.Persistence;
@ -56,6 +57,34 @@ namespace Elsa
return this;
}
public ElsaOptionsBuilder AddFeatures(IEnumerable<Assembly> assemblies, IEnumerable<string> features)
{
foreach (Assembly assembly in assemblies)
{
foreach (Type type in assembly.GetTypes())
{
var attributes = type.GetCustomAttributes(typeof(FeatureAttribute), true);
foreach (Attribute attribute in attributes)
{
if (!features.Contains(((FeatureAttribute)attribute).FeatureName)) continue;
MethodInfo methodInfo = type.GetMethod("ConfigureElsa");
if (methodInfo != null)
{
object[] parametersArray = new object[] { this };
object classInstance = Activator.CreateInstance(type, null);
methodInfo.Invoke(classInstance, parametersArray);
}
}
}
}
return this;
}
public ElsaOptionsBuilder AddActivity<T>() where T : IActivity => AddActivity(typeof(T));
public ElsaOptionsBuilder AddActivity(Type activityType)

View file

@ -10,6 +10,7 @@
<ItemGroup>
<ProjectReference Include="..\..\..\activities\Elsa.Activities.Conductor\Elsa.Activities.Conductor.csproj" />
<ProjectReference Include="..\..\..\activities\Elsa.Activities.Console\Elsa.Activities.Console.csproj" />
<ProjectReference Include="..\..\..\activities\Elsa.Activities.Email\Elsa.Activities.Email.csproj" />
<ProjectReference Include="..\..\..\activities\Elsa.Activities.Http\Elsa.Activities.Http.csproj" />
<ProjectReference Include="..\..\..\activities\Elsa.Activities.Temporal.Hangfire\Elsa.Activities.Temporal.Hangfire.csproj" />

View file

@ -1,16 +1,21 @@
using Elsa.Activities.Conductor.Extensions;
using Elsa.Activities.UserTask.Extensions;
using Elsa.Activities.Webhooks.Extensions;
using Elsa.Attributes;
using Elsa.Persistence.EntityFramework.Core.Extensions;
using Elsa.Persistence.EntityFramework.Sqlite;
using Elsa.Samples.Server.Host.Activities;
using Elsa.Webhooks.Persistence.EntityFramework.Core.Extensions;
//using Elsa.Webhooks.Persistence.EntityFramework.Core.Extensions;
using Elsa.Webhooks.Persistence.EntityFramework.Sqlite;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Elsa.Samples.Server.Host
{
@ -34,6 +39,9 @@ namespace Elsa.Samples.Server.Host
services.AddControllers();
//List<Assembly> assemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies().Select((item) => Assembly.Load(item)).ToList();
List<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList<Assembly>();
services
.AddActivityPropertyOptionsProvider<VehicleActivity>()
.AddRuntimeSelectItemsProvider<VehicleActivity>()
@ -46,7 +54,9 @@ namespace Elsa.Samples.Server.Host
//.UseRabbitMq(Configuration.GetConnectionString("RabbitMq"))
//.UseRebusCacheSignal()
//.UseRedisCacheSignal()
.AddConsoleActivities()
.AddHttpActivities(elsaSection.GetSection("Http").Bind)
.AddEmailActivities(elsaSection.GetSection("Smtp").Bind)
.AddQuartzTemporalActivities()
@ -63,7 +73,9 @@ namespace Elsa.Samples.Server.Host
.AddConductorActivities(options => elsaSection.GetSection("Conductor").Bind(options))
.AddActivitiesFrom<Startup>()
.AddWorkflowsFrom<Startup>()
.AddWebhooks(webhooks => webhooks.UseEntityFrameworkPersistence(ef => ef.UseWebhookSqlite()))
.AddFeatures(assemblies, elsaSection.GetSection("Features").Get<List<string>>())
//.AddWebhooks(webhooks => webhooks.UseEntityFrameworkPersistence(ef => ef.UseWebhookSqlite()))
);
// Elsa API endpoints.
@ -71,6 +83,8 @@ namespace Elsa.Samples.Server.Host
.AddElsaApiEndpoints()
.AddElsaSwagger();
//AddFeatures();
// Allow arbitrary client browser apps to access the API for demo purposes only.
// In a production environment, make sure to allow only origins you trust.
services.AddCors(cors => cors.AddDefaultPolicy(policy => policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().WithExposedHeaders("Content-Disposition")));
@ -91,5 +105,6 @@ namespace Elsa.Samples.Server.Host
.UseRouting()
.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
}
}

View file

@ -6,5 +6,8 @@
"System": "Information",
"Microsoft": "Warning"
}
},
"Elsa": {
"Features": [ "Webhook", "Console" ]
}
}

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />