【问题标题】:passing the 'TimeStamp' variable from cshtml page to controller via AJAX call通过 AJAX 调用将“TimeStamp”变量从 cshtml 页面传递到控制器
【发布时间】:2016-06-28 17:12:28
【问题描述】:

我是 EF 的 MVC 新手。我需要在应用程序中实现并发检查。

我正在关注有关 EF 中并发处理的内置支持的 MSDN 帮助:http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application

但就我而言,我正在进行部分更新,因此我使用 AJAX 调用服务器端方法来执行此操作。在这个服务器端方法中,我需要实现并发检查。

按照教程,我对代码进行了必要的更改:

首先在我的数据库中创建了时间戳列:

ALTER TABLE dbo.Job
ADD RowVersion rowversion NULL;

在实体类中:

[Timestamp]
public byte[] RowVersion { get; set; }

在我的映射类中(使用流利的 api):

this.Property(t =>     
    t.RowVersion).HasColumnName("RowVersion").IsConcurrencyToken();

在我的视图模型类中:

[Timestamp]
public byte[] RowVersion { get; set; }

在我的视图文件中:

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

在 JS 文件中(ajax 调用):

function UpdateJobTransferStatus(jobTransferStatusId, newJobTransferSatusId, currentAction, statusName) {
    var hdnJobId = $("#JobId").val();
    //var hdnRowVersion = $("#RowVersion").val();
    var hdnAccountingId = $("#hdnAccountingSystemId").val();
    $.ajax(
           {
               type: "GET",
               url: ResolveUrl("~/Api/Job/UpdateJobTransferStatus"),
               dataType: "json",
               contentType: "application/json; charset=utf-8",
               data: { jobId: hdnJobId, currentAction: currentAction, jobTransferStatusId: newJobTransferSatusId, accountingSystemId: hdnAccountingId },//,rowVersion: hdnRowVersion },
               success: function (data) {
                   GetPreviousOrNextStatus(jobTransferStatusId, currentAction, statusName, hdnAccountingId);
               },
               error: function (result) {

               }
           });

}

最后在我的控制器中(在我的 ajax 调用中): 我根据 MSDN (using System.Data.Entity.Infrastructure;) 添加了命名空间

[System.Web.Http.HttpGet]
public HttpResponseMessage UpdateJobTransferStatus(int jobId, int currentAction,
    int jobTransferStatusId, short accountingSystemId, byte[] rowVersion)

这里我总是得到 'null' 为 'byte[] rowVersion',无论我是否在 AJAX 调用中将值作为参数发送(我一直在我的代码 sn-p 中注释,我贴在这里)。

我已经检查过,每次成功执行插入/更新时,该列都会在数据库中更新,并且视图模型会在每次页面加载时从数据库中获取此 RowVersion 列的最新值。

在 MSDN 示例中,他们已经提交了表单,但我是使用 AJAX 调用来完成的,只是我试图保持每个方面都相同。

发送整个视图模型对象可能会为我完成这项工作,但我不需要整个对象来执行我的部分更新(虽然我没有尝试过)。

如何将rowVersion 传递给 ajax 调用?

【问题讨论】:

  • 感谢 Paul,我在提交后立即意识到格式错误,但您比我快得多。 :D

标签: c# ajax asp.net-mvc entity-framework asp.net-mvc-5


【解决方案1】:

您应该将其作为字符串发送,然后在服务器上将其转换回字节数组。这是因为 HTML 页面将其作为字符串存储在 base64 格式的 input 标记(隐藏类型)中。在 c# 端稍作改动应该可以解决它。

查看:现有代码无需更改,HiddenFor 在传入byte[] 时的默认行为是将其转换为Base 64 字符串

c#代码

[System.Web.Http.HttpGet]
public HttpResponseMessage UpdateJobTransferStatus(int jobId, int currentAction, int jobTransferStatusId, short accountingSystemId, string rowVersion){
    var rowVersionBytes = System.Convert.FromBase64String(rowVersion); // convert to byte array
}

Javascript:

function UpdateJobTransferStatus(jobTransferStatusId, newJobTransferSatusId, currentAction, statusName) {
    var hdnJobId = $("#JobId").val();
    var hdnRowVersion = $("#RowVersion").val(); // this will be a string
    var hdnAccountingId = $("#hdnAccountingSystemId").val();
    $.ajax(
       {
           type: "GET",
           url: ResolveUrl("~/Api/Job/UpdateJobTransferStatus"),
           dataType: "json",
           contentType: "application/json; charset=utf-8",
           data: { jobId: hdnJobId, currentAction: currentAction, jobTransferStatusId: newJobTransferSatusId, accountingSystemId: hdnAccountingId, rowVersion: hdnRowVersion }
           success: function (data) {
               GetPreviousOrNextStatus(jobTransferStatusId, currentAction, statusName, hdnAccountingId);
           },
           error: function (result) {
           }
       });
}

最后,因为您实际上是在执行更新,所以这应该是 HttpPost 或 HttpPut 而不是 HttpGet。

  • HttpGet 仅应在检索数据且未更改数据时使用。
  • 当可以多次调用相同的修改并获得完全相同的预期结果(这也称为幂等)时,应使用 HttpPut,这通常用于更新。
  • HttpPost 应该在每次调用相同的调用会导致不同的结果(无论是在服务器上还是在响应中)时使用,这通常用于 Creates

我在您的 sql 中发现了另一个错误,这可能会导致现有数据出现意外问题。列RowVersion 应标记为NOT NULL,因为即使在现有表上,当指定rowversion 类型时,Sql Server 也会使用一个值填充所有现有记录。

ALTER TABLE dbo.Job
ADD RowVersion rowversion NOT NULL

【讨论】:

  • 将时间戳序列化为base64不是更好吗?如果时间戳中的任何字节超出 UTF8 范围,您所拥有的将无法工作。
  • @MikeMcCaughan - 这可能吗? rowversion 由 8 个字节组成(每个字节的值是 0-255)。我认为 UTF8 不会有这个问题,因为单个 utf8 字符的大小可以是 1 到 4 个字节。但是,在 Controller 和 View 上明确指定相同的转换并不是一个坏主意,这样就不会混淆用于字节数组转换的格式。让我更新我的答案。
  • @MikeMcCaughan - 我再次更新了我的答案。事实证明,当一个字节数组 (byte[]) 被传递给HiddenFor 时,默认也是将它转换为一个 base 64 字符串(不知道这是可配置的还是硬编码的等)。所以你是对的,正确的答案是在Controller中调用FromBase64String
  • 这需要更多的支持。构建您自己的模型绑定器需要手动处理时间戳。
猜你喜欢
  • 2020-02-26
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多