Robware Software by Rob

Pre-loading dependencies in ASP.NET

I came across a situation where I had some dependencies which needed to run some code at launch. In this instance I wanted to register an event type at the application level for use in validation further down the line.

So achieve this is deceptively simple; we make use of a hosted service and scan our assembly for instances with a certain attribute.

The attribute, which we'll call Preload, doesn't contain any code and is just used to tag a class:

[AttributeUsage(AttributeTargets.Class)]
public class PreloadAttribute : Attribute
{
	
}

Then we use reflection on the start method of our hosted service to find the tagged types and then use the DI framework to get an instance of them:

public class InstantiationService(IServiceProvider serviceProvider) : IHostedService
{
	public Task StartAsync(CancellationToken cancellationToken)
	{
		using var scope = serviceProvider.CreateScope();

		var taggedTypes = AppDomain.CurrentDomain
			.GetAssemblies()
			.SelectMany(assembly =>
			{
				try
				{
					return assembly.GetTypes();
				}
				catch
				{
					return [];
				}
			})
			.Where(type =>
				type.IsClass &&
				!type.IsAbstract &&
				type.GetCustomAttribute<PreloadAttribute>() != null
			);

		foreach (var type in taggedTypes)
		{
			scope.ServiceProvider.GetService(type);
		}

		return Task.CompletedTask;
	}

	public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}

And in our Program.cs file we set it up with builder.Services.AddHostedService<InstantiationService>(); with the rest of our services.

A use case example of this is we have a class which wants to raise events, but we want these events to be strongly typed and scoped then used to validate against requests to subscribe to said events.

[Preload]
public class Thing : IThing
{
	public enum ThingEvents
	{
		Create,
		Update,
		Delete
	}

	private readonly IEvents<ThingEvents> _events;

	public Thing(IEvents<ThingEvents> events)
	{
		_events = events;
	}

	public void DoThing()
	{
		
	}
}
public class Events<T> : IEvents<T> where T : Enum
{
	private readonly IEventRegistry _eventRegistry;

	public Events(IEventRegistry eventRegistry)
	{
		_eventRegistry = eventRegistry;
		RegisterEventType();
	}

	private void RegisterEventType()
	{
		var enumType = typeof(T);
		var enumNames = Enum.GetNames(enumType);
		foreach (var name in enumNames)
		{
			_eventRegistry.RegisterEventType(enumType.Name + "." + name);
		}
	}

	public void Raise(T eventType, object payload)
	{
		
	}
}
public class EventRegistry : IEventRegistry
{
	private readonly List<string> _eventTypes = [];

	public void RegisterEventType(string eventName)
	{
		_eventTypes.Add(eventName);
		Console.WriteLine("Adding "+eventName);
	}

	public bool IsValidEventType(string eventName) => _eventTypes.Contains(eventName);
}
var valid = IsValidEvent("ThingEvents.Create");
Posted on Monday the 12th of January 2026