Skip to content

Commit

Permalink
Merge pull request #11199 from umbraco/register-notification-extension
Browse files Browse the repository at this point in the history
v9: Added Extension method to register all custom Notifications
  • Loading branch information
Zeegaan authored Oct 18, 2021
2 parents 616b577 + 58d980c commit 434ce0f
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 0 deletions.
104 changes: 104 additions & 0 deletions src/Umbraco.Core/Extensions/UmbracoBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Events;

namespace Umbraco.Cms.Core.Extensions
{
public static class UmbracoBuilderExtensions
{
/// <summary>
/// Registers all <see cref="INotificationHandler{TNotification}"/> within an assembly
/// </summary>
/// <param name="self"><see cref="IUmbracoBuilder"/></param>
/// <typeparam name="T">Type contained within the targeted assembly</typeparam>
/// <returns></returns>
public static IUmbracoBuilder AddNotificationsFromAssembly<T>(this IUmbracoBuilder self)
{
AddNotificationHandlers<T>(self);
AddAsyncNotificationHandlers<T>(self);

return self;
}

private static void AddNotificationHandlers<T>(IUmbracoBuilder self)
{
var notificationHandlers = GetNotificationHandlers<T>();
foreach (var notificationHandler in notificationHandlers)
{
var handlerImplementations = GetNotificationHandlerImplementations<T>(notificationHandler);
foreach (var implementation in handlerImplementations)
{
RegisterNotificationHandler(self, implementation, notificationHandler);
}
}
}

private static List<Type> GetNotificationHandlers<T>() =>
typeof(T).Assembly.GetTypes()
.Where(x => x.IsAssignableToGenericType(typeof(INotificationHandler<>)))
.ToList();

private static List<Type> GetNotificationHandlerImplementations<T>(Type handlerType) =>
handlerType
.GetInterfaces()
.Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(INotificationHandler<>))
.ToList();

private static void AddAsyncNotificationHandlers<T>(IUmbracoBuilder self)
{
var notificationHandlers = GetAsyncNotificationHandlers<T>();
foreach (var notificationHandler in notificationHandlers)
{
var handlerImplementations = GetAsyncNotificationHandlerImplementations<T>(notificationHandler);
foreach (var handler in handlerImplementations)
{
RegisterNotificationHandler(self, handler, notificationHandler);
}
}
}

private static List<Type> GetAsyncNotificationHandlers<T>() =>
typeof(T).Assembly.GetTypes()
.Where(x => x.IsAssignableToGenericType(typeof(INotificationAsyncHandler<>)))
.ToList();

private static List<Type> GetAsyncNotificationHandlerImplementations<T>(Type handlerType) =>
handlerType
.GetInterfaces()
.Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(INotificationAsyncHandler<>))
.ToList();

private static void RegisterNotificationHandler(IUmbracoBuilder self, Type notificationHandlerType, Type implementingHandlerType)
{
var descriptor = new UniqueServiceDescriptor(notificationHandlerType, implementingHandlerType, ServiceLifetime.Transient);
if (!self.Services.Contains(descriptor))
{
self.Services.Add(descriptor);
}
}

private static bool IsAssignableToGenericType(this Type givenType, Type genericType)
{
var interfaceTypes = givenType.GetInterfaces();

foreach (var it in interfaceTypes)
{
if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType)
{
return true;
}
}

if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
{
return true;
}

var baseType = givenType.BaseType;
return baseType != null && IsAssignableToGenericType(baseType, genericType);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using AutoFixture.NUnit3;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NUnit.Framework;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Extensions;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.Logging;
using Umbraco.Cms.Core.Notifications;

namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Extensions
{
[TestFixture]
public class UmbracoBuilderExtensionsTests
{
[Test, Customization]
public void AddNotificationsFromAssembly_Should_AddNotificationHandler_To_ServicesCollection(IUmbracoBuilder sut)
{
sut.AddNotificationsFromAssembly<CustomizationAttribute>();

var expectedHandlerType = typeof(INotificationHandler<ContentPublishedNotification>);
var handler = sut.Services.SingleOrDefault(x => x.ServiceType == expectedHandlerType);
Assert.NotNull(handler);
Assert.That(handler.ImplementationType, Is.EqualTo(typeof(StubNotificationHandler)));
}

[Test, Customization]
public void AddNotificationsFromAssembly_Should_AddAsyncNotificationHandler_To_ServicesCollection(IUmbracoBuilder sut)
{
sut.AddNotificationsFromAssembly<CustomizationAttribute>();

var expectedHandlerType = typeof(INotificationAsyncHandler<ContentPublishedNotification>);
var handler = sut.Services.SingleOrDefault(x => x.ServiceType == expectedHandlerType);
Assert.NotNull(handler);
Assert.That(handler.ImplementationType, Is.EqualTo(typeof(StubNotificationHandler)));
}

private class CustomizationAttribute : AutoDataAttribute
{
public CustomizationAttribute() : base(() => {
var fixture = new Fixture();

var stub = new UmbracoBuildStub();
fixture.Inject((IUmbracoBuilder)stub);

return fixture;
}){}
}

private class UmbracoBuildStub : IUmbracoBuilder
{
public IServiceCollection Services { get; }
public IConfiguration Config { get; }
public TypeLoader TypeLoader { get; }
public ILoggerFactory BuilderLoggerFactory { get; }
public IHostingEnvironment BuilderHostingEnvironment { get; }
public IProfiler Profiler { get; }
public AppCaches AppCaches { get; }
public TBuilder WithCollectionBuilder<TBuilder>() where TBuilder : ICollectionBuilder, new() => default;

public UmbracoBuildStub() => Services = new ServiceCollection();

public void Build() {}
}

private class StubNotificationHandler
: INotificationHandler<ContentPublishedNotification>
, INotificationAsyncHandler<ContentPublishedNotification>
{
public void Handle(ContentPublishedNotification notification) { }

public Task HandleAsync(ContentPublishedNotification notification, CancellationToken cancellationToken) => Task.CompletedTask;
}
}
}

0 comments on commit 434ce0f

Please sign in to comment.