7 changed files with 344 additions and 0 deletions
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,20 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0</TargetFrameworks> |
|||
<AssemblyName>LINGYUN.Abp.Dynamic.Definitions.Core</AssemblyName> |
|||
<PackageId>LINGYUN.Abp.Dynamic.Definitions.Core</PackageId> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Core" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,8 @@ |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.Dynamic.Definitions; |
|||
|
|||
public class AbpDynamicDefinitionsCoreModule : AbpModule |
|||
{ |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.Dynamic.Definitions; |
|||
|
|||
public class AbpDynamicDefinitionsOptions |
|||
{ |
|||
public DynamicDefinitionStrategy DefaultStrategy { get; set; } |
|||
public Dictionary<Type, DynamicDefinitionStrategy> DefinitionStrategy { get; set; } |
|||
public AbpDynamicDefinitionsOptions() |
|||
{ |
|||
DefaultStrategy = DynamicDefinitionStrategy.Static; |
|||
DefinitionStrategy = new Dictionary<Type, DynamicDefinitionStrategy>(); |
|||
} |
|||
|
|||
public void MapStrategy<T>(DynamicDefinitionStrategy strategy = DynamicDefinitionStrategy.Static) |
|||
{ |
|||
DefinitionStrategy[typeof(T)] = strategy; |
|||
} |
|||
|
|||
public DynamicDefinitionStrategy GetStrategy<T>() |
|||
{ |
|||
return GetStrategy(typeof(T)); |
|||
} |
|||
|
|||
public DynamicDefinitionStrategy GetStrategy(Type type) |
|||
{ |
|||
if (DefinitionStrategy.TryGetValue(type, out var strategy)) |
|||
{ |
|||
return strategy; |
|||
} |
|||
|
|||
return DefaultStrategy; |
|||
} |
|||
} |
|||
@ -0,0 +1,240 @@ |
|||
using Microsoft.Extensions.Options; |
|||
using System.Collections.Generic; |
|||
using System.Collections.Immutable; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.Dynamic.Definitions; |
|||
|
|||
public abstract class DynamicDefinitionManager<TGroupDefinition, TDefinition> : DynamicDefinitionManager<TDefinition> |
|||
{ |
|||
protected DynamicDefinitionManager( |
|||
IOptions<AbpDynamicDefinitionsOptions> options) : base(options) |
|||
{ |
|||
} |
|||
|
|||
public async virtual Task<TGroupDefinition?> GetGroupDefinitionAsync( |
|||
TGroupDefinition? staticGroupDefinition, |
|||
TGroupDefinition? dynamicGroupDefinition) |
|||
{ |
|||
if (staticGroupDefinition != null && dynamicGroupDefinition != null) |
|||
{ |
|||
var strategy = Options.GetStrategy<TGroupDefinition>(); |
|||
switch (strategy) |
|||
{ |
|||
case DynamicDefinitionStrategy.Dynamic: |
|||
return dynamicGroupDefinition; |
|||
case DynamicDefinitionStrategy.Merge: |
|||
await MergeGroupDefinitionAsync(staticGroupDefinition, dynamicGroupDefinition); |
|||
return staticGroupDefinition; |
|||
case DynamicDefinitionStrategy.Static: |
|||
default: |
|||
return staticGroupDefinition; |
|||
} |
|||
} |
|||
|
|||
return staticGroupDefinition ?? dynamicGroupDefinition; |
|||
} |
|||
|
|||
public async virtual Task<IReadOnlyList<TGroupDefinition>> GetGroupDefinitionsAsync( |
|||
IReadOnlyList<TGroupDefinition> staticGroupDefinitions, |
|||
IReadOnlyList<TGroupDefinition> dynamicGroupDefinitions) |
|||
{ |
|||
var strategy = Options.GetStrategy<TGroupDefinition>(); |
|||
return strategy switch |
|||
{ |
|||
DynamicDefinitionStrategy.Dynamic => await GetDynamicGroupDefinitionsAsync(staticGroupDefinitions, dynamicGroupDefinitions), |
|||
DynamicDefinitionStrategy.Merge => await GetMergedGroupDefinitionsAsync(staticGroupDefinitions, dynamicGroupDefinitions), |
|||
_ => await GetStaticGroupDefinitionsAsync(staticGroupDefinitions, dynamicGroupDefinitions), |
|||
}; |
|||
} |
|||
|
|||
protected virtual Task<IReadOnlyList<TGroupDefinition>> GetStaticGroupDefinitionsAsync( |
|||
IReadOnlyList<TGroupDefinition> staticGroupDefinitions, |
|||
IReadOnlyList<TGroupDefinition> dynamicGroupDefinitions) |
|||
{ |
|||
var staticDefinitionKeys = staticGroupDefinitions |
|||
.Select(GetGroupDefinitionKey) |
|||
.ToImmutableHashSet(); |
|||
|
|||
return Task.FromResult<IReadOnlyList<TGroupDefinition>>( |
|||
staticGroupDefinitions |
|||
.Concat(dynamicGroupDefinitions.Where(d => !staticDefinitionKeys.Contains(GetGroupDefinitionKey(d)))) |
|||
.ToImmutableList() |
|||
); |
|||
} |
|||
|
|||
protected virtual Task<IReadOnlyList<TGroupDefinition>> GetDynamicGroupDefinitionsAsync( |
|||
IReadOnlyList<TGroupDefinition> staticGroupDefinitions, |
|||
IReadOnlyList<TGroupDefinition> dynamicGroupDefinitions) |
|||
{ |
|||
var dynamicDefinitionKeys = dynamicGroupDefinitions |
|||
.Select(GetGroupDefinitionKey) |
|||
.ToImmutableHashSet(); |
|||
|
|||
return Task.FromResult<IReadOnlyList<TGroupDefinition>>( |
|||
dynamicGroupDefinitions |
|||
.Concat(staticGroupDefinitions.Where(s => !dynamicDefinitionKeys.Contains(GetGroupDefinitionKey(s)))) |
|||
.ToImmutableList() |
|||
); |
|||
} |
|||
|
|||
protected async virtual Task<IReadOnlyList<TGroupDefinition>> GetMergedGroupDefinitionsAsync( |
|||
IReadOnlyList<TGroupDefinition> staticGroupDefinitions, |
|||
IReadOnlyList<TGroupDefinition> dynamicGroupDefinitions) |
|||
{ |
|||
var mergedGroups = new Dictionary<string, TGroupDefinition>(); |
|||
|
|||
foreach (var staticGroup in staticGroupDefinitions) |
|||
{ |
|||
mergedGroups[GetGroupDefinitionKey(staticGroup)] = staticGroup; |
|||
} |
|||
|
|||
foreach (var dynamicGroup in dynamicGroupDefinitions) |
|||
{ |
|||
if (mergedGroups.TryGetValue(GetGroupDefinitionKey(dynamicGroup), out var existingGroup)) |
|||
{ |
|||
await BeforeMergeGroupDefinitionAsync(existingGroup, dynamicGroup); |
|||
await MergeGroupDefinitionAsync(existingGroup, dynamicGroup); |
|||
await AfterMergeGroupDefinitionAsync(existingGroup, dynamicGroup); |
|||
} |
|||
else |
|||
{ |
|||
mergedGroups[GetGroupDefinitionKey(dynamicGroup)] = dynamicGroup; |
|||
} |
|||
} |
|||
|
|||
await AfterMergedGroupDefinitionsAsync(mergedGroups); |
|||
|
|||
return mergedGroups.Values.ToImmutableList(); |
|||
} |
|||
|
|||
protected abstract string GetGroupDefinitionKey(TGroupDefinition groupDefinition); |
|||
|
|||
protected abstract Task MergeGroupDefinitionAsync(TGroupDefinition targetGroupDefinition, TGroupDefinition sourceGroupDefinition); |
|||
|
|||
protected virtual Task BeforeMergeGroupDefinitionAsync(TGroupDefinition targetGroupDefinition, TGroupDefinition sourceGroupDefinition) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
protected virtual Task AfterMergeGroupDefinitionAsync(TGroupDefinition targetGroupDefinition, TGroupDefinition sourceGroupDefinition) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
protected virtual Task AfterMergedGroupDefinitionsAsync(Dictionary<string, TGroupDefinition> mergedDefinitions) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
|
|||
public abstract class DynamicDefinitionManager<TDefinition> |
|||
{ |
|||
protected AbpDynamicDefinitionsOptions Options { get; } |
|||
protected DynamicDefinitionManager(IOptions<AbpDynamicDefinitionsOptions> options) |
|||
{ |
|||
Options = options.Value; |
|||
} |
|||
|
|||
public async virtual Task<TDefinition?> GetDefinitionAsync(TDefinition? staticDefinition, TDefinition? dynamicDefinition) |
|||
{ |
|||
if (staticDefinition != null && dynamicDefinition != null) |
|||
{ |
|||
var strategy = Options.GetStrategy<TDefinition>(); |
|||
return strategy switch |
|||
{ |
|||
DynamicDefinitionStrategy.Static => staticDefinition, |
|||
DynamicDefinitionStrategy.Dynamic => dynamicDefinition, |
|||
DynamicDefinitionStrategy.Merge => await MergeDefinitionAsync(staticDefinition, dynamicDefinition), |
|||
_ => staticDefinition |
|||
}; |
|||
} |
|||
|
|||
return staticDefinition ?? dynamicDefinition; |
|||
} |
|||
|
|||
public async virtual Task<IReadOnlyList<TDefinition>> GetDefinitionsAsync(IReadOnlyList<TDefinition> staticDefinitions, IReadOnlyList<TDefinition> dynamicDefinitions) |
|||
{ |
|||
var strategy = Options.GetStrategy<TDefinition>(); |
|||
return strategy switch |
|||
{ |
|||
DynamicDefinitionStrategy.Dynamic => await GetDynamicDefinitionsAsync(staticDefinitions, dynamicDefinitions), |
|||
DynamicDefinitionStrategy.Merge => await GetMergedDefinitionsAsync(staticDefinitions, dynamicDefinitions), |
|||
_ => await GetStaticDefinitionsAsync(staticDefinitions, dynamicDefinitions), |
|||
}; |
|||
} |
|||
|
|||
protected virtual Task<IReadOnlyList<TDefinition>> GetStaticDefinitionsAsync(IReadOnlyList<TDefinition> staticDefinitions, IReadOnlyList<TDefinition> dynamicDefinitions) |
|||
{ |
|||
var staticDefinitionKeys = staticDefinitions |
|||
.Select(GetDefinitionKey) |
|||
.ToImmutableHashSet(); |
|||
|
|||
return Task.FromResult<IReadOnlyList<TDefinition>>( |
|||
staticDefinitions |
|||
.Concat(dynamicDefinitions.Where(d => !staticDefinitionKeys.Contains(GetDefinitionKey(d)))) |
|||
.ToImmutableList() |
|||
); |
|||
} |
|||
|
|||
protected virtual Task<IReadOnlyList<TDefinition>> GetDynamicDefinitionsAsync(IReadOnlyList<TDefinition> staticDefinitions, IReadOnlyList<TDefinition> dynamicDefinitions) |
|||
{ |
|||
var dynamicDefinitionKeys = dynamicDefinitions |
|||
.Select(GetDefinitionKey) |
|||
.ToImmutableHashSet(); |
|||
|
|||
return Task.FromResult<IReadOnlyList<TDefinition>>( |
|||
dynamicDefinitions |
|||
.Concat(staticDefinitions.Where(s => !dynamicDefinitionKeys.Contains(GetDefinitionKey(s)))) |
|||
.ToImmutableList() |
|||
); |
|||
} |
|||
|
|||
protected async virtual Task<IReadOnlyList<TDefinition>> GetMergedDefinitionsAsync(IReadOnlyList<TDefinition> staticDefinitions, IReadOnlyList<TDefinition> dynamicDefinitions) |
|||
{ |
|||
var mergedDefinitions = new Dictionary<string, TDefinition>(); |
|||
|
|||
foreach (var staticDefinition in staticDefinitions) |
|||
{ |
|||
mergedDefinitions[GetDefinitionKey(staticDefinition)] = staticDefinition; |
|||
} |
|||
|
|||
foreach (var dynamicDefinition in dynamicDefinitions) |
|||
{ |
|||
if (mergedDefinitions.TryGetValue(GetDefinitionKey(dynamicDefinition), out var existingDefinition)) |
|||
{ |
|||
await BeforeMergeDefinitionAsync(existingDefinition, dynamicDefinition); |
|||
await MergeDefinitionAsync(existingDefinition, dynamicDefinition); |
|||
await AfterMergeDefinitionAsync(existingDefinition, dynamicDefinition); |
|||
} |
|||
else |
|||
{ |
|||
mergedDefinitions[GetDefinitionKey(dynamicDefinition)] = dynamicDefinition; |
|||
} |
|||
} |
|||
|
|||
await AfterMergedDefinitionsAsync(mergedDefinitions); |
|||
|
|||
return mergedDefinitions.Values.ToImmutableList(); |
|||
} |
|||
|
|||
protected abstract string GetDefinitionKey(TDefinition definition); |
|||
|
|||
protected abstract Task<TDefinition> MergeDefinitionAsync(TDefinition targetDefinition, TDefinition sourceDefinition); |
|||
|
|||
protected virtual Task BeforeMergeDefinitionAsync(TDefinition targetDefinition, TDefinition sourceDefinition) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
protected virtual Task AfterMergeDefinitionAsync(TDefinition targetDefinition, TDefinition sourceDefinition) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
protected virtual Task AfterMergedDefinitionsAsync(Dictionary<string, TDefinition> mergedDefinitions) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
namespace LINGYUN.Abp.Dynamic.Definitions; |
|||
|
|||
public enum DynamicDefinitionStrategy |
|||
{ |
|||
Static = 0, |
|||
Dynamic = 1, |
|||
Merge = 2, |
|||
} |
|||
Loading…
Reference in new issue