Reputation: 632
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?
Upvotes: 0
Views: 164
Reputation: 16801
First of all, you have a typeo in the date.
This 2018-03-04:T12:30:00
should be 2018-03-04T12:30:00
.
Then, to solve the routing problem, you could leave out the action name of the url and let the framework match the request against the parameters name.
Try it like this
api/Reservations?StartDate=2018-03-04T12:30:00&EndDate=2018-03-05T12:30:00
Then, if you want to be able to send nullable values to EndDate which is a value type of DateTime; make the DateTime nullable
[ResponseType(typeof(ListReservationDTO))]
public IHttpActionResult GetReservationsByDate(DateTime StartDate, DateTime? EndDate)
Notice the DateTime?
which is a shorthand for Nullable<DateTime>
Upvotes: 1