none
Не правильно отрабатывает представление RRS feed

  • Вопрос

  • Небольшой проект MVC 3 + MS SQLR2

    Используется стандартная авторизация

    Имеется класс с следующим свойством: 

    public string Name
    {
        get { return _profile == null ? string.Empty : _profile["Name"] as string; }
        set { if (_profile != null) _profile["Name"] = value; }
    }

    Проблема возникает при действии Edit:

    <div class="editor-label">
                <strong>@Html.LabelFor(model => model.Name)</strong>
    </div>
    <div class="editor-field">
                @Html.EditorFor(model => model.Name)
                @Html.ValidationMessageFor(model => model.Name)
    </div>

    В этом участке в место имени пользователя возвращается логин текущего зарегистрированного пользователя. 

    Если смотреть по брекпоинтам, то класс возвращается правильное значение имени пользователя, но в представлении уже оказывается логин.

    Если тоже самое свойство класса назвать по другому, то также возвращается верное значение.

    Подскажите, с чем это может быть связанно?


Ответы

  • EditorFor (и методы типа TextBoxFor) берут значение сначала из ModelState, а потом уже из Model. В ModelState в вашем примере есть значение для Name (взятое из параметра action-a).

    Самый простой способ обойти это в последствии - называть разные вещи по разному в пределах одного action-a. Сейчас у вас UserCRM.GetUser(name) может вернуть такого User-а, у которого Name не будет совпадать с name. Т.е. name и Name в вашем коде работы с пользователем - две совершенно разные вещи.

    В MVC многие вещи построены на convention-ах. Например, имена классов-контроллеров, механизм поиска представлений. Подтягивание значение по имени - это просто очередной convention, он просто не слишком заметен, пока на него не наткнешься.


    • Предложено в качестве ответа YatajgaEditor 12 мая 2012 г. 10:56
    • Помечено в качестве ответа Sergey Rogachev 12 мая 2012 г. 15:00

