Подтвердить что ты не робот

MVC 4 - Использовать другую модель в частичном представлении

Пожалуйста, воздержитесь от моего noobness, я супер новичок в шаблоне MVC.

Что я пытаюсь сделать

Я создаю страницу профиля для зарегистрированных пользователей на моем сайте. На этой странице будут перечислены данные о пользователе, такие как дата рождения, номер телефона, статус подписки и т.д. Вы получите эту идею. Я также хотел бы иметь форму, позволяющую пользователям изменять свой пароль, адрес электронной почты, личную информацию на той же странице.

Моя проблема

Пользовательские данные поступают от моего контроллера через переданную переменную модели:

public ActionResult Profil()
        {
            var model = db.Users.First(e => e.UserName == WebSecurity.CurrentUserName);
            return View(model);
        }

Результат выглядит следующим образом:

<label>Phone number: </label>
            @if (Model.PhoneNumber != null)
                    {
                        @Model.PhoneNumber
                    }
                    else
                    {
                        <span class="red">You haven't set up your phone number yet. </span>
                    }

Форма, в которой пользователь может изменить свою информацию, будет использовать другую модель ProfileModel. Итак, basiccaly мне нужно использовать две модели, на мой взгляд, одну для вывода информации и одну для публикации данных. Я думал, что с помощью частичного представления я могу это сделать, но получаю эту ошибку:

Элемент модели, переданный в словарь, имеет тип "Applicense.Models.User", но для этого словаря требуется элемент модели type 'Applicense.Models.ProfileModel'.

Вот как выглядит мой вызов частичного вида:

 @using (Html.BeginForm())
    {
        @Html.AntiForgeryToken()
        @Html.ValidationSummary()

        @Html.Partial("_ModifyProfileInfo")
    }

Здесь частичный вид:

@model Applicense.Models.ProfileModel
<ul>
    <li>
        @Html.LabelFor(m => m.Email)
        @Html.EditorFor(m => m.Email)
    </li>
    <li>
        @Html.LabelFor(m => m.ConfirmEmail)
        @Html.EditorFor(m => m.ConfirmEmail)
    </li>
    <input type="submit" value="Update e-mail" />
</ul>

И, наконец, здесь мой ProfileModel:

public class ProfileModel
    {
        [Required]
        [DataType(DataType.EmailAddress)]
        [Display(Name = "New e-mail address")]
        public string Email { get; set; }

        [DataType(DataType.EmailAddress)]
        [Display(Name = "Confirm new e-mail address")]
        [Compare("Email", ErrorMessage = "The e-mail and it confirmation field do not match.")]
        public string ConfirmEmail { get; set; }
    }

Я что-то упустил? Каков правильный способ сделать это?

Edit: Я переделаю свой код, отражающий ответ Никола Митев, но теперь у меня другая проблема. Вот ошибка, которую я получаю:

Ссылка на объект не установлена ​​в экземпляр объекта. (@Model.UserObject.LastName)

Это происходит только тогда, когда я отправляю измененные значения адресов электронной почты. Здесь моя ViewModel (ProfileModel.cs):

public class ProfileModel
    {
        public User UserObject { get; set; }

        [Required]
        [DataType(DataType.EmailAddress)]
        [Display(Name = "Új e-mail cím")]
        public string Email { get; set; }

        [DataType(DataType.EmailAddress)]
        [Display(Name = "Új e-mail cím megerősítése")]
        [Compare("Email", ErrorMessage = "A két e-mail cím nem egyezik.")]
        public string ConfirmEmail { get; set; }

        [DataType(DataType.EmailAddress)]
        [Display(Name= "E-mail cím")]
        public string ReferEmail { get; set; }
    }

Контроллер:

public ActionResult Profil()
        {
            var User = db.Users.First(e => e.UserName == WebSecurity.CurrentUserName);

            var ProfileViewModel = new ProfileModel
            {
                UserObject = User
            };

            return View(ProfileViewModel);
        }

