Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 1.添加领域事件转换为集成事件的转换器;2.自动生成领域事件订阅和集成事件发布代码 #56

Merged
merged 9 commits into from
Aug 31, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace NetCorePal.Extensions.DistributedTransactions;

public interface IIntegrationEventConvert<in TDomainEvent, out TIntegrationEvent>
santubeikawhi marked this conversation as resolved.
Show resolved Hide resolved
where TDomainEvent : notnull
santubeikawhi marked this conversation as resolved.
Show resolved Hide resolved
where TIntegrationEvent : notnull
{
public TIntegrationEvent Convert(TDomainEvent domainEvent);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace NetCorePal.Extensions.DistributedTransactions.CAP.SourceGenerators
{
[Generator]
public class CapIntegrationConvertDomainEventHandlerSourceGenerator : ISourceGenerator
{
public void Execute(GeneratorExecutionContext context)
{
context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.RootNamespace",
out var rootNamespace);
if (rootNamespace == null)
{
return;
}

var compilation = context.Compilation;
foreach (var syntaxTree in compilation.SyntaxTrees)
{
if (syntaxTree.TryGetText(out var sourceText) &&
!sourceText.ToString().Contains("IIntegrationEventConvert"))
{
continue;
}

var semanticModel = compilation.GetSemanticModel(syntaxTree);
if (semanticModel == null)
{
continue;
}

var typeDeclarationSyntaxs =
syntaxTree.GetRoot().DescendantNodesAndSelf().OfType<TypeDeclarationSyntax>();
foreach (var tds in typeDeclarationSyntaxs)
{
var symbol = semanticModel.GetDeclaredSymbol(tds);
if (symbol is not INamedTypeSymbol) return;
INamedTypeSymbol namedTypeSymbol = (INamedTypeSymbol)symbol;
if (!namedTypeSymbol.IsImplicitClass &&
namedTypeSymbol.AllInterfaces.Any(p => p.Name == "IIntegrationEventConvert"))
{
Generate(context, namedTypeSymbol, rootNamespace);
}
}
}
}


private void Generate(GeneratorExecutionContext context, INamedTypeSymbol integrationConvertTypeSymbol,
string rootNamespace)
{
string className = integrationConvertTypeSymbol.Name;

//根据dbContextType继承的接口IIntegrationEventHandle<TIntegrationEvent> 推断出TIntegrationEvent类型
var convertNamespace = integrationConvertTypeSymbol.ContainingNamespace.ToString();
var usingNamespace = integrationConvertTypeSymbol.ContainingNamespace.ContainingNamespace.ToString();

var iinterface = integrationConvertTypeSymbol.AllInterfaces
.FirstOrDefault(i => i.Name == "IIntegrationEventConvert");
if (iinterface == null)
{
return;
}

var domainEvent = iinterface.TypeArguments[0].Name;

string source = $@"// <auto-generated/>
using {convertNamespace};
using NetCorePal.Extensions.DistributedTransactions;
using NetCorePal.Extensions.Domain;
using {rootNamespace};

namespace {usingNamespace}.DomainEventHandlers
{{
/// <summary>
/// {className}DomainEventHandlers
/// </summary>
public class {className}DomainEventHandler(IIntegrationEventPublisher integrationEventPublisher,
{className} convert) : IDomainEventHandler<{domainEvent}>
santubeikawhi marked this conversation as resolved.
Show resolved Hide resolved
{{
/// <summary>
/// {className}DomainEventHandler
/// </summary>
/// <param name=""notification"">notification</param>
/// <param name=""cancellationToken"">cancellationToken</param>
public async Task Handle({domainEvent} notification, CancellationToken cancellationToken){{
// 发出转移操作集成事件
var integrationEvent = convert.Convert(notification);
await integrationEventPublisher.PublishAsync(integrationEvent, cancellationToken);
}}

}}
}}
";
context.AddSource($"{className}DomainEventHandlers.g.cs", source);
santubeikawhi marked this conversation as resolved.
Show resolved Hide resolved
}

public void Initialize(GeneratorInitializationContext context)
{
// Method intentionally left empty.
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using NetCorePal.Extensions.DistributedTransactions;
using NetCorePal.Web.Application.IntegrationEventHandlers;

namespace NetCorePal.Web.Application.IntegrationConvert;

/// <summary>
/// OrderCreatedIntegrationConvert
/// </summary>
public class OrderCreatedIntegrationConvert : IIntegrationEventConvert<OrderCreatedDomainEvent,OrderPaidIntegrationEvent>
santubeikawhi marked this conversation as resolved.
Show resolved Hide resolved
{
/// <summary>
///
/// </summary>
/// <param name="domainEvent"></param>
/// <returns></returns>
public OrderPaidIntegrationEvent Convert(OrderCreatedDomainEvent domainEvent)
{
return new OrderPaidIntegrationEvent(domainEvent.Order.Id);
}
}
4 changes: 4 additions & 0 deletions test/NetCorePal.Web/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@

builder.Services.AddScoped<OrderQuery>();


typeof(Program).Assembly.GetTypes()
santubeikawhi marked this conversation as resolved.
Show resolved Hide resolved
.Where(p => p.Namespace == "NetCorePal.Web.Application.IntegrationConvert" && p.IsClass && !p.IsAbstract).ToList()
.ForEach(p => { builder.Services.AddScoped(p); });
#region 基础设施

builder.Services.AddContext().AddEnvContext().AddCapContextProcessor();
Expand Down
4 changes: 4 additions & 0 deletions test/NetCorePal.Web/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"profiles": {
"Generators": {
"commandName": "DebugRoslynComponent",
"targetProject": "../NetCorePal.Web/NetCorePal.Web.csproj"
},
"http": {
"commandName": "Project",
"launchBrowser": true,
Expand Down
Loading