Menelaos Vergis Menelaos Vergis - 11 days ago 14
C# Question

Registration of ITagHelperActivator at Simple Injector in ASP.NET Core MVC app

I want to resolve some dependencies at a

TagHelper
and I have read here that I must register the
ITagHelperActivator
interface.

I tried that with the following code:

services.AddSingleton<ITagHelperActivator>(new SimpleInjectorTagHelperActivator(container));


But I get the following error:


ActivationException: The constructor of type UrlResolutionTagHelper
contains the parameter with name 'urlHelperFactory' and type
IUrlHelperFactory that is not registered. Please ensure
IUrlHelperFactory is registered, or change the constructor of
UrlResolutionTagHelper.


When I register
IUrlHelperFactory
with
UrlHelperFactory
then an other dependency is missing and I get an error for that too.

I guess I am doing something wrong, I don't want to register the complete framework.

Answer

This won't work. By replacing the default tag helper activator, you redirected the resolution of all tag helpers to Simple Injector, but apparently, there are built-in tag helpers and they require the built-in container to be resolved.

You should register a tag helper activator that resolves only application components and forwards all other requests back to the built-in DefaultTagHelperActivator. Example:

public class MultipleTagHelperActivator : ITagHelperActivator
{
    private readonly Container container;
    private readonly ITagHelperActivator frameworkActivator;
    private readonly Predicate<Type> useSimpleInjector;

    public MultipleTagHelperActivator(Container container,
        ITagHelperActivator frameworkActivator, Predicate<Type> useSimpleInjector)
    {
        this.container = container;
        this.frameworkActivator = frameworkActivator;
        this.useSimpleInjector = useSimpleInjector;
    }

    public TTagHelper Create<TTagHelper>(ViewContext context) 
        where TTagHelper : ITagHelper =>
        useSimpleInjector(typeof(TTagHelper))
            ? (TTagHelper)this.container.GetInstance(typeof(TTagHelper))
            : this.frameworkActivator.Create<TTagHelper>(context);
}

This is however where it gets really smelly with ASP.NET Core. While previous versions of ASP.NET made it super simple to wrap an original type with a new type (decoration), this same practice has become really painful in ASP.NET Core. I reported this issue a long time ago.

But long story short, you can add your custom activator as follows:

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

    // NOTE: Make this registration AFTER the call to AddMvc
    services.AddSingleton<ITagHelperActivator>(provider =>
        new MultipleTagHelperActivator(
            container,
            new DefaultTagHelperActivator(provider.GetService<ITypeActivatorCache>()),
            useSimpleInjector: type => type.Namespace.StartsWith("MyApplication")));

    // rest of your configuration
}