Question: I'm looking for some way to enforce the checking (runtime, of course) of the proper lifetime registration of dependency-injection services, in .Net Core or higher.

Let's say I have a stateful service like this one:

```
public class MyStatefulService
{
    private object _state;
}

```

However, by mistake, I could register it with the wrong lifetime:

```
services.AddTransient<MyStatefulService>();

```

So, I won't be alerted, but the actual behavior is not what I'd expect: the service is created at every request, and the state won't be preserved.

I wonder if there is a way to reinforce this pattern. For instance, it would be nice if I could decorate the class with an attribute like this:

```
[Singleton]
public class MyStatefulService
{
    private object _state;
}

```

at this point, possibily at startup or at the very first request, the framework should throw if the registration is different than `AddSingleton` (along its overloads).

Similarly, the subject could apply for transient-only services, which shouldn't registered as singletons.

The only solution came in my mind is rather naive, and I don't like so much:

```
//line of principle code
public static class MySingletonChecker
{
    private static HashSet<Type> _set = new HashSet<Type>();

    public static void Validate(Type type)
    {
        if (_set.Contains(type))
        {
            throw new Exception();
        }
        else
        {
            _set.Add(type);
        }
    }
}

public class MyStatefulService
{
    public MyStatefulService()
    {
        MySingletonChecker.Validate(this.GetType());
    }

    private object _state;
}

```

Is there any better solution, hack or anything that helps to prevent errors?

Answer: 
If you want to idiot-proof your code, you can provide an extension method to `IServiceCollection` that registers your service exactly the way it should be.

```
public static void AddMyStatefulService(this IServiceCollection services) 
{
    services.AddSingleton<MyStatefulService>();
}

```

Then in your services configuration section, the developer would type:

```
services.AddMyStatefulService();

```
Here's a way like I was pointing out in the comments

Let's have some empty types:

```
public class ScopedService {}
public class TransientService {}

```

Let's have a real service that derives from one of the empty types:

```
public class RealService: ScopedService, IRealService {
  //impl
}

```

And a generic registration method helper:

```
static void MyAddScoped<TService, TImplementation>(IServiceCollection services)
    where TService : class
    where TImplementation : ScopedService, TService 
{
    services.AddScoped<TService, TImplementation>();
}

```

Let's register our realservice using the helper:

```
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
        MyAddScoped<IRealService, RealService>(services);
    }

```

RealService is a ScopedService - think of this as "how you decorate a service to insist it be added as scoped"

Suppose the developer changes the service to be a transient:

```
class RealService: TransientService, IRealService {

```

Now you get a compiler error from the helper method:

> 
> The type 'YourApplication.RealService' cannot be used as type parameter 'TImplementation' in the generic type or method 'Startup.MyAddScoped<TService, TImplementation>(IServiceCollection)'. There is no implicit reference conversion from 'WebApplication1.RealService' to 'WebApplication1.ScopedService'.
> 
> 
> 

Your "one person who looks after registration" can know that the developer is indicating the service is no longer registerable as Scoped and can change it (and the build will be broken until it is changed, which is a good way of preventing accidental release of incorrect code)