Assembly Markers
Assembly markers are just “dummy” types you create to easily refer to an assembly in a safe, refactor-friendly way.
They’re super handy in multi-project / Clean Architecture .NET solutions when you want to:
Scan assemblies (Scrutor, MediatR, AutoMapper, FluentValidation, etc.)
Load embedded resources
Keep dependencies directional and explicit
Let’s walk through what they are and how you actually use them in a .NET 10 / C# 10 solution.
1. What is an “assembly marker”?
An assembly marker is usually:
An empty class, or
An empty interface, or
A static class
whose only job is to give you a strongly-typed way to get its assembly:
var assembly = typeof(MyAssemblyMarker).Assembly;
Instead of doing things like:
var assembly = typeof(SomeRandomKnownTypeInThisAssembly).Assembly;
…which is brittle, unclear, and annoying to change later.
2. Typical project layout with markers
Say you have a Clean Architecture style solution:
MyApp.DomainMyApp.ApplicationMyApp.InfrastructureMyApp.Web(API / UI)
You can add one marker per project.
MyApp.Domain – DomainAssemblyMarker.cs
namespace MyApp.Domain;
// File-scoped namespace; marker is empty
public sealed class DomainAssemblyMarker
{
}
MyApp.Application – ApplicationAssemblyMarker.cs
namespace MyApp.Application;
public sealed class ApplicationAssemblyMarker
{
}
MyApp.Infrastructure – InfrastructureAssemblyMarker.cs
namespace MyApp.Infrastructure;
public sealed class InfrastructureAssemblyMarker
{
}
MyApp.Web – WebAssemblyMarker.cs
namespace MyApp.Web;
public sealed class WebAssemblyMarker
{
}
Now any other project can get that assembly via typeof(WhateverAssemblyMarker).Assembly without needing to know about “some concrete type that happens to live there”.
3. Usage Example #1 – Registering MediatR by assembly
Goal: Register all MediatR handlers from the Application layer.
In MyApp.Web / Program.cs:
using MyApp.Application;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(typeof(ApplicationAssemblyMarker).Assembly);
});
var app = builder.Build();
// ...
app.Run();
Here:
typeof(ApplicationAssemblyMarker).Assemblygives you the Application project’s assembly.You don’t need to pick a handler class as the “anchor type”.
4. Usage Example #2 – AutoMapper configuration from a layer
Goal: Scan all AutoMapper profiles in Application.
using MyApp.Application;
// ...
builder.Services.AddAutoMapper(typeof(ApplicationAssemblyMarker).Assembly);
If later you move Profiles between folders/namespaces, this keeps working as long as the assembly marker stays in that project.
5. Usage Example #3 – Scrutor scanning for DI
Assembly markers shine with Scrutor (or any reflection-based DI scanning).
Suppose we want:
Classes ending with
ServiceinApplicationRegistered as
ImplementedInterfacesScoped lifetime
In Program.cs of MyApp.Web:
using MyApp.Application;
using MyApp.Infrastructure;
using Scrutor;
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
services.Scan(scan => scan
.FromAssemblies(
typeof(ApplicationAssemblyMarker).Assembly,
typeof(InfrastructureAssemblyMarker).Assembly)
.AddClasses(classes => classes
.InNamespaces("MyApp.Application.Services")
.Where(type => type.Name.EndsWith("Service")))
.AsImplementedInterfaces()
.WithScopedLifetime());
Key bits:
FromAssemblies(...)uses the markers, not a random “known type”.If you rename a class or move it to another folder, the scan still works.
6. Usage Example #4 – FluentValidation registration
using FluentValidation;
using MyApp.Application;
builder.Services.AddValidatorsFromAssembly(
typeof(ApplicationAssemblyMarker).Assembly);
Again, we’re telling FluentValidation: “scan this assembly”, anchored on the marker.
7. Usage Example #5 – Embedded resources
Assembly markers are also useful whenever you need Assembly to load resources.
using System.Reflection;
using MyApp.Infrastructure;
public sealed class SqlScriptLoader
{
public string LoadInitScript()
{
var assembly = typeof(InfrastructureAssemblyMarker).Assembly;
using var stream = assembly.GetManifestResourceStream(
"MyApp.Infrastructure.Scripts.InitDatabase.sql");
if (stream is null)
throw new InvalidOperationException("Embedded SQL script not found.");
using var reader = new StreamReader(stream);
return reader.ReadToEnd();
}
}
You never have to guess which assembly the resource lives in; you’ve anchored it to the marker.
8. Why not just use Assembly.GetExecutingAssembly()?
Because:
In ASP.NET / worker services, the executing assembly may not be the one you want.
If code moves into a shared library, executing/entry assembly changes.
Markers let you refer directly to the correct assembly with compile-time safety.
Assembly marker pattern:
Is explicit
Survives refactors (namespaces/classnames can safely change elsewhere)
Matches Clean Architecture layering (each project “exports” a single known anchor type)
9. Marker as interface vs class vs static class
You’ll see variations:
Empty class (most common)
public sealed class ApplicationAssemblyMarker
{
}
Pros: trivial, can’t be implemented anywhere else.
Interface
public interface IApplicationAssemblyMarker
{
}
Then you have a single class implementing it, and reference that type. Slightly more ceremony; sometimes used when people also use the interface as a “semantic marker” for types within the assembly.
Static class
public static class ApplicationAssemblyMarker
{
}
Also fine; you just need a Type, so any type works.
TL;DR: use a sealed empty class per assembly; it’s simple and clear.
10. Putting it together – Clean Architecture + markers
Quick mental model for your .NET 10 solution:
Domain: core entities, value objects, domain events
→DomainAssemblyMarkerApplication: use cases, commands, queries, validators, mapping profiles
→ApplicationAssemblyMarkerInfrastructure: EF Core, external APIs, implementations
→InfrastructureAssemblyMarkerWeb: controllers, endpoints, DI composition root
→WebAssemblyMarker(optional, but nice for consistency)
Then in Web (or whatever is your composition root):
builder.Services
.AddMediatR(cfg =>
cfg.RegisterServicesFromAssembly(typeof(ApplicationAssemblyMarker).Assembly))
.AddAutoMapper(typeof(ApplicationAssemblyMarker).Assembly)
.AddValidatorsFromAssembly(typeof(ApplicationAssemblyMarker).Assembly);
builder.Services.Scan(scan => scan
.FromAssemblies(
typeof(ApplicationAssemblyMarker).Assembly,
typeof(InfrastructureAssemblyMarker).Assembly)
.AddClasses()
.AsImplementedInterfaces()
.WithScopedLifetime());
That’s the practical, idiomatic way to use assembly markers in a modern C# 10 / .NET 10 project.
#dotnet #csharp #dotnet10