И, наконец, мой класс user.cs:

[Table("UserProfile")]
    public class User
    {
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int UserId { get; set; }
        [Column("UserName")]
        public string UserName { get; set; }
        [Column("Email")]
        [Required]
        public string Email { get; set; }
        [Column("FirstName")]
        public string FirstName { get; set; }
        [Column("LastName")]
        public string LastName { get; set; }
        [Column("PhoneNumber")]
        public string PhoneNumber { get; set; }
... You get the idea of the rest...

Я думаю, что это происходит, потому что модель пытается помещать данные в каждый столбец required в базу данных.

Edit2: Метод httppost моего действия Profil:

[HttpPost]
        [Authorize]
        [ValidateAntiForgeryToken]
        public ActionResult Profil(ProfileModel model)
        {
            if (ModelState.IsValid)
            {
//insert into database
                return Content("everything good");
            }
            else
            {
//outputs form errors
                return View(model);
            }
        }
4b9b3361

Ответ 1

Лучший способ справиться с этой ситуацией - использовать и передать viewModel в ваш контроллер профиля, viewModel - это класс-оболочка для нескольких объектов, которые вы хотите передать в свое представление.

public class ProfileUserViewModel
{
   public ProfileModel ProfileModelObject {get; set;}
   public UserModel  UserModelObject {get; set;}
}   

Ваш контроллер должен выглядеть так:

public ActionResult Profil()
{            
    var profileModel = db.Users.First(e => e.UserName == WebSecurity.CurrentUserName);
    var userModel = //fetch from db.

    var pmViewModel = new ProfileUserViewModel  
                          {
                              ProfileModelObject = profileModel,
                              UserModelObject = userModel
                          };

   return View(pmViewModel);
}

И, наконец, ваше мнение:

@model Applicense.Models.ProfileUserViewModel

<label>Phone number: </label>

@if (Model.ProfileModelObject.PhoneNumber != null)
{
   @Model.PhoneNumber
}
else
{
    <span class="red">You haven't set up your phone number yet. </span>
}

Ответ 2

Существует перегрузка @Html.Partial, которая позволяет отправлять ViewData, как определено в вашем контроллере, - это метод, который я обычно использую для частичных представлений. В вашем контроллере определите ViewData["mypartialdata"] как ViewDataDictionary. Тогда, на ваш взгляд,

@Html.Partial("_ModifyProfileInfo",ViewData["mypartialdata"])

Ответ 3

В вашей функции [HttpPost] profil, если modelstate.isvalid является ложным, вы возвращаете свое редактируемое представление, но вам нужно снова определить свой pmViewModel, иначе ваше частичное представление не будет иметь объект для отображения. Попробуйте использовать следующее и сообщите нам, что произойдет

[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public ActionResult Profil(ProfileModel model)
{
    if (ModelState.IsValid)
    {
        //insert into database
        return Content("everything good");
    }
    else
    {
        //outputs form errors
        var pmViewModel = new ProfileUserViewModel  
        {
            ProfileModelObject = profileModel,
            UserModelObject = userModel
        };

        return View(model);
    }
}

Ответ 4

Пока я знаю, что этот вопрос задан давно, однако некоторые люди могут столкнуться с подобной проблемой. Одним из простых решений, которые я использую для передачи или наличия более одной модели представления на странице, является использование ViewBag для хранения второго объекта и обращения к нему в представлении. См. Пример ниже.

В контроллере сделайте следующее:

Obj2 personalDets = new Obj2();
DbContext ctx = new DbContext();
var details = ctx.GetPersonalInformation;

foreach(var item in details) {
    personalDets.Password = item.Password;
    personalDets .EmailAddress = item.EmailAddress; 
}

ViewBag.PersonalInformation = personalDets;

Тогда, на ваш взгляд, эти свойства станут для вас доступными