Robware Software by Rob

Welcome

Hello, I'm Rob. I'm a senior software engineer at On The Beach. Professionally my focus has been in backend development primarily using C#. In my spare time I spend my time riding bikes or making stuff, typically involving an Arduino.

This website is primarily an outlet for me to write about things which have been technically challenging, either in a professional or personal capacity, though not limited to that.

If you wish to get in contact, then get in touch via my LinkedIn profile.

Latest code commit

Repositoryhomeassistantconfig
Branchmaster
SHAa8029b82c27742b7b1c94ac8da97f99956171c02
MessageSwap out heating on and off automations for single call for heat automation using template
Timestamp06:45:19 on Saturday the 17th of January 2026

Latest Blog Post

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

View more