Маршрутизация веб-API MVC к неправильному действию

avatar
Matt G
8 апреля 2018 в 06:05
133
1
0

У меня есть контроллер веб-API, когда я вызываю действие Get по умолчанию, это работает, когда я вызываю другое конкретное действие (GetReservationsForCustomer), это также работает, но одно действие выдает ошибку (GetReservationsByDate), кажется, что он направляется к действию по умолчанию Получите действие. Вот код:

    // 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);
    }

Вот мой вызов API:

http://localhost:55601/api/Reservations/GetReservationsByDate/?StartDate=2018-03-04:T12:30:00

И вот ответ:

{
    "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."
}

Пожалуйста, обратите внимание, что особенности действия не имеют значения на данном этапе, я изрядно потрудился, пытаясь заставить это работать! Я пытался указать дату начала и дату окончания, и ни один из них не работает. Кажется, что он всегда перенаправляется на действие Get по умолчанию.

Вот мой 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 }
        );
    }
}

А вот мой 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 }
        );
    }

Итак, оба варианта по умолчанию.

Почему это не приводит к правильному действию, только для этого, а не для других? У меня есть другой контроллер (Клиенты), который, кажется, работает правильно для всех действий. Я читал это и это, а также это и это на самом деле было симпатично и весьма актуально, но это было весьма актуально,3 не решить мою проблему.

Что я здесь делаю не так?

Источник
Aluan Haddad
8 апреля 2018 в 06:24
0

endDate — обязательный параметр без значения по умолчанию. Следовательно, это действие не является кандидатом на сопоставление с маршрутом, и выбирается маршрут по умолчанию. Впоследствии это не удается, потому что для id нет значения.

Matt G
8 апреля 2018 в 06:26
0

@AluanHaddad Я тоже пробовал это с датой окончания, и это не имеет значения. Я также пробовал полностью удалить enddate из действия.

Marcus Höglund
8 апреля 2018 в 06:37
1

Вы должны пропустить имя действия URL-адреса и позволить платформе сопоставить запрос с именем параметров, попробуйте это так: localhost:55601/api/Reservations?StartDate=2018-03-04:T12:30:00

Matt G
8 апреля 2018 в 06:52
0

@MarcusHöglund, похоже, справился с задачей. Теперь я получаю другую ошибку, но, по крайней мере, ее маршрутизация к правильному контроллеру: { "Message": "Запрос недействителен.", "MessageDetail": "Словарь параметров содержит нулевую запись для параметра "Дата начала" не -Обнуляемый тип "System.DateTime" для метода "System.Web.Http.IHttpActionResult GetReservationsByDate(System.DateTime, System.DateTime)" в "GreenLionBookings.API.ReservationsController". Необязательный параметр должен быть ссылочным типом, допускающим значение NULL или быть объявленным как необязательный параметр." }

Matt G
8 апреля 2018 в 06:53
0

Но не уверен, почему он говорит, что параметр равен нулю?

Marcus Höglund
8 апреля 2018 в 07:07
1

похоже, у вас опечатка в дате, 2018-03-04:T12:30:00 должно быть 2018-03-04T12:30:00

Marcus Höglund
8 апреля 2018 в 07:09
0

Кроме того, как указал Алуан, вам нужно установить для EndDate значение nullable DateTime, использовать DateTime?, это тип значения, а не ссылочный тип

Matt G
8 апреля 2018 в 21:15
0

@MarcusHöglund спасибо за опечатку. Также изменение DateTime на nullable требует изменения кода для использования [...].Value.[...]. А также .Date нельзя использовать в запросах LINQ. Теперь работает, спасибо. Хотя где-то есть логическая ошибка, он просто возвращает все записи на данный момент.

Marcus Höglund
9 апреля 2018 в 04:57
1

@MattG Np, тогда я должен опубликовать это как ответ?

Matt G
11 апреля 2018 в 05:56
1

@MarcusHöglund, да, пожалуйста, и я отмечу его как принятое. Ваше здоровье

Ответы (1)

avatar
Marcus Höglund
11 апреля 2018 в 06:45
1

Во-первых, у вас опечатка в дате.

Этот 2018-03-04:T12:30:00 должен быть 2018-03-04T12:30:00.

Затем, чтобы решить проблему маршрутизации, вы можете пропустить имя действия в URL-адресе и позволить платформе сопоставить запрос с именем параметра.

Попробуйте так

api/Reservations?StartDate=2018-03-04T12:30:00&EndDate=2018-03-05T12:30:00 

Затем, если вы хотите иметь возможность отправлять значения, допускающие значение NULL, в EndDate, который является типом значения DateTime; сделать DateTime обнуляемым

[ResponseType(typeof(ListReservationDTO))]
public IHttpActionResult GetReservationsByDate(DateTime StartDate, DateTime? EndDate)

Обратите внимание на DateTime?, который является сокращением для Nullable<DateTime>