Skip to content

Commit e63e8e3

Browse files
committed
Modules as plugins posibility was added.
1 parent 2c0434c commit e63e8e3

File tree

6 files changed

+191
-10
lines changed

6 files changed

+191
-10
lines changed

README.md

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,113 @@
11
# Calabonga.AspNetCore.AppDefinitions
22

3-
Сборка позволяет навести порядок в вашем `Program.cs`. Можно всё разложить "по полочкам". Чтобы воспользоваться сборкой надо:
3+
Сборка позволяет навести порядок в вашем `Program.cs`. Можно всё разложить "по полочкам". Чтобы воспользоваться сборкой надо просто установить nuget-пакет Calabonga.AspNetCore.AppDefinitions.
4+
5+
## Что нового
6+
7+
### Версия 2.1.0
8+
9+
* В новой версии появилась возможность подключения модулей к проекту. Достаточно воспользовать новым способом регистрации.
10+
```
11+
// Вместо этого (instead of)
12+
builder.AddDefinitions(typeof(Program));
13+
14+
// использовать этот (use this to add definitions for application)
15+
const string moduleFolder = "Modules:Folder";
16+
var modulesPath = builder.Configuration[moduleFolder] ?? throw new ArgumentNullException(moduleFolder);
17+
builder.AddDefinitionsWithModules(modulesPath, typeof(Program));
18+
```
19+
* Вывод зарегистрированных AppDefinitions усовершенствована.
20+
```
21+
[15:43:03 DBG] [AppDefinitions]: From Program
22+
[15:43:03 DBG] [AppDefinitions]: AuthorizationDefinition (Program) (Enabled: Yes)
23+
[15:43:03 DBG] [AppDefinitions]: AuthorizeEndpoints (Program) (Enabled: Yes)
24+
[15:43:03 DBG] [AppDefinitions]: AutomapperDefinition (Program) (Enabled: Yes)
25+
[15:43:03 DBG] [AppDefinitions]: CommonDefinition (Program) (Enabled: Yes)
26+
[15:43:03 DBG] [AppDefinitions]: ContainerDefinition (Program) (Enabled: Yes)
27+
[15:43:03 DBG] [AppDefinitions]: CorsDefinition (Program) (Enabled: Yes)
28+
[15:43:03 DBG] [AppDefinitions]: DataSeedingDefinition (Program) (Enabled: Yes)
29+
[15:43:03 DBG] [AppDefinitions]: DbContextDefinition (Program) (Enabled: Yes)
30+
[15:43:03 DBG] [AppDefinitions]: ErrorHandlingDefinition (Program) (Enabled: Yes)
31+
[15:43:03 DBG] [AppDefinitions]: ETagGeneratorDefinition (Program) (Enabled: Yes)
32+
[15:43:03 DBG] [AppDefinitions]: EventItemEndpoints (Program) (Enabled: Yes)
33+
[15:43:03 DBG] [AppDefinitions]: FluentValidationDefinition (Program) (Enabled: Yes)
34+
[15:43:03 DBG] [AppDefinitions]: MediatorDefinition (Program) (Enabled: Yes)
35+
[15:43:03 DBG] [AppDefinitions]: OpenIddictDefinition (Program) (Enabled: Yes)
36+
[15:43:03 DBG] [AppDefinitions]: ProfilesEndpoints (Program) (Enabled: Yes)
37+
[15:43:03 DBG] [AppDefinitions]: SwaggerDefinition (Program) (Enabled: Yes)
38+
[15:43:03 DBG] [AppDefinitions]: TokenEndpoints (Program) (Enabled: Yes)
39+
[15:43:03 DBG] [AppDefinitions]: UnitOfWorkDefinition (Program) (Enabled: Yes)
40+
[15:43:03 DBG] From Program assemblies totally AppDefinitions found: 18
41+
[15:43:04 DBG] Total AppDefinitions applied: 18
42+
```
43+
* Появилсь возможность не только включать/выключать определенные AppDefinitions, но и указывать нужно ли их экспортировать или нет. Обратите внимание, что по умолчанию `Exported` свойство задано как `False`, то есть, не экспортировать данный `AppDefinition`. Например, если регистрацию конечной точки (endpoint) `WeatherForcast` слелать через определение (AppDefinition), то экспорт мог бы выглядеть так:
44+
```
45+
public class WeatherForecastEndpoints : AppDefinition
46+
{
47+
/// <summary>
48+
/// Enables or disables export definition as a content for module that can be exported.
49+
/// </summary>
50+
/// /// <remarks>Default values is <c>False</c></remarks>
51+
public override bool Exported => true;
52+
53+
public override void ConfigureApplication(WebApplication app)
54+
{
55+
app.MapGet("/weatherforecast", WeatherGet)
56+
.ProducesProblem(401)
57+
.Produces<WeatherForecast[]>()
58+
.WithName("GetWeatherForecast")
59+
.WithTags("ModuleTwo")
60+
.WithOpenApi()
61+
.RequireAuthorization(policyNames: CookieAuthenticationDefaults.AuthenticationScheme + ",OpenIddict.Validation.AspNetCore");
62+
}
63+
64+
// [FeatureGroupName("Weather")]
65+
private WeatherForecast[] WeatherGet([FromServices] ILogger<WeatherForecastEndpoints> logger)
66+
{
67+
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
68+
var forecast = Enumerable.Range(1, 5).Select(index =>
69+
new WeatherForecast
70+
(
71+
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
72+
Random.Shared.Next(-20, 55),
73+
summaries[Random.Shared.Next(summaries.Length)]
74+
))
75+
.ToArray();
76+
logger.LogInformation("WeatherForecast request execute at [{Time}].", DateTime.UtcNow);
77+
return forecast;
78+
}
79+
}
80+
```
81+
82+
### Версия 2.0.0
83+
84+
* Больше не требуется вливать зависимость `IServiceCollection` в метод `ConfigureServices`. Теперь достаточно только `WebApplicationBuilder`. Следовательно при переходе на версию 2.0.0 нужно просто удалить лишние зависимости. Например, регистрация `FluentValidation` это выглядит так:
85+
``` csharp
86+
/// <summary>
87+
/// FluentValidation registration as Application definition
88+
/// </summary>
89+
public class FluentValidationDefinition : AppDefinition
90+
{
91+
/// <summary>
92+
/// Configure services for current application
93+
/// </summary>
94+
/// <param name="builder"></param>
95+
public override void ConfigureServices(WebApplicationBuilder builder)
96+
{
97+
builder.Services.Configure<ApiBehaviorOptions>(options =>
98+
{
99+
options.SuppressModelStateInvalidFilter = true;
100+
});
101+
102+
builder.Services.AddValidatorsFromAssembly(typeof(Program).Assembly);
103+
}
104+
}
105+
```
106+
107+
* Регистрация стала гораздо проще.
108+
``` csharp
109+
builder.AddDefinitions(typeof(Program));
110+
```
4111

