I have a web API controller, when I call the default Get action this works, when I call another specific action (GetReservationsForCustomer) this also works, but one action gives an error (GetReservationsByDate), it seems to route to the default Get action. Here is the code:
// GET: api/Reservations public IQueryable<Reservation> GetReservations() { return db.Reservations; } [ResponseType(typeof(ReservationDTO))] public IHttpActionResult GetReservationsForCustomer(int CustomerId) { IEnumerable<Reservation> reservations = db.Reservations.Where(r => r.CustomerId == CustomerId).ToList(); List<ReservationDTO> reservationList = new List<ReservationDTO>(); foreach(Reservation reservation in reservations) { reservationList.Add(new ReservationDTO { id = reservation.id, ReservationStart = reservation.ReservationStart, Covers = reservation.Covers }); } return Ok(reservationList); } [ResponseType(typeof(ListReservationDTO))] public IHttpActionResult GetReservationsByDate(DateTime StartDate, DateTime EndDate) { IEnumerable<Reservation> reservations = new List<Reservation>(); if (EndDate != null) { reservations = db.Reservations.Where(r => r.ReservationStart.Date >= StartDate.Date && r.ReservationStart.Date >= EndDate.Date).ToList(); } else { reservations = db.Reservations.Where(r => r.ReservationStart.Date == StartDate.Date).ToList(); } List<ReservationDTO> reservationList = new List<ReservationDTO>(); foreach (Reservation res in reservations) { reservationList.Add(new ReservationDTO { id = res.id, ReservationStart = res.ReservationStart, Covers = res.Covers, CustomerEmail = res.Customer.EmailAddress, CustomerName = res.Customer.Name, CustomerPhone = res.Customer.PhoneNumber }); } return Ok(reservationList); } Here is my API call:
http://localhost:55601/api/Reservations/GetReservationsByDate/?StartDate=2018-03-04:T12:30:00
And here is the response:
{ "Message": "The request is invalid.", "MessageDetail": "The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Http.IHttpActionResult GetReservation(Int32)' in 'GreenLionBookings.API.ReservationsController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter." } Please note the specifics of the action are not relevant at this stage, I've butchered it a fair bit trying to get this to work! I've tried specifying a start date and end date and neither seems to work. It always seems to get routed to the default Get action.
Here is my RouteConfig:
public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } And here is my WebApiConfig:
public static void Register(HttpConfiguration config) { // Web API configuration and services // Configure Web API to use only bearer token authentication. config.SuppressDefaultHostAuthentication(); config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } So both basically just default.
Why is this not routing to the correct action, just for this one and not the others? I have another controller (Customers) which seems to work correctly for all actions too. I've read this and this, and also this and this which I actually thought was pretty relevant and quite helpful, but didn't solve my problem.
What am I doing wrong here?
endDateis a required parameter with no default. Therefore, that action is not a candidate for matching the route and the default route is chosen. That subsequently fails because there is no value forid.