我正在尝试逐步更新我的 ASP.NET MVC 5 网站,以便最终可以迁移到 ASP.NET MVC Core。我曾经将一些数据放入隐藏字段中,并使用 @Html.Serialize("name", value) 将其放入隐藏字段中,然后在 html POST 上使用 [Deserialize] 属性将其反序列化为操作参数。这曾经是 Microsoft.AspNet.Mvc.Futures 5.0.0.0 nuget 包的一部分,最后一次更新是在很多年前,我不知道它迁移到了什么,或者甚至没有后继者?
我根据旧的 SerializationExtensions 和 DeserializeAttribute 使用 JSON 编写了自己的替代品:
序列化扩展.cs:
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace My.WebApplication {
public static class SerializationExtensions {
public static IHtmlContent Serialize(this IHtmlHelper htmlHelper, string name) {
return SerializeInternal(htmlHelper, name, null, useViewData: true);
}
public static IHtmlContent Serialize(this IHtmlHelper htmlHelper, string name, object data) {
return SerializeInternal(htmlHelper, name, data, useViewData: false);
}
private static IHtmlContent SerializeInternal(IHtmlHelper htmlHelper, string name, object data, bool useViewData) {
if (htmlHelper == null) {
throw new ArgumentNullException("htmlHelper");
}
if (string.IsNullOrEmpty(name)) {
throw new ArgumentException(nameof(name));
}
name = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
if (useViewData) {
data = htmlHelper.ViewData.Eval(name);
}
string value = System.Text.Json.JsonSerializer.Serialize(data);
TagBuilder tagBuilder = new TagBuilder("input");
tagBuilder.Attributes["type"] = "hidden";
tagBuilder.Attributes["name"] = name;
tagBuilder.Attributes["value"] = value;
return tagBuilder;
}
}
}
JsonModelBinder.cs:
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace My.WebApplication {
public class JsonModelBinder : IModelBinder {
public Task BindModelAsync(ModelBindingContext bindingContext) {
if (bindingContext == null) {
throw new ArgumentNullException(nameof(bindingContext));
}
var modelName = bindingContext.ModelName;
// Try to fetch the value of the argument by name
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None) {
return Task.CompletedTask;
}
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var value = valueProviderResult.FirstValue;
// Check if the argument value is null or empty
if (string.IsNullOrEmpty(value)) {
return Task.CompletedTask;
}
try {
var model = System.Text.Json.JsonSerializer.Deserialize(value, bindingContext.ModelType);
bindingContext.Result = ModelBindingResult.Success(model);
} catch (Exception ex) {
bindingContext.ModelState.TryAddModelError(
modelName, ex.Message);
return Task.CompletedTask;
}
return Task.CompletedTask;
}
}
}
JsonDeserializeAttribute.cs:
using Microsoft.AspNetCore.Mvc;
namespace My.WebApplication {
public class JsonDeserializeAttribute : ModelBinderAttribute {
public JsonDeserializeAttribute() : base(typeof(JsonModelBinder)) {
}
}
}
您可以像旧的 @Html.Serialize() 和 [Deserialize] 组合一样使用它们:
@Html.Serialize("oldValue", ViewData["oldValue"])
在你的控制器操作中:
public ActionResult Edit([JsonDeserialize] Test oldValue, Test value)
也许我会将其添加到 github,以便其他人也可以使用它。
对于那些好奇我为什么使用这个的人:它对于对象编辑页面很方便,您想要在其中存储对象的旧值并在发布时将其发送回控制器操作,因此在 SQL UPDATE 语句中您可以放置旧字段值在 SQL WHERE 子句中,以防止更新冲突(因此,如果 WHERE 子句与当前数据库记录不匹配,则 UPDATE 会失败,因此其他用户的更新不会被静默覆盖)。我想这是一种更新数据库记录的老式方法,但它很可靠,我喜欢它。