@Html.Serialize 和 [Deserialize] 当前的 ASP.NET MVC 替代品是什么?

问题描述 投票:0回答:1

我正在尝试逐步更新我的 ASP.NET MVC 5 网站,以便最终可以迁移到 ASP.NET MVC Core。我曾经将一些数据放入隐藏字段中,并使用 @Html.Serialize("name", value) 将其放入隐藏字段中,然后在 html POST 上使用 [Deserialize] 属性将其反序列化为操作参数。这曾经是 Microsoft.AspNet.Mvc.Futures 5.0.0.0 nuget 包的一部分,最后一次更新是在很多年前,我不知道它迁移到了什么,或者甚至没有后继者?

c# asp.net asp.net-mvc asp.net-core asp.net-mvc-5
1个回答
0
投票

我根据旧的 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 会失败,因此其他用户的更新不会被静默覆盖)。我想这是一种更新数据库记录的老式方法,但它很可靠,我喜欢它。

© www.soinside.com 2019 - 2024. All rights reserved.