3

I'm developing an application which has 2 controllers - an AdminController and a JsonController (based off ControllerBase). The application contains 2 or more self-hosts for the controllers, but only 1 self-host will contain the AdminController - the other hosts will each contain the JsonController only.

I'm trying to use the ControllerFeatureProvider in just one self-host for the moment to disable the AdminController (and leave the JsonController active), however, if I implement this it disables both controllers, i.e. i cannot query either of them. I've confirmed that the IsController is returning true/false for each of the controllers in question. The ControllerFeatureProvider is shown below

public class CustomControllerFeatureProvider : ControllerFeatureProvider
{
    protected override bool IsController(TypeInfo typeInfo)
    {
        if (base.IsController(typeInfo))
        {
            if (typeInfo.Name == nameof(AdminController))
            {
                return false;
            }

            return true;
        }

        return false;
    }
}

And the Startup contents are:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(
                "CorsPolicy",
                builder => builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader());
        });

        services.AddResponseCompression(options =>
        {
            options.Providers.Add<GzipCompressionProvider>();
            options.Providers.Add<BrotliCompressionProvider>();
        });

        services.Configure<GzipCompressionProviderOptions>(options =>
        {
            options.Level = CompressionLevel.Optimal;
        });
        services.Configure<BrotliCompressionProviderOptions>(options =>
        {
            // Found via Fiddler that 'Optimal' is very slow
            options.Level = CompressionLevel.Fastest;
        });
        
        services.AddControllers()
            .ConfigureApplicationPartManager(manager =>
            {
                manager.FeatureProviders.Add(new CustomControllerFeatureProvider());

            })
            .ConfigureApiBehaviorOptions(options =>
            {
                options.SuppressInferBindingSourcesForParameters = true;
                options.SuppressModelStateInvalidFilter = true;

            })
            .AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.DefaultValueHandling = DefaultValueHandling.Ignore;
            });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseResponseCompression();
        app.UseCors("CorsPolicy");
        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(name: "JSON API", pattern: "json", defaults: new { controller = "json" });
        });
    }

I've tried all sorts: removing any other Feature Providers, specifically mapping the route to the JsonController. Am i missing something here?

3
  • what do you mean by self-host which can be multiple? looks like you run multiple instances of your web app, each one has a different configuration (with some controllers enabled/disabled)? For one application I've tried, it seems working to disable/enable specific controllers (of course you need to remove the default ControllerFeatureProvider before adding your custom one, otherwise the default provider will still take effect and enable all controllers). Commented Mar 19, 2021 at 15:14
  • "self-host" wasn't the best description - I'm creating multiple IHosts via the Host.CreateDefaultBuilder(). Each one will have the same JsonController but running on different ports (and through DI using different 'resources'). For now, however, i've just got one and i'm trying to disable the AdminController. I tried removing all other FeatureProviders before adding the new one - but again, neither of the 2 controllers were accessible. Commented Mar 19, 2021 at 15:23
  • Go it! so, the code i found was just removing the ControllerFeatureProviders (and that didn't work), however, i've just cleared everything, i.e. manager.FeatureProviders.Clear() and that now works. My guess is that it wasn't actually clearing everything the first time. Thanks for pointing me in the right direction :) Commented Mar 19, 2021 at 15:33

1 Answer 1

4

Not quite sure what happened, but seems to be working now. As King King mentioned in the comments, you need to clear any existing FeatureProviders (which i did try but to no avail).

The code is now simply:

        services.AddControllers()
            .ConfigureApplicationPartManager(manager =>
            {
                manager.FeatureProviders.Clear();
                manager.FeatureProviders.Add(new CustomControllerFeatureProvider());
            })

And because my IsController method was pretty amateur, this is now:

    protected override bool IsController(TypeInfo typeInfo)
    {
        if (!base.IsController(typeInfo) || typeInfo.Name == nameof(AdminController))
            return false;

        return true;
    }
Sign up to request clarification or add additional context in comments.

3 Comments

I think you should not clear all the feature providers, because they're essential parts of your app. Replace only the ControllerFeatureProvider with your custom one. You can find that instance using LINQ, such as var controllerFeatureProvider = manager.FeatureProviders.OfType<ControllerFeatureProvider>().FirstOrDefault(); manager.FeatureProviders.Remove(controllerFeatureProvider);
That's a fair point - although that's the only item in there at present. Doesn't mean it always will be though so I'll do that - otherwise I'll be wasting a lot of time scratching my head in the future, no doubt.
per my debugging on my side, there are 6 providers, not just 1 controller feature provider. The others are for TagHelperFeatureProvider, ViewsFeatureProvider, ViewComponentFeatureProvider, ...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.