Alex G.
Alex G.

Reputation: 2153

How to add Web API controller to an existing ASP.NET Core MVC?

I created a project using the default ASP.NET Core MVC template. I would like to also create a RESTful API under /api/{Controller}. I added a new Web API controller (standard Web API controller class template) but I can't call it. I get an error saying that the page cannot be found. I tried adding a route in Startup.cs but it doesn't do anything:

app.UseMvc(routes =>
{
    routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
    routes.MapRoute(name: "api", template: "api/{controller=Admin}");
});

EDIT:

Like I said, it's all default templates. Here's the Web API Controller that I added:

[Route("api/[controller]")]
public class AdminController : Controller
{                
    // GET api/values/5
    [HttpGet("{id}")]
    public string Get(int id)
    {
        return "value";
    }

    // POST api/values
    [HttpPost]
    public void Post([FromBody]string value)
    {
    }

    // PUT api/values/5
    [HttpPut("{id}")]
    public void Put(int id, [FromBody]string value)
    {
    }

    // DELETE api/values/5
    [HttpDelete("{id}")]
    public void Delete(int id)
    {
    }
}

Upvotes: 29

Views: 37544

Answers (7)

Stefan Varga
Stefan Varga

Reputation: 508

I tried to call https://localhost:7052/api/TranslationsJS/GetAll but I got 404 not found.

So my issue was that I had a typo in action. I defined a route name instead route template(path).

[Authorize]
[Route("api/[controller]")]
[ApiController]
public class TranslationsJSController : ControllerBase
{
    [HttpGet(Name = "GetAll")] // this didn't work because it is route name
    [HttpGet("GetAll")] // this worked because it is route template(path)
    public ActionResult<Dictionary<string, string>> GetAll()
    {
        var resourceSet = TranslationsJS.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
        var translationsJs = new Dictionary<string, string>();
        foreach (DictionaryEntry entry in resourceSet)
        {
            translationsJs.Add(entry.Key.ToString(), entry.Value.ToString());
        }
        return translationsJs;
    }
}

In program.cs

builder.Services.AddControllersWithViews();

...

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

More info:

https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-7.0#route-name

https://csharp-video-tutorials.blogspot.com/2017/02/generating-links-using-route-names-in.html

Upvotes: 0

Ador-25
Ador-25

Reputation: 31

Running existing .net core MVC:

1

In order to add api controllers to existing .net core 6 mvc application, Open Program.cs file, add following codes:

//for apis
builder.Services.AddRazorPages();
builder.Services.AddControllers();

app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
});

Now go ahead and add a new controller:

[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    //endpoint: http://localhost:5207/api/test/strings
    [HttpGet("strings")]
    public IActionResult TestMethod()
    {
        return Ok(new string[]{ 
        "23", "24"});
    }
}

Testing Endpoint here

2

This works for me in .net core 6

Upvotes: 3

Nkosi
Nkosi

Reputation: 247008

Two things.

First, when using convention-based routing, more specific routes should come before more generic routes to avoid route conflicts.

app.UseMvc(routes =>
{
    routes.MapRoute(name: "api", template: "api/{controller=Admin}");
    routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
});

Secondly, you are already using attribute routing on the controller so should have been able to route to the controller except for the fact that you do not have a routing template on the controller that would accept /api/{Controller}

That would require a default route.

[Route("api/[controller]")]
public class AdminController : Controller {
 
    [HttpGet("")] //Matches GET api/admin <-- Would also work with [HttpGet]
    public IActionResult Get() {
        return Ok();
    }

    [HttpGet("{id}")] //Matches GET api/admin/5
    public IActionResult Get(int id) {
        return Ok("value");
    }    

    //...other code removed for brevity
}

Upvotes: 12

Ricardo May
Ricardo May

Reputation: 111

I had luck doing this with v3.1:

Add Folder Controllers to the project. Add Controller, named TestController, to the folder. Then add the following to the Startup.cs:

services.AddControllers();

to

public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
        services.AddControllers();
    }

and:

endpoints.MapControllers();

to

app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
            endpoints.MapControllers();
        });

Then I was able to call /api/Test.

Upvotes: 11

Kevin Youn
Kevin Youn

Reputation: 731

If someone still have problem in adding webapi to .net core MVC, just inserting [ApiController] and [Route("api/[controller]")] attributes before class solves the problem:

[Route("api/[controller]")]
[ApiController]
public class ListController
{ ... }

I didn't added a route mapping in Startup.cs and still working well. The version of .net that I am using is 2.1.402

Upvotes: 8

Alex G.
Alex G.

Reputation: 2153

After updating to the latest version of ASP.NET Core, v2.0.1 (the one that needs VS2017), the problem resolved itself. I think it was probably a bug or shortcoming in the old version.

Upvotes: 3

William Han
William Han

Reputation: 78

Try setting name to "Admin"

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "Admin",
                template: "api/{controller=Admin}");
        });

Upvotes: 0

Related Questions