grokky
grokky

Reputation: 9255

Override controller name in ASP.NET Core

Similar to this question, but for the new ASP.NET Core.

I can override an action's routing name:

[ActionName("Bar")]
public IActionResult Foo() {

Can I do that for a controller, using attribute routing?

[?("HelloController")]
public SomeController : Controller {

It should allow generation of links using tag helpers:

<a asp-controller="some" ...      // before
<a asp-controller="hello" ...     // after

Upvotes: 10

Views: 20010

Answers (4)

juunas
juunas

Reputation: 58723

Such an attribute does not exist. But you can create one yourself:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ControllerNameAttribute : Attribute
{
    public string Name { get; }

    public ControllerNameAttribute(string name)
    {
        Name = name;
    }
}

Apply it on your controller:

[ControllerName("Test")]
public class HomeController : Controller
{
}

Then create a custom controller convention:

public class ControllerNameAttributeConvention : IControllerModelConvention
{
    public void Apply(ControllerModel controller)
    {
        var controllerNameAttribute = controller.Attributes.OfType<ControllerNameAttribute>().SingleOrDefault();
        if (controllerNameAttribute != null)
        {
            controller.ControllerName = controllerNameAttribute.Name;
        }
    }
}

And add it to MVC conventions in Startup.cs:

services.AddMvc(mvc =>
{
    mvc.Conventions.Add(new ControllerNameAttributeConvention());
});

Now HomeController Index action will respond at /Test/Index. Razor tag helper attributes can be set as you wanted.

Only downside is that at least ReSharper gets a bit broken in Razor. It is not aware of the convention so it thinks the asp-controller attribute is wrong.

Upvotes: 28

krillgar
krillgar

Reputation: 12805

It should be the same way that you would do it in ASP.NET WebAPI2 before Core:

[Route("Bar")]
public IActionResult Foo() { }

If you're looking to do it on the Controller level as well, there's a different attribute for that:

[RoutePrefix("ControllerFoo")]
public class MyController() { }

Here is a (non-Microsoft) article that goes over how it should be done in .NET Core.

Upvotes: 2

Tseng
Tseng

Reputation: 64121

If you don't want to derive the controller name from the Controller class (Classname minus Controller surfix), then just leave out the [controller] place holder.

[Route("/api/hello")]
public SomeController : Controller {
    [HttpGet]
    public IActionResult Get() { }

    [HttpGet("something")]
    public IActionResult GetSomething() { }
}

The overloads in HttpGet will set the action name. Doing so however, you can't use generic routes like

routes.MapRoute("default", "api/{controller}/{id?}");

or you have to register them manually there

routes.MapRoute("hello", "api/hello/{id?}", defaults: new { controller = "Hello" });
routes.MapRoute("default", "api/{controller}/{id?}");

Upvotes: 10

Craig Selbert
Craig Selbert

Reputation: 777

Here is code we are using

[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class MembersController : Controller { /* */ }

Upvotes: 3

Related Questions