需要帮助解释Readonly\ScaffoldColumn(false)

ver*_*sus 3 http-post member-hiding asp.net-mvc-3

请帮忙解决这个问题并且不要严格判断因为我是MVC的新手:我有一个模型用于在我的数据库中按ID存储用户名

public class Names
    {
public int NameId { get; set; }
public string Username { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

,一个conrtoller

[HttpPost]
        public ActionResult EditforModel(Names Name)
        {
            if (ModelState.IsValid)
            {
                db.Entry(Name).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(Name);
        }
Run Code Online (Sandbox Code Playgroud)

添加和编辑视图添加工作正常,问题是关于编辑我使用

    @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>
Run Code Online (Sandbox Code Playgroud)

编辑我的模型.当我试图转到这个视图时,我看到了Id和用户名的编辑器,但是如果我填写Id - 我有错误,因为DB中没有带有这样ID的条目.好的.让我们寻找隐藏编辑器的属性.[ScaffoldColumn(false)]类似于标记是否为Id呈现编辑器.将它推荐给我的模型我从我的View中发布了"0"id.尝试另一个attr.[ReadOnly(true)]使字段成为只读字段.但同时我在发布Id时得到"0".修改视图我为模型中的每个字段放置了一个编辑器

@Html.HiddenFor(model => model.NameId)
@Html.EditorFor(model => model.Username)
Run Code Online (Sandbox Code Playgroud)

但使用它是危险的,因为一些用户可以发布错误的Id throgh post-request.

我不能使用[ScaffoldColumn(false)]在控制器的[Httppost]动作中应用Id,通过在DB中搜索适当的用户条目,因为名称已更改..我不敢相信@ Html.HiddenFor是唯一的出路.但找不到一个:(

Ahm*_*him 5

正如您所提到的那样"[ScaffoldColumn(false)]类似于标记是否为Id编辑器",而[ReadOnly(true)]意味着绑定模型时默认模型绑定器将排除此属性.

问题是HTTP协议是无状态协议,这意味着当用户将编辑表单发布到MVC控制器时,该控制器不知道他正在编辑哪个对象,除非您在收到的请求中包含一些标识符到您的对象来自用户,虽然包括真实对象Id因为你提到的原因不是一个好主意(有人可以发布另一个Id).

可能的解决方案可能是将带有加密ID的视图模型发送到View,并在控制器中解密此Id.

对象的视图模型可能如下所示:

public class UserViewModel
{
    [HiddenInput(DisplayValue = false)]
    public string EncryptedId { get; set; }
    public string Username { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

所以你的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);
    }
Run Code Online (Sandbox Code Playgroud)

不要忘记将View的模型更改为ViewModel

@model UserViewModel
Run Code Online (Sandbox Code Playgroud)

现在,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);
    }
Run Code Online (Sandbox Code Playgroud)

当用户尝试更改加密密钥时,解密将无法抛出CryptographicException,您可以在catch块中处理它.

你可以在这里找到SimpleAES加密类(不要忘记修复Key和Vector数组的值): C#的简单不安全双向"混淆"

PS:这个答案基于Henry Mori的以下答案: Asp.net MVC 3加密隐藏值