【问题标题】:asp.net:How to pass the same data between Controller and View?asp.net:如何在Controller和View之间传递相同的数据?
【发布时间】:2026-02-17 17:30:01
【问题描述】:

我需要识别它是否是同一个客户端,所以在Controller的action方法中我将一个id放入视图模型中,稍后发送给视图。当用户在浏览器中输入一些内容并提交时,包含用户输入的视图模型和控制器发送给视图的 id 应该被发送回控制器。但是,在这种情况下,我在调试时发现返回给控制器的视图模型没有带 id。我错过了什么?

我猜也许 View 创建了一个新的视图模型来加载用户的输入,但是 id 在旧的视图模型中。

@model MicroCommunity.Models.RegisterViewModel
@{
    ViewBag.Title = "Register";
}

<h2>@ViewBag.Title.</h2>

@using (Html.BeginForm("Register", "Account", FormMethod.Post, new {@class = "form-horizontal", role = "form"}))
{
    @Html.AntiForgeryToken()
    <h4>Create a new account.</h4>
    <hr/>
    @Html.ValidationSummary("", new {@class = "text-danger"})



    <div class="form-group">
        @Html.LabelFor(m => m.Name, new {@class = "col-md-2 control-label"})
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Name, new {@class = "form-control"})
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.Department, new {@class = "col-md-2 control-label"})
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Department, new {@class = "form-control"})
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.EmployeeCardURL, new {@class = "col-md-2 control-label"})
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.EmployeeCardURL, new {@class = "form-control"})
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" class="btn btn-default" value="Register"/>
        </div>
    </div>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

以下是GET方法中的部分代码:

    // GET: /Account/Register
            var registerViewModel = new RegisterViewModel() {OpenId = wechatUserAccessToken.openid};
            return View(registerViewModel);

这里是帖子:

        // POST: /Account/Register
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Register(RegisterViewModel model)
        {
            if (ModelState.IsValid)
            {
                var user = new ApplicationUser
                {
                    Openid  =model.OpenId,
                    UserName = model.OpenId,
                    EmployeeCardURL = model.EmployeeCardURL,
                    Department = new Department() {Name = model.Department},
                    Name = model.Name
                };
                try
                {
                    var result = await UserManager.CreateAsync(user, model.OpenId);
                    if (result.Succeeded)
                    {
                        await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);

                        // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
                        // Send an email with this link
                        // string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
                        // var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
                        // await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");

                        return RedirectToAction("Index", "Home");
                    }
                    AddErrors(result);
                }
                catch (DbEntityValidationException e)
                {
                    foreach (var eve in e.EntityValidationErrors)
                    {
                        Console.WriteLine(
                            "Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
                            eve.Entry.Entity.GetType().Name, eve.Entry.State);
                        foreach (var ve in eve.ValidationErrors)
                        {
                            Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
                                ve.PropertyName, ve.ErrorMessage);
                        }
                    }
                    throw;
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

【问题讨论】:

  • 从视图和操作方法发布相关代码
  • 确保您使用的是相同的对象实例。
  • 请分享你的html文件
  • 为了确保 id 返回到控制器,您需要在输入控件的视图中呈现 tha id。由于在这种情况下 id 不需要可见,您可以使用 @htm.HiddenFor (m=>m.Id) 创建隐藏控件。这将创建一个模型绑定控件,当您提交表单时,其值将发送到服务器。
  • @guo 问题是您的 ID 没有绑定回您的模型。这意味着当您在视图中传递数据时,不能保证将数据返回到控制器中。要使其正常工作,请在您的视图中创建一个表示该 ID 的控件,如果 ID 在您的 UI 中不是一个重要因素,则可以使用隐藏字段。在这种情况下,它将自动绑定到您的模型。当然你的视图应该是强类型的

标签: c# asp.net .net asp.net-mvc


【解决方案1】:

视图中的OpenId 属性没有对应的input 字段,因此您不可能期望它以某种方式自动发送到您的POST 操作。因此,您可以考虑将其作为隐藏字段您的Html.BeginForm

@Html.HiddenFor(x => x.OpenId)

ASP.NET MVC 是无状态的。这意味着您在渲染视图时发送一个视图模型,但这并不能保证当您回发到另一个控制器操作时您将获得相同的视图模型。

现在,话虽如此,您应该知道,通过使用这种方法,任何人都可以向您的 POST 控制器操作发送请求,并伪造 OpenId 属性,具有他想要的任何值。如果您想确保此值没有被篡改,您可以考虑在 POST 操作中从您在 GET 操作中执行的相同位置(通常是数据库或缓存层)检索它。

所以在你的 POST 操作中:

string openId = wechatUserAccessToken.openid;

目前还不清楚这个 wechatUserAccessToken 实例是什么,但如果它在您的 POST 操作中不可用,那么您可以考虑将这个 openid 值存储在您的服务器上的某个位置(在数据库中?),这样您就不需要将其作为隐藏字段包含在每个请求中,而是将其与当前登录的用户会话相关联。这将保证该值在服务器上始终可用且不可篡改。

【讨论】:

  • 感谢您指出OpenId 可以伪造,但是我无法在POST 中检索OpenId,因为OpenId 用于识别用户。如果客户端没有将它的OpenId 发送给服务器,服务器就无法知道它是谁。
  • 不,这不是真的。您已经在GET 操作中很好地检索了这个值。因此,您可以简单地将其存储在服务器上的某个位置,并将其与当前用户会话相关联。您可以阅读有关 ASP.NET FORms 身份验证的更多信息以了解用户会话。