Skip to content

Instantly share code, notes, and snippets.

@alistairjevans
Created February 19, 2020 12:49
Show Gist options
  • Save alistairjevans/e670568a7e929e815ee1591feef53e6f to your computer and use it in GitHub Desktop.
Save alistairjevans/e670568a7e929e815ee1591feef53e6f to your computer and use it in GitHub Desktop.
Single Registration Protections
using Autofac;
using Autofac.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using Xunit;
namespace PreventDuplicateSingletons
{
public class SingleRegistrationServices
{
private static readonly HashSet<Type> servicesThatOnlyAllowOneRegistration = new HashSet<Type>
{
typeof(HttpClient)
};
private readonly HashSet<Type> servicesAlreadyRegistered = new HashSet<Type>();
public void ServiceRegistered(object sender, ComponentRegisteredEventArgs e)
{
// Get the typed services in the registration.
var typedServices = e.ComponentRegistration.Services.OfType<TypedService>();
foreach (var service in typedServices)
{
// Is this service type in our list of 'protected' types?
if(servicesThatOnlyAllowOneRegistration.Contains(service.ServiceType))
{
// If we cannot add it to the set we've already registered,
// it means we have already seen it.
if(!servicesAlreadyRegistered.Add(service.ServiceType))
{
throw new InvalidOperationException($"Detected invalid double-registration of {service.ServiceType.Name}");
}
}
}
}
}
public class PreventDuplicateServicesTests
{
[Fact]
public void ThrowsOnDuplicateService()
{
var builder = new ContainerBuilder();
var singleAssertions = new SingleRegistrationServices();
builder.RegisterCallback(regBuilder => regBuilder.Registered += singleAssertions.ServiceRegistered);
var httpClient1 = new HttpClient();
var httpClient2 = new HttpClient();
builder.RegisterInstance(httpClient1);
builder.RegisterInstance(httpClient2);
Assert.Throws<InvalidOperationException>(() =>
{
builder.Build();
});
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment