Search code examples
c#asp.net-mvcasp.net-web-apiasp.net-web-api-routing

Added a second controller to my WebAPI and it is not working


Added a second controller in my WebAPI project and it is nor working completely but the first controller is working as expected

The default URI works for the first controller to return all records: http://localhost:59654/api/TidalBatch

The second controller does not work and returns the error in question: http://localhost:59654/api/TidalBatchConsolidated

However, if I pass in {id} for it, it does work for when I use the id (example shown): http://localhost:59654/api/TidalBatchConsolidated/BAM

Tried modifying the routing addresses

WebAPI config: config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "TidalBatchApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "TidalBatchConsolidatedApi",
            routeTemplate: "api/TidalBatchConsolidated/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

I have 2 controllers, TidalBatchController.cs and TidalBatchConsolidatedController.cs. Both inherit from ApiController class.

Here's an example of my second controller that is not working as expected:

 public class TidalBatchConsolidatedController : ApiController 
 {
   public TidalBatchConsolidated GetAll(string id) 
   { 
     using (BDW_ProcessingEntities_TidalBatch entities = new BDW_ProcessingEntities_TidalBatch()) 
     { 
       return entities.TidalBatchConsolidateds.FirstOrDefault(e => e.CompanyAbbr == id); 
     } 
   } 
 }

When I navigate to the base controller in the address it should return the List results in JSON format based on which entity data model is being passed in.


Solution

  • First, the order you register routes is important where more generic routes need to be registered after more specific routes. Secondly you more specific route needs controller in order for it to match.

    config.MapHttpAttributeRoutes();
    
    config.Routes.MapHttpRoute(
        name: "TidalBatchConsolidatedApi",
        routeTemplate: "api/TidalBatchConsolidated/{id}",
        defaults: new { controller ="TidalBatchConsolidated", id = RouteParameter.Optional }
    );
    
    config.Routes.MapHttpRoute(
        name: "TidalBatchApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
    

    The controller also needs to ensure that there is a matching action

    For example

    public class TidalBatchConsolidatedController: ApiController {
    
        [HttpGet]
        public IHttpActionResult Get() {
            //...
        }
    
        [HttpGet]
        public IHttpActionResult Get(string id) {
            //...
        }
    
    }
    

    Since you have attribute routing enabled with config.MapHttpAttributeRoutes();, you could forego convention based route and use attribute routing on the controller instead

    [RoutePrefix("api/TidalBatchConsolidated")]
    public class TidalBatchConsolidatedController: ApiController {
    
        //GET api/TidalBatchConsolidated
        [Route("")] //Default route
        [HttpGet]
        public IHttpActionResult GetAll() {
            //...
        }
    
    
        //GET api/TidalBatchConsolidated/BAM
        [Route("{id}")]
        [HttpGet]
        public IHttpActionResult Get(string id) {
            //...
        }
    
    }
    

    Reference Attribute Routing in ASP.NET Web API 2