2

I need to build project, that implement REST API predefined by vendor application(which will consume it) - there is about thousand of REST-resources with some actions defined by different HTTP-Verb's(POST, GET, PUT, DELETE, etc..).

So, ideally, for each resource i should have single class like this:

public class SomethingController
{
  public Something Post(string name, DateTime time)
  {
     // ...
  }

  public int PostStrange(string text)
  {
     // ...
  }

  public Something Put([FromBody]Something item)
  {
     // ...
  }

  public void Delete(int id)
  {
     // ...
  }
}

In previous versions i can just call MapHttpRoute while registering routes, inherit classes like this from ApiController - and ASP.NET Web Api will do as i need... But in .NET Core i can't find anything like MapHttpRoute/ApiController.. Now there is routing and http-verb attributes, and i need to define everything explicitly for each class/method:

[Route("api/[controller]")]
public class SomethingController : Controller
{
    [HttpPost]
    public Something Post(string name, DateTime time)
    {
        // ...
    }

    [HttpPost("api/[controller]/strange")]
    public int PostStrange(string text)
    {
        // ...
    }

    [HttpPut]
    public Something Put([FromBody]Something item)
    {
        // ...
    }

    [HttpDelete]
    public void Delete(int id)
    {
        // ...
    }
}

Writing this attributes for each of thousands REST-resources is very boring and error prone...

Do i miss something here? Why in pretty new and modern ASP.NET Core that very common and important thing as building REST-Api made so over-complicated, compared to old ASP.NET?

rufanov
  • 3,266
  • 1
  • 23
  • 41

2 Answers2

3

There is nuget package Microsoft.AspNetCore.Mvc.WebApiCompatShim which main goal is to make migration from web api to core easier. It also provides a way to perform convention-based routing to actions you need. So, first install that package, then in startup:

public void ConfigureServices(IServiceCollection services) {
    // add conventions here
    services.AddMvc().AddWebApiConventions();                
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
    app.UseMvc(routes => {
        // map one global route
        routes.MapWebApiRoute("WebApi", "api/{controller}");
    });
}

After this small configuration you can inherit your controllers either from ApiController, which is added in package above for convenience of migration from web api, or native asp.net core Controller. Example of ApiController:

public class SomeController : ApiController {
    // maps to GET /api/Some
    // note - no routing attributes anywhere
    public HttpResponseMessage Get() {
        return new HttpResponseMessage(HttpStatusCode.OK);
    }

    // maps to POST /api/Some
    public HttpResponseMessage Post() {
        return new HttpResponseMessage(HttpStatusCode.OK);
    }
}

Native asp.net core controller:

// mark with these attributes for it to work
[UseWebApiRoutes]
[UseWebApiActionConventions]
public class TestController : Controller {
    // maps to GET /api/Test
    // no routing attributes, but two "conventions" attributes
    public IActionResult Get(string p) {
        return new ObjectResult(new { Test = p });
    }
}

You can also mark your base controller with these attributes:

[UseWebApiRoutes]
[UseWebApiActionConventions]    
public class BaseController : Controller {

}

public class TestController : BaseController {
    // maps to GET /api/Test
    // no attributes
    public IActionResult Get(string p) {
        return new ObjectResult(new { Test = p });
    }
}

If you are not migrating from web api - I'd suggest to use native Controller. ApiController has different structure (similar to asp.net web api ApiController), so there is not much reason to use it for anything other than its intended goal (migration from web api).

Evk
  • 98,527
  • 8
  • 141
  • 191
2

MapRoute is still there https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing

Attribute routing compliments MapRoute, not replaces it.

Apparently there are quite a few examples which drop the piece about Routing in order to simplify example. So just dig dipper.

v-andrew
  • 21,939
  • 6
  • 36
  • 41
  • 1
    Yes `MapRoute` is still there, but not mentioned `MapHttpRoute` - they provide totally different route mapping. `MapRoute` only provide mapping from url query string to action-methods of controllers(perfect for building web sites based on mvc), while `MapHttpRoute` was provided mapping from HTTP-verb and query string to verb-methods in api controllers. – rufanov Dec 19 '17 at 04:36
  • 1
    Using `MapRoute` i can't archive single named REST-resource like `api/something` that can be called with different http-verbs to do different things with resource(which is essence of REST-api) - to controller above `MapRoute` will map 4 different urls - `api/something/post`, `api/something/delete`, `api/something/put`, and `api/something/putstrange` – rufanov Dec 19 '17 at 04:37