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

elcex8rz  于 2023-08-08  发布在  .NET
关注(0)|答案(1)|浏览(76)

我正在尝试逐步更新我的ASP.NETMVC5网站,以便最终迁移到ASP.NETMVCCore。我曾经把一些数据放在隐藏字段中,并使用@Html.Serialize(“name”,value)将其序列化到隐藏字段中,然后在html POST时使用[Deserialize]属性将其反序列化到一个动作参数中。这曾经是Microsoft.AspNet.Mvc.Futures www.example.com nuget包的一部分5.0.0.0,它最近一次更新是在很多年前,我不知道它迁移到了什么地方,或者甚至没有继任者?

wz3gfoph

wz3gfoph1#

我基于旧的SerializationExtensions和DeserializeAttribute使用JSON编写了自己的替代品:
SerializationExtensions.cs:

using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace My.WebApplication {
    public static class SerializationExtensions {
        public static IHtmlContent JsonSerialize(this IHtmlHelper htmlHelper, string name) {
            return JsonSerializeInternal(htmlHelper, name, null, useViewData: true);
        }

        public static IHtmlContent JsonSerialize(this IHtmlHelper htmlHelper, string name, object data) {
            return JsonSerializeInternal(htmlHelper, name, data, useViewData: false);
        }

        private static IHtmlContent JsonSerializeInternal(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.JsonSerialize("oldValue", ViewData["oldValue"])


在您的控制器操作中:

public ActionResult Edit([JsonDeserialize] Test oldValue, Test value)


也许我会把它添加到github,这样其他人也可以使用它。
对于那些好奇我为什么使用它的人:这对于对象编辑页面来说很方便,在那里你想存储一个对象的旧值,并在发布时将它发送回控制器操作,所以在SQL UPDATE语句中,你把旧的字段值放在SQL WHERE子句中,以防止更新冲突(所以如果WHERE子句与当前数据库记录不匹配,UPDATE就会失败,这样另一个用户的更新就不会被默默地覆盖)。我想这是一个老学校的方式更新数据库记录,但它的固体,我喜欢它。

相关问题