Нужна помощь, чтобы объяснить Readonly\ScaffoldColumn(false)
Пожалуйста, помогите с таким вопросом и не судите строго, потому что я новичок в MVC: у меня есть модель для хранения имен пользователей по идентификатору в моей БД
public class Names
{
public int NameId { get; set; }
public string Username { get; set; }
}
контролер
[HttpPost]
public ActionResult EditforModel(Names Name)
{
if (ModelState.IsValid)
{
db.Entry(Name).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(Name);
}
добавление и редактирование представления добавления работает хорошо, вопрос о редактировании я использую
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
<fieldset>
<legend> legend </legend>
@Html.EditorForModel()
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
редактировать мою модель. при попытке перейти к этому представлению я вижу редактор для идентификатора и имени пользователя, но если я заполняю идентификатор - у меня появляется ошибка, потому что нет записи в БД с таким идентификатором. Хорошо. Давайте посмотрим на атрибуты, чтобы скрыть редактор. [ScaffoldColumn(false)] является чем-то вроде маркера, отображать ли редактор для идентификатора или нет. Применив его к моей модели, я получил сообщение "0" из моего View.Try другой attr. [ReadOnly(true)] делает поле доступным только для чтения. Но в то же время у меня есть "0" при публикации идентификатора. Изменяя вид, я поместил редакторы для каждого поля в модели
@Html.HiddenFor(model => model.NameId)
@Html.EditorFor(model => model.Username)
но использовать его опасно, потому что какой-то пользователь может опубликовать неправильный Id throgh пост-запрос.
Я не могу использовать [ScaffoldColumn (false)] с применением идентификатора при действии [Httppost] контроллера, путем поиска соответствующей записи пользователя в БД, потому что имя было изменено. Я не могу поверить, что @Html.HiddenFor является Единственный выход. Но не могу найти один:(
1 ответ
Как вы упомянули, "[ScaffoldColumn(false)] является чем-то вроде маркера, отображать ли редактор для идентификатора или нет", а [ReadOnly(true)] означает, что это свойство будет исключено средством связывания модели по умолчанию при привязке вашей модели.
Проблема заключается в том, что протокол HTTP является протоколом без сохранения состояния, что означает, что когда пользователь отправляет форму редактирования на контроллер MVC, этот контроллер не имеет ни малейшего представления, какой объект он редактировал, если только вы не включили какой-либо идентификатор для вашего объекта в полученный запрос от пользователя, хотя включение реального идентификатора объекта не является хорошей идеей по той причине, которую вы упомянули (что кто-то может опубликовать другой идентификатор).
Возможным решением может быть отправка View View с зашифрованным Id в View и расшифровка этого Id в контроллере.
Модель представления для вашего объекта может выглядеть следующим образом:
public class UserViewModel
{
[HiddenInput(DisplayValue = false)]
public string EncryptedId { get; set; }
public string Username { get; set; }
}
Таким образом, ваш метод действия HttpGet будет
[HttpGet]
public ActionResult EditforModel()
{
// fetching the real object "user"
...
var userView = new UserViewModel
{
// passing the encrypted Id to the ViewModel object
EncryptedId = new SimpleAES().EncryptToString(user.NameId.ToString()),
Username = user.Username
};
// passing the ViewModel object to the View
return View(userView);
}
Не забудьте изменить модель для вашего View, чтобы он был ViewModel
@model UserViewModel
Теперь метод действия HttpPost будет получать UserViewModel
[HttpPost]
public ActionResult EditforModel(UserViewModel Name)
{
if (ModelState.IsValid)
{
try
{
var strId = new SimpleAES().DecryptString(Name.EncryptedId);
var id = int.Parse(strId);
// select the real object using the decrypted Id
var user = ...Single(p => p.NameId == id);
// update the value from the ViewModel
user.Username = Name.Username;
db.Entry(user).State = EntityState.Modified;
}
catch (CryptographicException)
{
// handle the case where the encrypted key has been changed
return View("Error");
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(Name);
}
Когда пользователь пытается изменить зашифрованный ключ, дешифрование завершится неудачей, и вы получите исключение CryptographicException, где вы можете обработать его в блоке catch.
Вы можете найти класс шифрования SimpleAES здесь (не забудьте исправить значения массивов Key и Vector): простая небезопасная двусторонняя "обфускация" для C#
PS: Этот ответ основан на следующем ответе Генри Мори: Asp.net MVC 3 Encrypt Hidden Values