【问题标题】:Post a List<Interface> .net core 1.0发布 List<Interface> .net core 1.0
【发布时间】:2016-12-27 23:49:36
【问题描述】:

我正在 .net 核心中构建一个动态表单创建器。一个“表单”将由许多不同的表单元素组成。所以表单模型看起来像这样:

public class FormModel {
  public string FormName {get;set;}
  public List<IElements> Elements{get;set;}
}

我有 TextBoxElementTextAreaElementCheckBoxElement 的类,它们都实现了 IElemets 接口。每个元素我都有EditorTemplates。呈现表单的代码效果很好。尽管由于接口的List 无法发布表单。

我一直在研究如何实现自定义模型绑定器,并在网上看到了一些示例,但我没有让任何人工作。

如果有人能告诉我如何为此示例实现自定义模型绑定器,我将不胜感激。

B 计划: 将表单作为 json 发布到 web api 并让 JSON.Net 隐藏它。我已经尝试过了,它奏效了。在 startup.cs 我添加了:

services.AddMvc().AddJsonOptions(opts => opts.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto);

它在必要时返回类型,例如。 Elements-list 中的对象,但不在 FormModel 上的对象。但我真的很想知道如何使用自定义模型绑定器来解决它。

【问题讨论】:

  • 模型绑定器如何知道在发布时为列表元素实例化哪种类型?
  • 不知道为什么有人投了反对票。我想你必须发布一些额外的信息,让你的自定义模型绑定器知道要实例化什么类型的类。
  • 我认为 JSON.NET 可以通过序列化/反序列化类型名称来处理类型。如果您使用的是 JSON,那么也许您可以利用它。
  • 我的想法是隐藏类型的字段。
  • JSON.Net 可以反序列化,如果你在类型中包含一个 $type 参数,如果你做一些简单的事情。 JsonConvert.DeserializeObject(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });我不确定在发布到 Web api 时如何添加此设置。同样在这种情况下,我只希望在发布 json 时使用此设置,而不是在返回时,如果可能的话,现在任何人都可以吗?

标签: asp.net-mvc asp.net-core asp.net-core-1.0 custom-model-binder


【解决方案1】:

好的,这对我有用。我仍在掌握新的模型绑定,所以我可能会做一些愚蠢的事情,但这是一个开始!

测试表格

<form method="post">
    <input type="hidden" name="Elements[0].Value" value="Hello" />
    <input type="hidden" name="Elements[0].Type" value="InterfacePost.Model.Textbox" />

    <input type="hidden" name="Elements[1].Value" value="World" />
    <input type="hidden" name="Elements[1].Type" value="InterfacePost.Model.Textbox" />

    <input type="hidden" name="Elements[2].Value" value="True" />
    <input type="hidden" name="Elements[2].Type" value="InterfacePost.Model.Checkbox" />

    <input type="submit" value="Submit" />
</form>

界面

public interface IElement
{
    string Value { get; set; }
}

文本框实现

public class Textbox : IElement
{
    public string Value { get; set; }
}

复选框实现

public class Checkbox : IElement
{
    public string Value { get; set; }
}

模型粘合剂提供者

public class ModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (context.Metadata.ModelType == typeof(IElement))
        {
            return new ElementBinder();
        }

        // else...
        return null;
    }
}

模型粘合剂

public class ElementBinder : IModelBinder
{
    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType == typeof(IElement))
        {
            var type = bindingContext.ValueProvider.GetValue($"{bindingContext.ModelName}.Type").FirstValue;

            if (!String.IsNullOrWhiteSpace(type))
            {

                var element = Activator.CreateInstance(Type.GetType(type)) as IElement;

                element.Value = bindingContext.ValueProvider.GetValue($"{bindingContext.ModelName}.Value").FirstValue;

                bindingContext.Result = ModelBindingResult.Success(element);
            }
        }
    }
}

连接模型粘合剂提供者

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(options =>
        {
            options.ModelBinderProviders.Insert(0, new ModelBinderProvider());
        });
    }
}

形成模型

public class FormModel
{
    public string FormName { get; set; } // Not using this

    public List<IElement> Elements { get; set; }
}

动作

注意三种类型,文本框、文本框和复选框。

【讨论】:

  • 我试过这个例子。 bindingContext.ValueProvider.GetValue 返回 null bindingContext.ModelName 是一个空字符串
  • 没关系,我错过了 html 中的 name="Elements[0].Type"
  • 这很好用,但是如果 List 碰巧没有项目,那么整个 Form 模型将返回为 null。可以做些什么来解决这个问题?
  • @Tak90 如果它为空 - 我想这是因为没有发布数据。你能简单地检查代码中的空值吗?
  • @LeeGunn 谢谢回复我。问题是在我们的例子中接收一个空列表仍然有效,所以我们希望模型有一个名称但一个空或空列表。但是,在查看我的代码时,我意识到不是你的代码行为不端,而是我的错误。看我的问题Here,我自己回答了。非常感谢。
猜你喜欢
  • 2016-12-14
  • 1970-01-01
  • 1970-01-01
  • 2017-06-23
  • 2015-04-14
  • 1970-01-01
  • 2018-05-19
  • 1970-01-01
相关资源
最近更新 更多