Skip to content

Commit

Permalink
Add support for Autofac
Browse files Browse the repository at this point in the history
  • Loading branch information
pomianowski committed May 11, 2024
1 parent 79c82cf commit c239b88
Show file tree
Hide file tree
Showing 22 changed files with 314 additions and 54 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/reflection-events-cd-nuget.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,11 @@ jobs:
- name: Build
run: dotnet build src\ReflectionEventing\ReflectionEventing.csproj --configuration Release --no-restore -p:SourceLinkEnabled=true

- name: Build
run: dotnet build src\ReflectionEventing.Autofac\ReflectionEventing.Autofac.csproj --configuration Release --no-restore -p:SourceLinkEnabled=true

- name: Build
run: dotnet build src\ReflectionEventing.DependencyInjection\ReflectionEventing.DependencyInjection.csproj --configuration Release --no-restore -p:SourceLinkEnabled=true

- name: Publish the package to NuGet.org
run: nuget push **\*.nupkg -NonInteractive -SkipDuplicate -Source 'https://api.nuget.org/v3/index.json'
3 changes: 1 addition & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
</PropertyGroup>

<PropertyGroup>
<Version>1.0.0</Version>
<PackageVersion>1.0.0</PackageVersion>
<Version>2.0.0</Version>
</PropertyGroup>

