DEV Community

Dennis
Dennis

Posted on

How to register internal controllers in Umbraco 13+

In this short tutorial, I will show you how to register a controller from a package that is marked as internal.

Setup

Before we get started, let's create a simple api controller for the Umbraco backoffice:

internal record MyRequestModel(string Value);

[PluginController("myplugin")]
internal class MyExampleController
    : UmbracoAuthorizedApiController
{
    public IActionResult Get([FromQuery] MyRequestModel request)
    {
        return Ok(request.Value);
    }
}
Enter fullscreen mode Exit fullscreen mode

You'll find that you cannot reach this controller with an HTTP request. Let's fix that:

Making the controller available

To make the controller available, we need to implement a ControllerFeatureProvider:

public class ExampleControllerFeatureProvider
    : ControllerFeatureProvider
{
    protected override bool IsController(TypeInfo typeInfo)
    {
        // 👇 Check for the type that it is the type of our controller
        return typeof(MyExampleController).IsAssignableTo(typeInfo);
    }
}
Enter fullscreen mode Exit fullscreen mode

Now register this object in a composer:

public class ExampleComposer
    : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.AddMvcAndRazor(options =>
        {
            options.ConfigureApplicationPartManager(manager =>
            {
                manager.FeatureProviders.Add(new ExampleControllerFeatureProvider());
            });
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

That's all! Now your controller is internal, but you can still reach it.

Why you should do this

When you publish a package, all your public types are part of your public API. They're tools that you allow consumers of your package to use. Also, every public type "should" be documented with xml comments or else you get warnings:

A screenshot of a lot of warnings about missing xml comments

Making your controllers public has a cascading effect: all your request and response models also need to be public and all your constructor dependencies need to be public and all these things then need to be documented.

By making your controllers internal, you can make its dependencies and public members internal as well, allowing you more fine control over the features that you publicly expose.

Top comments (0)