ASP.net MVC - отдельная модель представления для действия POST - PullRequest
3 голосов
/ 15 декабря 2011

В моем приложении MVC у меня есть View View, которая выглядит примерно так:

public class ComplexViewModel
{
    public ComplexDetailsViewModel Details1 { get; set; }
    public ComplexDetailsViewModel Details2 { get; set; }
}

public class ComplexDetailsViewModel 
{
    public int Id { get; set; }
    public string DisplayValue1 { get; set; }
    public string DisplayValue2 { get; set; }
    // ...
}

Я изначально делал следующее в моем представлении:

@Html.HiddenFor(model => model.Details1.Id)
@Html.HiddenFor(model => model.Details2.Id)

@Html.DisplayFor(model => model.Details1.DisplayValue1)
...

Я бы ПОЗИЛполная модель для контроллера:

 public ActionResult Post(ComplexViewModel model)

Мне на самом деле ничего не нужно из ComplexViewModel, кроме значений Id, поэтому я решил создать другую модель представления, используемую специально для размещения данных:

public class PostViewModel
{
    public int Details1Id { get; set; }
    public int Details2Id { get; set; }   
}

public ActionResult Post(PostViewModel model)

Проблема в том, что теперь мой @HiddenFor(model => model.Details1.Id) не сопоставляется с моей моделью POST, поэтому на самом деле ничего не выполняется POST.

Есть ли способ иметь отдельную структуру для моей модели POST и моей модели GET, покавсе еще используете помощник HiddenFor?

Ответы [ 4 ]

5 голосов
/ 15 декабря 2011

То, что вы не используете все данные в версии POST, не означает, что вам нужно создать другую модель. Почему бы не сделать это простым?

Вот как это должно работать:

Ваш вид информации о посте должен быть строго типизирован для конкретной модели представления. Затем в вашем контроллере у вас есть два результата действия с именем Post, например, один украшен атрибутом [HTTPGET], а действие, на которое вы хотите опубликовать, - атрибутом [HTTPPOST]. Кроме того, ваш метод get должен принимать такой параметр, как идентификатор записи, а метод post должен принимать модель в качестве параметра.

Для корректной проверки на стороне сервера вы можете украсить свойства вашего класса следующим образом:

public class ComplexDetailsViewModel 
{
    [Required]//Works for just the Id property
    public int Id { get; set; }
    public string DisplayValue1 { get; set; }
    public string DisplayValue2 { get; set; }
    // ...
}

Теперь в вашем контроллере вы можете использовать это bool: ModelState.IsValid. В основном, если у них отключен JavaScript, и модель была опубликована без Id, то модель будет недействительной.

Этот шаблон является чрезвычайно мощным и позволяет быстро внедрить проверку на стороне клиента и на стороне сервера. И, конечно, проверка на стороне клиента использует jQuery из коробки, поэтому мы можем легко расширить валидаторы. Вы даже можете выполнить проверку AJAX очень быстро. Когда я строю свои формы, я нигде не жертвую, когда дело доходит до проверки ... так как все это занимает совсем немного времени, чтобы сделать это правильно.

Чтобы ответить на ваш оригинальный вопрос:

Вид может быть строго типизирован только для одной модели. Вы не можете загрузить вид с одной моделью, а разместить его с другой (насколько я знаю). Я думаю, что если вы пытаетесь это сделать, ваша проблема в том, как вы построили свою модель.

1 голос
/ 15 декабря 2011

Модели должны быть более похожими. Одна ваша модель «Вид» имеет свойства класса, а ваша модель «Пост» - нет. Если имена свойств класса и свойств не совпадают, они не будут связаны связывателем модели. Попробуйте что-то вроде:

public class ComplexViewModel 
{ 
  public ComplexDetailsViewModel Details1 { get; set; } 
  public ComplexDetailsViewModel Details2 { get; set; } 
} 

public class ComplexDetailsViewModel : PostDetailsModel
{ 
  public string DisplayValue1 { get; set; } 
  public string DisplayValue2 { get; set; } 
} 

public class PostModel
{
  public PostDetailsModel Details1 { get; set; } 
  public PostDetailsModel Details2 { get; set; } 
}

public class PostDetailsModel  
{ 
  public int Id { get; set; } 
} 

Большой проблемой, не использующей одни и те же модели между View и Post, является проверка. Что произойдет, если вы захотите изменить валидацию (при условии использования встроенной валидации MVC для клиентской и серверной сторон). Теперь вам нужно сменить обе модели! Ой, подождите ... нет, ты не ...

public interface MyValidation
{
  [required]
  public int id { get; set; }
}

Затем просто добавьте эти проверки в ваши классы: (MetadataType сообщает MVC, что использовать для проверки)

[MetadataType(typeof(MyValidation))]  
public class ComplexDetailsViewModel ....

[MetadataType(typeof(MyValidation))]
public class PostDetailsModel ....

Это, безусловно, сработало бы, но я НАСТОЯТЕЛЬНО отговаривал бы любого использовать две разные модели между представлениями и постбэками. В этом случае я не вижу абсолютно никакой причины, почему они должны отличаться.

1 голос
/ 15 декабря 2011

Просто напишите HTML для скрытых входных данных вручную вместо использования Html Helpers.

<input type="hidden" id="Details1Id" value="@Model.Details1.Id"/>
<input type="hidden" id="Details2Id" value="@Model.Details1.Id"/>

Обновление

У меня были проблемы с чем-то похожим. Я закончил сглаживать свойства, связанные с формой, в моих представлениях. Automapper позволяет действительно легко сопоставлять другие объекты с вашим видом и может выравнивать иерархии. При этом ваш новый вид может выглядеть примерно так.

public class ComplexViewModel        
{        
    public long Details1Id { get; set; }        
    public string Details1Name { get; set; }
    public long Details2Id { get; set; }    
    public string Details2Name { get; set; }    
}  
0 голосов
/ 05 октября 2016

Легко: просто наследуйте модель представления вашего представления от пост-модели вашего контроллера.Затем ваши методы HiddenFor с работой, вам просто нужно убедиться, что свойства, которые вы ожидаете опубликовать, находятся в базовом классе (модель публикации).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...