<PropertyGroup>
Expand Down
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<Project>
<ItemGroup>
<PackageVersion Include="Autofac" Version="4.0.0" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageVersion Include="coverlet.collector" Version="6.0.0" />
<PackageVersion Include="FluentAssertions" Version="6.12.0" />
Expand Down
12 changes: 12 additions & 0 deletions ReflectionEventing.sln
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReflectionEventing.Autofac", "src\ReflectionEventing.Autofac\ReflectionEventing.Autofac.csproj", "{6023E50F-2B4D-4315-B85D-9E8A12746045}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReflectionEventing.DependencyInjection", "src\ReflectionEventing.DependencyInjection\ReflectionEventing.DependencyInjection.csproj", "{09F0D6A2-3791-4173-A612-98E6EA92FCC4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -31,6 +35,14 @@ Global
{898865CB-C39C-4E69-9FF8-E96AAD7FF0A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{898865CB-C39C-4E69-9FF8-E96AAD7FF0A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{898865CB-C39C-4E69-9FF8-E96AAD7FF0A4}.Release|Any CPU.Build.0 = Release|Any CPU
{6023E50F-2B4D-4315-B85D-9E8A12746045}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6023E50F-2B4D-4315-B85D-9E8A12746045}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6023E50F-2B4D-4315-B85D-9E8A12746045}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6023E50F-2B4D-4315-B85D-9E8A12746045}.Release|Any CPU.Build.0 = Release|Any CPU
{09F0D6A2-3791-4173-A612-98E6EA92FCC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09F0D6A2-3791-4173-A612-98E6EA92FCC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09F0D6A2-3791-4173-A612-98E6EA92FCC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09F0D6A2-3791-4173-A612-98E6EA92FCC4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
23 changes: 23 additions & 0 deletions src/ReflectionEventing.Autofac/AutofacConsumerProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and ReflectionEventing Contributors.
// All Rights Reserved.

using System;
using System.Collections.Generic;
using Autofac;

namespace ReflectionEventing.Autofac;

public class AutofacConsumerProvider(ILifetimeScope lifetimeScope) : IConsumerProvider
{
public IEnumerable<object> GetConsumerTypes(Type consumerType)
{
if (consumerType is null)
{
throw new ArgumentNullException(nameof(consumerType));
}

return new List<object> { lifetimeScope.Resolve(consumerType) };
}
}
10 changes: 10 additions & 0 deletions src/ReflectionEventing.Autofac/AutofacEventBusBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and ReflectionEventing Contributors.
// All Rights Reserved.

using Autofac;

namespace ReflectionEventing.Autofac;

public class AutofacEventBusBuilder(ContainerBuilder builder) : EventBusBuilder;

Check warning on line 10 in src/ReflectionEventing.Autofac/AutofacEventBusBuilder.cs

View workflow job for this annotation

GitHub Actions / deploy

Parameter 'builder' is unread.

Check warning on line 10 in src/ReflectionEventing.Autofac/AutofacEventBusBuilder.cs

View workflow job for this annotation

GitHub Actions / deploy

Parameter 'builder' is unread.

Check warning on line 10 in src/ReflectionEventing.Autofac/AutofacEventBusBuilder.cs

View workflow job for this annotation

GitHub Actions / deploy

Parameter 'builder' is unread.

Check warning on line 10 in src/ReflectionEventing.Autofac/AutofacEventBusBuilder.cs

View workflow job for this annotation

GitHub Actions / deploy

Parameter 'builder' is unread.

Check warning on line 10 in src/ReflectionEventing.Autofac/AutofacEventBusBuilder.cs

View workflow job for this annotation

GitHub Actions / deploy

Parameter 'builder' is unread.

Check warning on line 10 in src/ReflectionEventing.Autofac/AutofacEventBusBuilder.cs

View workflow job for this annotation

GitHub Actions / deploy

Parameter 'builder' is unread.

Check warning on line 10 in src/ReflectionEventing.Autofac/AutofacEventBusBuilder.cs

View workflow job for this annotation

GitHub Actions / deploy

Parameter 'builder' is unread.

Check warning on line 10 in src/ReflectionEventing.Autofac/AutofacEventBusBuilder.cs

View workflow job for this annotation

GitHub Actions / deploy

Parameter 'builder' is unread.

Check warning on line 10 in src/ReflectionEventing.Autofac/AutofacEventBusBuilder.cs

View workflow job for this annotation

GitHub Actions / deploy

Parameter 'builder' is unread.

Check warning on line 10 in src/ReflectionEventing.Autofac/AutofacEventBusBuilder.cs

View workflow job for this annotation

GitHub Actions / deploy

Parameter 'builder' is unread.
37 changes: 37 additions & 0 deletions src/ReflectionEventing.Autofac/ContainerBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and ReflectionEventing Contributors.
// All Rights Reserved.

using System;
using Autofac;

namespace ReflectionEventing.Autofac;

public static class ContainerBuilderExtensions
{
public static ContainerBuilder AddEventBus(
this ContainerBuilder builder,
Action<EventBusBuilder> configure
)
{
AutofacEventBusBuilder autofacBuilder = new(builder);

configure(autofacBuilder);

_ = builder
.RegisterType<HashedConsumerTypesProvider>()
.As<IConsumerTypesProvider>()
.WithParameter("consumers", autofacBuilder.GetConsumers())
.SingleInstance();

_ = builder
.RegisterType<AutofacConsumerProvider>()
.As<IConsumerProvider>()
.InstancePerLifetimeScope();

_ = builder.RegisterType<EventBus>().As<IEventBus>().InstancePerLifetimeScope();

return builder;
}
}
42 changes: 42 additions & 0 deletions src/ReflectionEventing.Autofac/ReflectionEventing.Autofac.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<PackageId>ReflectionEventing.Autofac</PackageId>
<TargetFrameworks>netstandard2.0;netstandard2.1;net462;net6.0;net8.0</TargetFrameworks>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<IsTrimmable>true</IsTrimmable>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PublishAot>true</PublishAot>
<StripSymbols>true</StripSymbols>
<OptimizationPreference>Speed</OptimizationPreference>
</PropertyGroup>

<!-- Necessary polyfills -->
<PropertyGroup>
<PolySharpIncludeGeneratedTypes>
System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute;
System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute;
System.Diagnostics.CodeAnalysis.MemberNotNullAttribute;
System.Diagnostics.CodeAnalysis.NotNullAttribute;
System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute;
System.Diagnostics.CodeAnalysis.NotNullWhenAttribute;
System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute;
System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute;
System.Runtime.CompilerServices.CallerArgumentExpressionAttribute;
System.Runtime.CompilerServices.IsExternalInit;
System.Runtime.CompilerServices.SkipLocalsInitAttribute;
</PolySharpIncludeGeneratedTypes>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Autofac" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ReflectionEventing\ReflectionEventing.csproj" />
</ItemGroup>

</Project>
1 change: 1 addition & 0 deletions src/ReflectionEventing.Demo.Wpf/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using ReflectionEventing.Demo.Wpf.Services;
using ReflectionEventing.Demo.Wpf.ViewModels;
using ReflectionEventing.DependencyInjection;

namespace ReflectionEventing.Demo.Wpf;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ReflectionEventing\ReflectionEventing.csproj" />
<ProjectReference Include="..\ReflectionEventing.DependencyInjection\ReflectionEventing.DependencyInjection.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and ReflectionEventing Contributors.
// All Rights Reserved.

namespace ReflectionEventing.DependencyInjection;

public class DependencyInjectionConsumerProvider(IServiceProvider serviceProvider)
: IConsumerProvider
{
public IEnumerable<object> GetConsumerTypes(Type consumerType)
{
if (consumerType is null)
{
throw new ArgumentNullException(nameof(consumerType));
}

IServiceScopeFactory? scopeFactory = serviceProvider.GetService<IServiceScopeFactory>();

if (scopeFactory is null)
{
return GetConsumersFromComputedScope(consumerType);
}

return serviceProvider.GetServices(consumerType);
}

private IEnumerable<object> GetConsumersFromComputedScope(Type consumerType)
{
using IServiceScope scope = serviceProvider.CreateScope();
return scope.ServiceProvider.GetServices(consumerType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and ReflectionEventing Contributors.
// All Rights Reserved.

using System.Diagnostics.CodeAnalysis;

namespace ReflectionEventing.DependencyInjection;

public class DependencyInjectionEventBusBuilder(IServiceCollection services) : EventBusBuilder
{
public override void AddConsumer(
#if NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
#endif
Type consumerType
)
{
ServiceDescriptor? descriptor = services.FirstOrDefault(d => d.ServiceType == consumerType);

if (descriptor is null)
{
throw new InvalidOperationException(
"Event consumer must be registered in the service collection."
);
}

if (descriptor.Lifetime == ServiceLifetime.Transient)
{
throw new InvalidOperationException("Transient consumers are not supported.");
}

base.AddConsumer(consumerType);
}
}
11 changes: 11 additions & 0 deletions src/ReflectionEventing.DependencyInjection/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and ReflectionEventing Contributors.
// All Rights Reserved.

global using System;
global using System.Collections.Generic;
global using System.Linq;
global using System.Threading;
global using System.Threading.Tasks;
global using Microsoft.Extensions.DependencyInjection;
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<PackageId>ReflectionEventing.DependencyInjection</PackageId>
<TargetFrameworks>netstandard2.0;netstandard2.1;net462;net6.0;net8.0</TargetFrameworks>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<IsTrimmable>true</IsTrimmable>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PublishAot>true</PublishAot>
<StripSymbols>true</StripSymbols>
<OptimizationPreference>Speed</OptimizationPreference>
</PropertyGroup>

<!-- Necessary polyfills -->
<PropertyGroup>
<PolySharpIncludeGeneratedTypes>
System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute;
System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute;
System.Diagnostics.CodeAnalysis.MemberNotNullAttribute;
System.Diagnostics.CodeAnalysis.NotNullAttribute;
System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute;
System.Diagnostics.CodeAnalysis.NotNullWhenAttribute;
System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute;
System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute;
System.Runtime.CompilerServices.CallerArgumentExpressionAttribute;
System.Runtime.CompilerServices.IsExternalInit;
System.Runtime.CompilerServices.SkipLocalsInitAttribute;
</PolySharpIncludeGeneratedTypes>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ReflectionEventing\ReflectionEventing.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// Copyright (C) Leszek Pomianowski and ReflectionEventing Contributors.
// All Rights Reserved.

namespace ReflectionEventing;
namespace ReflectionEventing.DependencyInjection;

/// <summary>
/// Provides extension methods for the <see cref="IServiceCollection"/> interface.
Expand All @@ -17,21 +17,22 @@ public static class ServiceCollectionExtensions
/// <param name="configure">A delegate that configures the <see cref="EventBusBuilder"/>.</param>
/// <returns>The same service collection so that multiple calls can be chained.</returns>
/// <remarks>
/// This method adds a singleton service of type <see cref="IConsumerProvider"/> that uses a <see cref="StaticConsumerProvider"/> with the consumers from the event bus builder.
/// This method adds a singleton service of type <see cref="IConsumerTypesProvider"/> that uses a <see cref="HashedConsumerTypesProvider"/> with the consumers from the event bus builder.
/// It also adds a scoped service of type <see cref="IEventBus"/> that uses the <see cref="EventBus"/> class.
/// </remarks>
public static IServiceCollection AddEventBus(
this IServiceCollection services,
Action<EventBusBuilder> configure
)
{
EventBusBuilder builder = new(services);
DependencyInjectionEventBusBuilder builder = new(services);

configure(builder);

_ = services.AddSingleton<IConsumerProvider>(
new StaticConsumerProvider(builder.GetConsumers())
_ = services.AddSingleton<IConsumerTypesProvider>(
new HashedConsumerTypesProvider(builder.GetConsumers())
);
_ = services.AddScoped<IConsumerProvider, DependencyInjectionConsumerProvider>();
_ = services.AddScoped<IEventBus, EventBus>();

return services;
Expand Down
Loading

0 comments on commit c239b88

Please sign in to comment.