5112
## Установка nuget-пакета
6113

src/Calabonga.AspNetCore.AppDefinitions/AppDefinition.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,14 @@ public virtual void ConfigureApplication(WebApplication app) { }
2525
public virtual int OrderIndex => 0;
2626

2727
/// <summary>
28-
/// Enable or disable to register into pipeline for the current application Definition
28+
/// Enable or disable to register into pipeline for the current application Definition.
2929
/// </summary>
30+
/// <remarks>Default values is <c>True</c></remarks>
3031
public virtual bool Enabled { get; protected set; } = true;
32+
33+
/// <summary>
34+
/// Enables or disables export definition as a content for module that can be exported.
35+
/// </summary>
36+
/// /// <remarks>Default values is <c>False</c></remarks>
37+
public virtual bool Exported { get; protected set; }
3138
}

src/Calabonga.AspNetCore.AppDefinitions/AppDefinitionCollection.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
internal sealed class AppDefinitionCollection
77
{
88
internal IList<AppDefinitionItem> Items { get; } = new List<AppDefinitionItem>();
9+
910
internal IList<string> EntryPoints { get; } = new List<string>();
1011

1112
internal void AddInfo(AppDefinitionItem definition)
@@ -28,4 +29,4 @@ internal void AddInfo(AppDefinitionItem definition)
2829
/// Information about <see cref="IAppDefinition"/>
2930
/// </summary>
3031
/// <param name="Definition"></param>
31-
public sealed record AppDefinitionItem(IAppDefinition Definition, string AssemblyName);
32+
public sealed record AppDefinitionItem(IAppDefinition Definition, string AssemblyName, bool Enabled, bool Exported);

src/Calabonga.AspNetCore.AppDefinitions/AppDefinitionExtensions.cs

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,71 @@
11
using Microsoft.AspNetCore.Builder;
22
using Microsoft.Extensions.DependencyInjection;
33
using Microsoft.Extensions.Logging;
4+
using System.Reflection;
45

56
namespace Calabonga.AspNetCore.AppDefinitions;
67

78
public static class AppDefinitionExtensions
89
{
10+
/// <summary>
11+
/// Finding all definitions in your project and include their into pipeline. Modules from third party *.dll find too.<br/>
12+
/// Using <see cref="IServiceCollection"/> for registration.
13+
/// </summary>
14+
/// <remarks>
15+
/// When executing on development environment there are more diagnostic information available on console.
16+
/// </remarks>
17+
/// <param name="builder"></param>
18+
/// <param name="modulesFolderPath"></param>
19+
/// <param name="entryPointsAssembly"></param>
20+
public static void AddDefinitionsWithModules(this WebApplicationBuilder builder, string modulesFolderPath, params Type[] entryPointsAssembly)
21+
{
22+
var modulesFolder = Path.Combine(builder.Environment.ContentRootPath, modulesFolderPath);
23+
24+
if (!Directory.Exists(modulesFolder))
25+
{
26+
throw new DirectoryNotFoundException(modulesFolder);
27+
}
28+
29+
var types = new List<Type>();
30+
types.AddRange(entryPointsAssembly);
31+
32+
var modulesDirectory = new DirectoryInfo(modulesFolderPath);
33+
var modules = modulesDirectory.GetFiles("*.dll");
34+
if (!modules.Any())
35+
{
36+
return;
37+
}
38+
39+
foreach (var fileInfo in modules)
40+
{
41+
var module = Assembly.LoadFile(fileInfo.FullName);
42+
var typesAll = module.GetExportedTypes();
43+
var typesDefinition = typesAll
44+
.Where(Predicate)
45+
.ToList();
46+
47+
var instances = typesDefinition.Select(Activator.CreateInstance)
48+
.Cast<IAppDefinition>()
49+
.Where(x => x.Enabled && x.Exported)
50+
.Select(x => x.GetType())
51+
.ToList();
52+
53+
types.AddRange(instances);
54+
}
55+
56+
if (types.Any())
57+
{
58+
AddDefinitions(builder, types.ToArray());
59+
}
60+
}
61+
62+
/// <summary>
63+
/// Finds an AppDefinition in the list of types
64+
/// </summary>
65+
/// <param name="type"></param>
66+
/// <returns></returns>
67+
private static bool Predicate(Type type) => type is { IsAbstract: false, IsInterface: false } && typeof(AppDefinition).IsAssignableFrom(type);
68+
969
/// <summary>
1070
/// Finding all definitions in your project and include their into pipeline.<br/>
1171
/// Using <see cref="IServiceCollection"/> for registration.
@@ -17,7 +77,7 @@ public static class AppDefinitionExtensions
1777
/// <param name="entryPointsAssembly"></param>
1878
public static void AddDefinitions(this WebApplicationBuilder builder, params Type[] entryPointsAssembly)
1979
{
20-
var logger = builder.Services.BuildServiceProvider().GetRequiredService<ILogger<AppDefinition>>();
80+
var logger = builder.Services.BuildServiceProvider().GetRequiredService<ILogger<IAppDefinition>>();
2181
var definitions = new List<IAppDefinition>();
2282
var appDefinitionInfo = builder.Services.BuildServiceProvider().GetService<AppDefinitionCollection>();
2383
var info = appDefinitionInfo ?? new AppDefinitionCollection();
@@ -26,12 +86,12 @@ public static void AddDefinitions(this WebApplicationBuilder builder, params Typ
2686
{
2787
info.AddEntryPoint(entryPoint.Name);
2888

29-
var types = entryPoint.Assembly.ExportedTypes.Where(x => !x.IsAbstract && typeof(IAppDefinition).IsAssignableFrom(x));
89+
var types = entryPoint.Assembly.ExportedTypes.Where(Predicate);
3090
var instances = types.Select(Activator.CreateInstance).Cast<IAppDefinition>().ToList();
3191

3292
foreach (var definition in instances)
3393
{
34-
info.AddInfo(new AppDefinitionItem(definition, entryPoint.Name));
94+
info.AddInfo(new AppDefinitionItem(definition, entryPoint.Name, definition.Enabled, definition.Exported));
3595
}
3696

3797
var instancesOrdered = instances.Where(x => x.Enabled).OrderBy(x => x.OrderIndex).ToList();
@@ -83,5 +143,4 @@ public static void UseDefinitions(this WebApplication source)
83143
logger.LogDebug("Total AppDefinitions applied: {Count}", instancesOrdered.Count);
84144
}
85145
}
86-
87146
}

src/Calabonga.AspNetCore.AppDefinitions/Calabonga.AspNetCore.AppDefinitions.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<Nullable>enable</Nullable>
77
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
88
<Title>Calabonga.AspNetCore.AppDefinitions</Title>
9-
<Version>2.0.0</Version>
9+
<Version>2.1.0</Version>
1010
<Authors>Calabonga</Authors>
1111
<Company>Calabonga Soft</Company>
1212
<Product>Calabonga.AspNetCore.AppDefinitions</Product>
@@ -18,7 +18,7 @@
1818
<RepositoryUrl>https://github.com/Calabonga/Calabonga.AspNetCore.AppDefinitions</RepositoryUrl>
1919
<RepositoryType>git</RepositoryType>
2020
<PackageTags>calabonga;architecture;definitions;minimal-api;nimble-framework</PackageTags>
21-
<PackageReleaseNotes>IServiceCollection was removed. Just use WebApplicationBuilder.Services please. Assembly name added for debug information at startup.</PackageReleaseNotes>
21+
<PackageReleaseNotes>Modules as plugins posibility was added.</PackageReleaseNotes>
2222
<PackageLicenseExpression>MIT</PackageLicenseExpression>
2323
</PropertyGroup>
2424

src/Calabonga.AspNetCore.AppDefinitions/IAppDefinition.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,14 @@ public interface IAppDefinition
2525
int OrderIndex { get; }
2626

2727
/// <summary>
28-
/// Enable or disable to register into pipeline for the current application Definition
28+
/// Enable or disable to register into pipeline for the current application Definition.
2929
/// </summary>
30+
/// <remarks>Default values is <c>True</c></remarks>
3031
bool Enabled { get; }
32+
33+
/// <summary>
34+
/// Enables or disables export definition as a content for module that can be exported.
35+
/// </summary>
36+
/// /// <remarks>Default values is <c>False</c></remarks>
37+
bool Exported { get; }
3138
}

0 commit comments

Comments
 (0)