ASP.NET MVC 2: Необязательные URL-параметры

суббота, 13 февраля 2010, Евгений Жарков

Если у вас объект модели имеет свойство Id, то вы столкнетесь с проблемой, когда состояние модели будет невалидным при связывании с этой моделью, даже когда у вас отсутствует поле "Id" в форме.

Следующая ситуация более понятно объяснит к чему я клоню. Предпологается, что у вас есть модель с двумя свойствами.

public class Product {
    public int Id { get; set; }
    public string Name { get; set; }
}

Добавляете представление для создания нового Product. Вы конечно же не хотите, чтобы пользователь задавал Id.

<% using (Html.BeginForm()) {%>
 
  <fieldset>
    <legend>Fields</legend>
 
 
    <div class="editor-label">
      <%= Html.LabelFor(model => model.Name) %>
    </div>
    <div class="editor-field">
      <%= Html.TextBoxFor(model => model.Name) %>
      <%= Html.ValidationMessageFor(model => model.Name) %>
    </div>
 
    <p>
      <input type="submit" value="Create" />
    </p>
  </fieldset>
 
<% } %>
<p > </p>

Метод действия выглядит так:

[HttpPost]
public ActionResult Index(Product p)
{
    if (!ModelState.IsValid) {
        throw new InvalidOperationException("Modelstate not valid");
    }
    return View();
}

Вы обнаружите, что состояние модели невалидно. В чем же причина? Проблема в том, что свойство Id, объекта Product устанавливается, как пустая строка. Почему же так происходит, когда поле Id не присутствует в форме? Ответ, друзья мои, прост - всему виной маршрутизация.

Если открыть свеже-созданный проект ASP.NET MVC 1.0, то можно увидеть объявление маршрутизатора по умолчанию

routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = "" }
);

Напомню, в проекте имеется маршрутизатор с тремя URL-параметрами (controller, action, id), каждые имеет значение по умолчанию ("home", "index", "").

Соответственно, если вы будете отсылать данные формы по адресу /Home/Index, без указания "ID" в URL, то маршрутизатор подставит пустую строку для ключа "id". Теперь нам ясно, что используются значения маршрутизатора для связки с параметрами метода действия.

В итоге, случилась "накладка", когда свойство вашего объекта модели "Id", имееет точно такое же имя, как и у параметра маршрутизатора, а модель привязки пытается присвоить значению свойства Id пустую строку. Но Id является целым числом не равное null, соответственно у нас возникает ошибка приведения типов.

routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

И немного изменив настройки роутера, мы изменяем логику - если не передается ID в URL, то не будет производиться подстановка значения по умолчанию, что не приведет к заданию значения свойства "Id", до тех пор, пока мы не добавим поле "Id" на форму.

Начиная с ASP.NET MVC 2 RTM версии, стандартный шаблон проекта будет с измененным видом роутера.

Источник - Phil Haack


Ищите нас в интернетах!

Комментарии

Свежие вакансии