Skip to content

Commit 649d7fd

Browse files
committed
Added UmbracoBuilderExtensions.AddNotificationsFromAssembly to help all notifications from within an Assembly
1 parent 5bfab13 commit 649d7fd

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Microsoft.Extensions.DependencyInjection;
5+
using Umbraco.Cms.Core.DependencyInjection;
6+
using Umbraco.Cms.Core.Events;
7+
8+
namespace Umbraco.Cms.Core.Extensions
9+
{
10+
public static class UmbracoBuilderExtensions
11+
{
12+
/// <summary>
13+
/// Registers all <see cref="INotificationHandler{TNotification}"/> within an assembly
14+
/// </summary>
15+
/// <param name="self"><see cref="IUmbracoBuilder"/></param>
16+
/// <typeparam name="T">Type contained within the targeted assembly</typeparam>
17+
/// <returns></returns>
18+
public static IUmbracoBuilder AddNotificationsFromAssembly<T>(this IUmbracoBuilder self)
19+
{
20+
AddNotificationHandlers<T>(self);
21+
AddAsyncNotificationHandlers<T>(self);
22+
23+
return self;
24+
}
25+
26+
private static void AddNotificationHandlers<T>(IUmbracoBuilder self)
27+
{
28+
var notificationHandlers = GetNotificationHandlers<T>();
29+
foreach (var notificationHandler in notificationHandlers)
30+
{
31+
var handlerImplementations = GetNotificationHandlerImplementations<T>(notificationHandler);
32+
foreach (var implementation in handlerImplementations)
33+
{
34+
RegisterNotificationHandler(self, implementation, notificationHandler);
35+
}
36+
}
37+
}
38+
39+
private static List<Type> GetNotificationHandlers<T>() =>
40+
typeof(T).Assembly.GetTypes()
41+
.Where(x => x.IsAssignableToGenericType(typeof(INotificationHandler<>)))
42+
.ToList();
43+
44+
private static List<Type> GetNotificationHandlerImplementations<T>(Type handlerType) =>
45+
handlerType
46+
.GetInterfaces()
47+
.Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(INotificationHandler<>))
48+
.ToList();
49+
50+
private static void AddAsyncNotificationHandlers<T>(IUmbracoBuilder self)
51+
{
52+
var notificationHandlers = GetAsyncNotificationHandlers<T>();
53+
foreach (var notificationHandler in notificationHandlers)
54+
{
55+
var handlerImplementations = GetAsyncNotificationHandlerImplementations<T>(notificationHandler);
56+
foreach (var handler in handlerImplementations)
57+
{
58+
RegisterNotificationHandler(self, handler, notificationHandler);
59+
}
60+
}
61+
}
62+
63+
private static List<Type> GetAsyncNotificationHandlers<T>() =>
64+
typeof(T).Assembly.GetTypes()
65+
.Where(x => x.IsAssignableToGenericType(typeof(INotificationAsyncHandler<>)))
66+
.ToList();
67+
68+
private static List<Type> GetAsyncNotificationHandlerImplementations<T>(Type handlerType) =>
69+
handlerType
70+
.GetInterfaces()
71+
.Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(INotificationAsyncHandler<>))
72+
.ToList();
73+
74+
private static void RegisterNotificationHandler(IUmbracoBuilder self, Type notificationHandlerType, Type implementingHandlerType)
75+
{
76+
var descriptor = new UniqueServiceDescriptor(notificationHandlerType, implementingHandlerType, ServiceLifetime.Transient);
77+
if (!self.Services.Contains(descriptor))
78+
{
79+
self.Services.Add(descriptor);
80+
}
81+
}
82+
83+
private static bool IsAssignableToGenericType(this Type givenType, Type genericType)
84+
{
85+
var interfaceTypes = givenType.GetInterfaces();
86+
87+
foreach (var it in interfaceTypes)
88+
{
89+
if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType)
90+
return true;
91+
}
92+
93+
if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
94+
return true;
95+
96+
var baseType = givenType.BaseType;
97+
return baseType != null && IsAssignableToGenericType(baseType, genericType);
98+
}
99+
}
100+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using System.Linq;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
using AutoFixture;
5+
using AutoFixture.NUnit3;
6+
using Microsoft.Extensions.Configuration;
7+
using Microsoft.Extensions.DependencyInjection;
8+
using Microsoft.Extensions.Logging;
9+
using NUnit.Framework;
10+
using Umbraco.Cms.Core.Cache;
11+
using Umbraco.Cms.Core.Composing;
12+
using Umbraco.Cms.Core.DependencyInjection;
13+
using Umbraco.Cms.Core.Events;
14+
using Umbraco.Cms.Core.Extensions;
15+
using Umbraco.Cms.Core.Hosting;
16+
using Umbraco.Cms.Core.Logging;
17+
using Umbraco.Cms.Core.Notifications;
18+
19+
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Extensions
20+
{
21+
[TestFixture]
22+
public class UmbracoBuilderExtensionsTests
23+
{
24+
[Test, Customization]
25+
public void AddNotificationsFromAssembly_Should_AddNotificationHandler_To_ServicesCollection(IUmbracoBuilder sut)
26+
{
27+
sut.AddNotificationsFromAssembly<CustomizationAttribute>();
28+
29+
var expectedHandlerType = typeof(INotificationHandler<ContentPublishedNotification>);
30+
var handler = sut.Services.SingleOrDefault(x => x.ServiceType == expectedHandlerType);
31+
Assert.NotNull(handler);
32+
Assert.That(handler.ImplementationType, Is.EqualTo(typeof(StubNotificationHandler)));
33+
}
34+
35+
[Test, Customization]
36+
public void AddNotificationsFromAssembly_Should_AddAsyncNotificationHandler_To_ServicesCollection(IUmbracoBuilder sut)
37+
{
38+
sut.AddNotificationsFromAssembly<CustomizationAttribute>();
39+
40+
var expectedHandlerType = typeof(INotificationAsyncHandler<ContentPublishedNotification>);
41+
var handler = sut.Services.SingleOrDefault(x => x.ServiceType == expectedHandlerType);
42+
Assert.NotNull(handler);
43+
Assert.That(handler.ImplementationType, Is.EqualTo(typeof(StubNotificationHandler)));
44+
}
45+
46+
private class CustomizationAttribute : AutoDataAttribute
47+
{
48+
public CustomizationAttribute() : base(() => {
49+
var fixture = new Fixture();
50+
51+
var stub = new UmbracoBuildStub();
52+
fixture.Inject((IUmbracoBuilder)stub);
53+
54+
return fixture;
55+
}){}
56+
}
57+
58+
private class UmbracoBuildStub : IUmbracoBuilder
59+
{
60+
public IServiceCollection Services { get; }
61+
public IConfiguration Config { get; }
62+
public TypeLoader TypeLoader { get; }
63+
public ILoggerFactory BuilderLoggerFactory { get; }
64+
public IHostingEnvironment BuilderHostingEnvironment { get; }
65+
public IProfiler Profiler { get; }
66+
public AppCaches AppCaches { get; }
67+
public TBuilder WithCollectionBuilder<TBuilder>() where TBuilder : ICollectionBuilder, new() => default;
68+
69+
public UmbracoBuildStub() => Services = new ServiceCollection();
70+
71+
public void Build() {}
72+
}
73+
74+
private class StubNotificationHandler
75+
: INotificationHandler<ContentPublishedNotification>
76+
, INotificationAsyncHandler<ContentPublishedNotification>
77+
{
78+
public void Handle(ContentPublishedNotification notification) { }
79+
80+
public Task HandleAsync(ContentPublishedNotification notification, CancellationToken cancellationToken) => Task.CompletedTask;
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)