Все ответы

  • "Используется стандартная авторизация" - что  именно, стандартный провайдер Membership API?

    "Если смотреть по брекпоинтам, то класс возвращается правильное значение имени пользователя, но в представлении уже оказывается логин." - данные из контроллера в модель передаются верно, по пути не искажаются. Ту дело в Вашем классе модели. Попробуйте привести чуть больше сведений о классе модели.


    Модератор
  • using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Profile;
    using System.Web.Security;
    
    namespace CugaetCRM.Models
    {
        public class UserCRM
        {
            private ProfileBase _profile = null;
            private MembershipUser _user = null;
    
            private string _passwd = String.Empty;
            private string _confirmPasswd = String.Empty;
    
            #region Конструкторы
            public UserCRM(string username)
            {
                _profile = ProfileBase.Create(username);
                _user = Membership.GetUser(username);
            }
    
            public UserCRM(MembershipUser user)
            {
                _profile = ProfileBase.Create(user.UserName);
                _user = user;
            }
            #endregion
    
            #region Профиль
            [Required]
            [Display(Name = "Имя")]
            public string Name
            {
                get { return _profile == null ? string.Empty : _profile["Name"] as string; }
                set { if (_profile != null) _profile["Name"] = value; }
            }
    
            [Display(Name = "Имя")]
            public string UserName
            {
                get { return Name; }
                set { Name = value; }
            }
    
            [Display(Name = "Отчество")]
            public string MiddleName
            {
                get { return _profile == null ? string.Empty : _profile["MiddleName"] as string; }
                set { if (_profile != null) _profile["MiddleName"] = value; }
            }
    
            [Display(Name = "Фамилия")]
            public string LastName
            {
                get { return _profile == null ? string.Empty : _profile["LastName"] as string; }
                set { if (_profile != null) _profile["LastName"] = value; }
            }
    
            [Display(Name = "Дата рождения")]
            public string Birthday
            {
                get { return _profile == null ? DateTime.Now.ToShortDateString() : (((DateTime)_profile["Birthday"]).ToShortDateString()); }
                set { if (_profile != null) _profile["Birthday"] = Convert.ToDateTime(value); }
            }
    
            [Display(Name = "Группа")]
            public string UserRole
            {
                get { return _profile == null ? string.Empty : _profile["UserRole"] as string; }
                set { if (_profile != null) _profile["UserRole"] = value; }
            }
    
            [Display(Name = "ФИО")]
            public string FullName { get { return LastName + " " + Name + " " + MiddleName; } }
            #endregion
    
            #region Аккаунт
            [Display(Name = "Логин")]
            public string Login { get { return _user!=null ? _user.UserName : String.Empty; } }
    
            [Required]
            [StringLength(100, ErrorMessage = "Значение {0} должно содержать не менее {2} символов.", MinimumLength = 4)]
            [DataType(DataType.Password)]
            [Display(Name = "Пароль")]
            public string Paswword
            {
                get { return _passwd ?? (_passwd = _user.GetPassword()); }
                set { _passwd = value; }
            }
    
            [DataType(DataType.Password)]
            [Display(Name = "Подтверждение пароля")]
            [Compare("Password", ErrorMessage = "Пароль и его подтверждение не совпадают.")]
            public string ConfirmPaswword
            {
                get { return _confirmPasswd; }
                set { _confirmPasswd = value; }
            }
    
            [Display(Name = "E-Mail")]
            public string EMail
            {
                get { return _user != null ? _user.Email : String.Empty; }
                set
                {
                    if (_user != null && !String.IsNullOrEmpty(value))
                        _user.Email = value;
                }
            }
            [Display(Name = "Секретный вопрос")]
            public string SecretQuestion
            {
                get { return _user != null ? _user.PasswordQuestion : String.Empty; }
    
            }
    
            #endregion
    
            public void Save() { if (_profile != null)_profile.Save(); }
    
            public static List<UserCRM> GetUsers()
            {
                var userList = Membership.GetAllUsers();
                return (from object user in userList select new UserCRM((MembershipUser) user)).ToList();           
            }
    
            public static UserCRM GetUser(string name)
            {
                var member = Membership.GetUser(name);
    
                return member == null ? null : new UserCRM(member);
            }
        }
    }
    Использую класс Membership для авторизации
  • Да, странно как-то получается. Вроде всё верно, но почему тогда ошибка. Надо будет на практике протестировать и проверить. Или может я невнимательно смотрю.
    Модератор
  • При чём такая ситуация повторяется стабильно. Ради любопытства пере создавал представление, тоже самое. На других представлениях, всё нормально отображается (там используется этаже модель и в частности свойство Name). Следовательно, может проблема в отдельно взятом представлении? Либо что то ещё влияет.

    Представление никаких особых примочек не имеет. Всё стандартно. _Layout.chtml как главная страница с меню + используется @Html.Partial("_Links.chtml") со списком линков (Типа: На главную > Панель администратора > Список пользователей)

    P.S. Свойство UserName вставлено для теста. Если использовать его для формирования поля ввода, то имя пользователя отображается нормально в этом поле. Как вариант, может быть движок как то неадекватно реагирует в данном представлении на имя свойства?
  • Покажите код контроллера. Action случайно не принимает string name параметром?
  • А как это может повлиять? 

    Код:

    public ActionResult Edit(string name)
            {
                ViewBag.Message = String.Format("Пользователь {0} не существует", name);
    
                var user = UserCRM.GetUser(name);
                return user != null ? View(user) : View("Error");
            }
    
            //
            // POST: /Admin/Edit/5
    
            [HttpPost]
            public ActionResult Edit(string name, FormCollection collection)
            {
                try
                {
                    // TODO: Add update logic here
     
                    return RedirectToAction("Index");
                }
                catch
                {
                    return View();
                }
            }

  • Исправил передаваемый параметр в Action со string name на string uName  и всё заработало. 

    Объясните, почему сложилась такая ситуация? Как с этим в последствии бороться или обходить?

  • А представление у Вас какое ?
    Модератор
  • шаблон Razor

    @model Models.UserCRM

    @{ ViewBag.Title = "Редактирование"; } @Html.Partial("_Links") <h2>Редактирование данных пользователя</h2> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> @using (Html.BeginForm()) { @Html.ValidationSummary(true, "Не удалось отредактировать данные пользователя. Исправьте ошибки и попробуйте снова") <fieldset> <legend>@Model.FullName</legend> <br/> <fieldset> <legend> Персональные данные</legend> <div class="editor-label"> @Html.LabelFor(model => model.Name) </div> <div class="editor-field"> @Html.EditorFor(model => model.Name) @Html.ValidationMessageFor(model => model.Name) </div> <div class="editor-label"> @Html.LabelFor(model => model.MiddleName) </div> <div class="editor-field"> @Html.EditorFor(model => model.MiddleName) @Html.ValidationMessageFor(model => model.MiddleName) </div> <div class="editor-label"> @Html.LabelFor(model => model.LastName) </div> <div class="editor-field"> @Html.EditorFor(model => model.LastName) @Html.ValidationMessageFor(model => model.LastName) </div> <div class="editor-label"> @Html.LabelFor(model => model.Birthday) </div> <div class="editor-field"> @Html.EditorFor(model => model.Birthday) @Html.ValidationMessageFor(model => model.Birthday) </div> <div class="editor-label"> @Html.LabelFor(model => model.UserRole) </div> <div class="editor-field"> @Html.DropDownListFor(model => model.UserRole, new SelectList(Roles.GetAllRoles())) @Html.ValidationMessageFor(model => model.UserRole) </div> </fieldset> <fieldset> <legend>Данные об аккаунте</legend> @if (!Membership.RequiresQuestionAndAnswer) { <div class="editor-label"> @Html.LabelFor(model => model.Paswword) </div> <div class="editor-field"> @Html.EditorFor(model => model.Paswword) @Html.ValidationMessageFor(model => model.Paswword) </div> } else { <div class="editor-label"> @Model.SecretQuestion </div> <div class="editor-field"> @Html.EditorFor(model => model.SecretAnswer) @Html.ValidationMessageFor(model => model.SecretAnswer) </div> } <div class="editor-label"> @Html.LabelFor(model => model.EMail) </div> <div class="editor-field"> @Html.EditorFor(model => model.EMail) @Html.ValidationMessageFor(model => model.EMail) </div> </fieldset> <p> <input type="submit" value="Save" /> </p> </fieldset> } <div> @Html.ActionLink("Назад", "UserList") </div>


  • EditorFor (и методы типа TextBoxFor) берут значение сначала из ModelState, а потом уже из Model. В ModelState в вашем примере есть значение для Name (взятое из параметра action-a).

    Самый простой способ обойти это в последствии - называть разные вещи по разному в пределах одного action-a. Сейчас у вас UserCRM.GetUser(name) может вернуть такого User-а, у которого Name не будет совпадать с name. Т.е. name и Name в вашем коде работы с пользователем - две совершенно разные вещи.

    В MVC многие вещи построены на convention-ах. Например, имена классов-контроллеров, механизм поиска представлений. Подтягивание значение по имени - это просто очередной convention, он просто не слишком заметен, пока на него не наткнешься.


    • Предложено в качестве ответа YatajgaEditor 12 мая 2012 г. 10:56
    • Помечено в качестве ответа Sergey Rogachev 12 мая 2012 г. 15:00