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

1.0.64 preview 1 #195

Merged
merged 10 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create --generate-notes ${{ env.ReleaseVersion }}
gh release create ${{ env.ReleaseVersion }} --generate-notes --target ${{ env.GITHUB_SHA }} ./artifacts/packages/*.nupkg
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

[![WeihanLi.Common Latest](https://img.shields.io/nuget/vpre/WeihanLi.Common)](https://www.nuget.org/packages/WeihanLi.Common/absoluteLatest)

[![Azure Pipelines Build Status](https://weihanli.visualstudio.com/Pipelines/_apis/build/status/WeihanLi.WeihanLi.Common?branchName=dev)](https://weihanli.visualstudio.com/Pipelines/_build/latest?definitionId=16&branchName=dev)
[![Azure Pipelines Build Status](https://weihanli.visualstudio.com/Pipelines/_apis/build/status/WeihanLi.WeihanLi.Common?branchName=master)](https://weihanli.visualstudio.com/Pipelines/_build/latest?definitionId=16&branchName=master)

[![Github Actions Build Status](https://github.com/WeihanLi/WeihanLi.Common/actions/workflows/default.yml/badge.svg)](https://github.com/WeihanLi/WeihanLi.Common/actions/workflows/default.yml)

Expand Down
2 changes: 1 addition & 1 deletion build/version.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<VersionPatch>63</VersionPatch>
<VersionPatch>64</VersionPatch>
<VersionPrefix>$(VersionMajor).$(VersionMinor).$(VersionPatch)</VersionPrefix>
</PropertyGroup>
</Project>
5 changes: 2 additions & 3 deletions samples/AspNetCoreSample/Events/EventConsumer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@
{
await queues.Select(async q =>
{
var @event = await _eventQueue.DequeueAsync(q);
if (null != @event)
if (await _eventQueue.TryDequeueAsync(q, out var @event, out var properties))
{
var handlers = _eventHandlerFactory.GetHandlers(@event.GetType());

Check warning on line 24 in samples/AspNetCoreSample/Events/EventConsumer.cs

View workflow job for this annotation

GitHub Actions / Running tests on ubuntu-latest

Dereference of a possibly null reference.

Check warning on line 24 in samples/AspNetCoreSample/Events/EventConsumer.cs

View workflow job for this annotation

GitHub Actions / Running tests on ubuntu-latest

Dereference of a possibly null reference.

Check warning on line 24 in samples/AspNetCoreSample/Events/EventConsumer.cs

View workflow job for this annotation

GitHub Actions / Running tests on macOS-latest

Dereference of a possibly null reference.

Check warning on line 24 in samples/AspNetCoreSample/Events/EventConsumer.cs

View workflow job for this annotation

GitHub Actions / Running tests on macOS-latest

Dereference of a possibly null reference.

Check warning on line 24 in samples/AspNetCoreSample/Events/EventConsumer.cs

View workflow job for this annotation

GitHub Actions / Running tests on windows-latest

Dereference of a possibly null reference.

Check warning on line 24 in samples/AspNetCoreSample/Events/EventConsumer.cs

View workflow job for this annotation

GitHub Actions / Running tests on windows-latest

Dereference of a possibly null reference.
if (handlers.Count > 0)
{
await handlers
.Select(h => h.Handle(@event))
.Select(h => h.Handle(@event, properties))

Check warning on line 28 in samples/AspNetCoreSample/Events/EventConsumer.cs

View workflow job for this annotation

GitHub Actions / Running tests on ubuntu-latest

Possible null reference argument for parameter 'properties' in 'Task IEventHandler.Handle(object eventData, EventProperties properties)'.

Check warning on line 28 in samples/AspNetCoreSample/Events/EventConsumer.cs

View workflow job for this annotation

GitHub Actions / Running tests on ubuntu-latest

Possible null reference argument for parameter 'properties' in 'Task IEventHandler.Handle(object eventData, EventProperties properties)'.

Check warning on line 28 in samples/AspNetCoreSample/Events/EventConsumer.cs

View workflow job for this annotation

GitHub Actions / Running tests on macOS-latest

Possible null reference argument for parameter 'properties' in 'Task IEventHandler.Handle(object eventData, EventProperties properties)'.

Check warning on line 28 in samples/AspNetCoreSample/Events/EventConsumer.cs

View workflow job for this annotation

GitHub Actions / Running tests on macOS-latest

Possible null reference argument for parameter 'properties' in 'Task IEventHandler.Handle(object eventData, EventProperties properties)'.

Check warning on line 28 in samples/AspNetCoreSample/Events/EventConsumer.cs

View workflow job for this annotation

GitHub Actions / Running tests on windows-latest

Possible null reference argument for parameter 'properties' in 'Task IEventHandler.Handle(object eventData, EventProperties properties)'.

Check warning on line 28 in samples/AspNetCoreSample/Events/EventConsumer.cs

View workflow job for this annotation

GitHub Actions / Running tests on windows-latest

Possible null reference argument for parameter 'properties' in 'Task IEventHandler.Handle(object eventData, EventProperties properties)'.
.WhenAll()
;
}
Expand Down
4 changes: 2 additions & 2 deletions samples/AspNetCoreSample/Events/PageViewEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace AspNetCoreSample.Events;

public class PageViewEvent : EventBase
public class PageViewEvent
{
public string? Path { get; set; }
}
Expand All @@ -11,7 +11,7 @@ public class PageViewEventHandler : EventHandlerBase<PageViewEvent>
{
public static int Count;

public override Task Handle(PageViewEvent @event)
public override Task Handle(PageViewEvent @event, EventProperties eventProperties)
{
Interlocked.Increment(ref Count);
return Task.CompletedTask;
Expand Down
6 changes: 3 additions & 3 deletions samples/AspNetCoreSample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,16 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
}

// pageView middleware
app.Use((context, next) =>
app.Use(async (context, next) =>
{
var eventPublisher = context.RequestServices
.GetRequiredService<IEventPublisher>();
eventPublisher.Publish(new PageViewEvent()
await eventPublisher.PublishAsync(new PageViewEvent()
{
Path = context.Request.Path.Value ?? "",
});

return next();
await next();
});
app.UseHttpLogging();
app.UseRouting();
Expand Down
10 changes: 5 additions & 5 deletions samples/DotNetCoreSample/EventTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace DotNetCoreSample;

internal class EventTest
{
public static void MainTest()
public static async Task MainTest()
{
var eventBus = DependencyResolver.ResolveRequiredService<IEventBus>();

Expand All @@ -18,11 +18,11 @@ public static void MainTest()
eventBus.Subscribe<CounterEvent, CounterEventHandler2>();
eventBus.Subscribe<CounterEvent, DelegateEventHandler<CounterEvent>>(); // could be used for eventLogging

eventBus.Publish(new CounterEvent { Counter = 1 });
await eventBus.PublishAsync(new CounterEvent { Counter = 1 });

eventBus.UnSubscribe<CounterEvent, CounterEventHandler1>();
// eventBus.Unsubscribe<CounterEvent, DelegateEventHandler<CounterEvent>>();
eventBus.Publish(new CounterEvent { Counter = 2 });
await eventBus.PublishAsync(new CounterEvent { Counter = 2 });
}
}

Expand All @@ -33,7 +33,7 @@ public class CounterEvent : EventBase

internal class CounterEventHandler1 : EventHandlerBase<CounterEvent>
{
public override Task Handle(CounterEvent @event)
public override Task Handle(CounterEvent @event, EventProperties eventProperties)
{
LogHelper.GetLogger<CounterEventHandler1>().Info($"Event Info: {@event.ToJson()}, Handler Type:{GetType().FullName}");
return Task.CompletedTask;
Expand All @@ -42,7 +42,7 @@ public override Task Handle(CounterEvent @event)

internal class CounterEventHandler2 : EventHandlerBase<CounterEvent>
{
public override Task Handle(CounterEvent @event)
public override Task Handle(CounterEvent @event, EventProperties eventProperties)
{
LogHelper.GetLogger<CounterEventHandler2>().Info($"Event Info: {@event.ToJson()}, Handler Type:{GetType().FullName}");
return Task.CompletedTask;
Expand Down
36 changes: 24 additions & 12 deletions src/WeihanLi.Common/Event/DelegateEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,43 @@

namespace WeihanLi.Common.Event;

public static class DelegateEventHandler
{
public static DelegateEventHandler<TEvent> FromAction<TEvent>(Action<TEvent> action) where TEvent : class, IEventBase => new(action);

public static DelegateEventHandler<TEvent> FromFunc<TEvent>(Func<TEvent, Task> func) where TEvent : class, IEventBase => new(func);
}

public sealed class DelegateEventHandler<TEvent> : EventHandlerBase<TEvent>
where TEvent : class, IEventBase
{
private readonly Func<TEvent, Task> _func;
private readonly Func<TEvent, EventProperties, Task> _func;

public DelegateEventHandler(Action<TEvent> action)
{
Guard.NotNull(action);
_func = action.WrapTask();
_func = (e, _) =>
{
action(e);
return Task.CompletedTask;
};
}

public DelegateEventHandler(Action<TEvent, EventProperties> action)
{
Guard.NotNull(action);
_func = (e, properties) =>
{
action(e, properties);
return Task.CompletedTask;
};
}

public DelegateEventHandler(Func<TEvent, Task> func)
{
Guard.NotNull(func);
_func = (e, _) => func(e);
}

public DelegateEventHandler(Func<TEvent, EventProperties, Task> func)
{
_func = Guard.NotNull(func);
}

public override Task Handle(TEvent @event)
public override Task Handle(TEvent @event, EventProperties properties)
{
return _func.Invoke(@event);
return _func.Invoke(@event, properties);
}
}
13 changes: 13 additions & 0 deletions src/WeihanLi.Common/Event/EventBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@ protected EventBase(string eventId, DateTimeOffset eventAt)
}
}

internal interface IEventWrapper
{
EventProperties Properties { get; }
object Data { get; }
}

internal sealed class EventWrapper<T> : IEventWrapper
{
public required T Data { get; init; }
object IEventWrapper.Data => Data!;
public required EventProperties Properties { get; init; }
}

public static class EventBaseExtensions
{
private static readonly JsonSerializerSettings EventSerializerSettings = JsonSerializeExtension.SerializerSettingsWith(s =>
Expand Down
40 changes: 17 additions & 23 deletions src/WeihanLi.Common/Event/EventBus.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Weihan Li. All rights reserved.
// Licensed under the Apache license.

using System.Diagnostics;
using WeihanLi.Common.Helpers;
using WeihanLi.Common.Logging;
using WeihanLi.Extensions;

Expand All @@ -16,38 +18,29 @@ public sealed class EventBus(IEventSubscriptionManager subscriptionManager, IEve
private readonly IEventSubscriptionManager _subscriptionManager = subscriptionManager;
private readonly IEventHandlerFactory _eventHandlerFactory = eventHandlerFactory;

public bool Publish<TEvent>(TEvent @event) where TEvent : class, IEventBase
public async Task<bool> PublishAsync<TEvent>(TEvent @event, EventProperties? properties)
{
var handlers = _eventHandlerFactory.GetHandlers<TEvent>();
if (handlers.Count > 0)
properties ??= new();
if (string.IsNullOrEmpty(properties.EventId))
{
var handlerTasks = new Task[handlers.Count];

handlers.ForEach((handler, index) =>
{
handlerTasks[index] = handler.Handle(@event).ContinueWith(r =>
{
Logger.Error(r.Exception?.Unwrap(),
$"handle event [{typeof(TEvent).FullName}] error, eventHandlerType:{handler.GetType().FullName}");
}, TaskContinuationOptions.OnlyOnFaulted);
});

_ = handlerTasks.WhenAllSafely().ConfigureAwait(false);

return true;
properties.EventId = Guid.NewGuid().ToString();
}
if (properties.EventAt == default)
{
properties.EventAt = DateTimeOffset.Now;
}
using var activity = DiagnosticHelper.ActivitySource.StartActivity();
if (string.IsNullOrEmpty(properties.TraceId) && Activity.Current != null)
{
properties.TraceId = Activity.Current.TraceId.ToString();
}
return false;
}

public async Task<bool> PublishAsync<TEvent>(TEvent @event) where TEvent : class, IEventBase
{
var handlers = _eventHandlerFactory.GetHandlers<TEvent>();
if (handlers.Count > 0)
{
var handlerTasks = new Task[handlers.Count];
handlers.ForEach((handler, index) =>
{
handlerTasks[index] = handler.Handle(@event).ContinueWith(r =>
handlerTasks[index] = handler.Handle(@event, properties).ContinueWith(r =>
{
Logger.Error(r.Exception?.Unwrap(),
$"handle event [{typeof(TEvent).FullName}] error, eventHandlerType:{handler.GetType().FullName}");
Expand All @@ -63,6 +56,7 @@ public async Task<bool> PublishAsync<TEvent>(TEvent @event) where TEvent : class
public bool Subscribe(Type eventType, Type eventHandlerType) => _subscriptionManager.Subscribe(eventType, eventHandlerType);

public Task<bool> SubscribeAsync(Type eventType, Type eventHandlerType) => _subscriptionManager.SubscribeAsync(eventType, eventHandlerType);
public Task<bool> SubscribeAsync<TEvent>(IEventHandler<TEvent> eventHandler) => _subscriptionManager.SubscribeAsync(eventHandler);

public bool UnSubscribe(Type eventType, Type eventHandlerType) => _subscriptionManager.UnSubscribe(eventType, eventHandlerType);

Expand Down
12 changes: 6 additions & 6 deletions src/WeihanLi.Common/Event/EventBusExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using WeihanLi.Extensions;

namespace WeihanLi.Common.Event;

Expand Down Expand Up @@ -36,15 +37,15 @@ public static IEventBuilder AddEvents(this IServiceCollection services)
}

public static IEventBuilder AddEventHandler<TEvent, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TEventHandler>(this IEventBuilder eventBuilder, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
where TEvent : class, IEventBase
where TEvent : class
where TEventHandler : class, IEventHandler<TEvent>
{
eventBuilder.Services.TryAddEnumerable(new ServiceDescriptor(typeof(IEventHandler<TEvent>), typeof(TEventHandler), serviceLifetime));
return eventBuilder;
}

public static IEventBuilder AddEventHandler<TEvent>(this IEventBuilder eventBuilder, IEventHandler<TEvent> eventHandler)
where TEvent : class, IEventBase
where TEvent : class
{
eventBuilder.Services.TryAddEnumerable(new ServiceDescriptor(typeof(IEventHandler<TEvent>), eventHandler));
return eventBuilder;
Expand All @@ -53,8 +54,7 @@ public static IEventBuilder AddEventHandler<TEvent>(this IEventBuilder eventBuil
[RequiresUnreferencedCode("Assembly.GetTypes() requires unreferenced code")]
public static IEventBuilder RegisterEventHandlers(this IEventBuilder builder, Func<Type, bool>? filter = null, ServiceLifetime serviceLifetime = ServiceLifetime.Singleton, params Assembly[] assemblies)
{
Guard.NotNull(assemblies, nameof(assemblies));
if (assemblies.Length == 0)
if (assemblies.IsNullOrEmpty())
{
assemblies = Helpers.ReflectHelper.GetAssemblies();
}
Expand All @@ -67,12 +67,12 @@ public static IEventBuilder RegisterEventHandlers(this IEventBuilder builder, Fu
{
handlerTypes = handlerTypes.Where(filter);
}

foreach (var handlerType in handlerTypes)
{
foreach (var implementedInterface in handlerType.GetTypeInfo().ImplementedInterfaces)
{
if (implementedInterface.IsGenericType && typeof(IEventBase).IsAssignableFrom(implementedInterface.GenericTypeArguments[0]))
if (implementedInterface.IsGenericType && typeof(IEventHandler<>) == implementedInterface.GetGenericTypeDefinition())
{
builder.Services.TryAddEnumerable(new ServiceDescriptor(implementedInterface, handlerType, serviceLifetime));
}
Expand Down
31 changes: 15 additions & 16 deletions src/WeihanLi.Common/Event/EventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,40 @@ namespace WeihanLi.Common.Event;

public interface IEventHandler
{
Task Handle(object eventData);
Task Handle(object eventData, EventProperties properties);
}

public interface IEventHandler<in TEvent> : IEventHandler where TEvent : class, IEventBase
public interface IEventHandler<in TEvent> : IEventHandler
{
/// <summary>
/// Handler event
/// </summary>
/// <param name="event">event</param>
Task Handle(TEvent @event);
/// <param name="properties">eventProperties</param>
Task Handle(TEvent @event, EventProperties properties);
}

public abstract class EventHandlerBase<TEvent> : IEventHandler<TEvent> where TEvent : class, IEventBase
public abstract class EventHandlerBase<TEvent> : IEventHandler<TEvent>
{
public abstract Task Handle(TEvent @event);
public abstract Task Handle(TEvent @event, EventProperties eventProperties);

public virtual Task Handle(object eventData)
public virtual Task Handle(object eventData, EventProperties properties)
{
Guard.NotNull(eventData);

switch (eventData)
{
case TEvent data:
return Handle(data);
return Handle(data, properties);

case JObject jObject:
{
var @event = jObject.ToObject<TEvent>();
if (@event != null)
{
return Handle(@event);
}
break;
}
var @event = jObject.ToObject<TEvent>();
if (@event != null)
return Handle(@event, properties);
break;

case string eventDataJson:
return Handle(eventDataJson.JsonToObject<TEvent>());
return Handle(eventDataJson.JsonToObject<TEvent>(), properties);
}

throw new ArgumentException(@$"Unsupported event DataType:{eventData.GetType()}", nameof(eventData));
Expand Down
Loading