C# 复杂的ASP.NET MVC绑定

C# 复杂的ASP.NET MVC绑定,c#,asp.net-mvc,C#,Asp.net Mvc,我一直在研究模型绑定,以解决我遇到的一个特定问题。我尝试了各种博客和答案中描述的一些方法,但我并没有真正做到这一点 首先,我将介绍我的模型: public class CampaignModel { [Required] [StringLength(24)] [Display(Name = "CampaignModel_Name", Prompt = "CampaignModel_Name", ResourceType = typeof(CampaignResources

我一直在研究模型绑定,以解决我遇到的一个特定问题。我尝试了各种博客和答案中描述的一些方法,但我并没有真正做到这一点

首先,我将介绍我的模型:

public class CampaignModel
{
    [Required]
    [StringLength(24)]
    [Display(Name = "CampaignModel_Name", Prompt = "CampaignModel_Name", ResourceType = typeof(CampaignResources))]
    public string Name { get; set; }

    [StringLength(255)]
    [Display(Name = "CampaignModel_Description", Prompt = "CampaignModel_Description", ResourceType = typeof(CampaignResources))]
    public string Description { get; set; }

    [Required]
    [DataType(DataType.Date)]
    [Display(Name = "CampaignModel_StartDate", ResourceType = typeof(CampaignResources))]
    public DateTime StartDate { get; set; }

    [Required]
    [DataType(DataType.Date)]
    [Display(Name = "CampaignModel_EndDate", ResourceType = typeof(CampaignResources))]
    public DateTime EndDate { get; set; }

    [Display(Name = "CampaignModel_Tags", Prompt = "CampaignModel_Tags", ResourceType = typeof(CampaignResources))]
    public TagList Tags { get; set; }
}
因此,除了最后一个属性标记列表之外,这是一个相当基本的模型。现在在我的模型的未来分配将有一个标记列表,所以这对我来说是相当重要的。标记列表如下所示:

public class TagList : List<Tag>
{
}
My ModelBinder(在global.asax中设置为DefaultModelBinder)

公共类标记ListModelBinder:DefaultModelBinder
{
受保护的覆盖无效绑定属性(
ControllerContext ControllerContext,
ModelBindingContext bindingContext,
PropertyDescriptor PropertyDescriptor)
{
if(propertyDescriptor.PropertyType==typeof(标记列表))
{
ValueProviderResult值=bindingContext.ValueProvider.GetValue(propertyDescriptor.Name);
字符串[]rawTags=value.AttemptedValue.Split(',');
List tagIds=新列表();
标记列表标记=新标记列表();
foreach(rawTag中的字符串rawTag)
{
长id;
if(长锥虫(rawTag,out id))
{
//需要从数据库中检索现有标记
tagid.Add(id);
}
其他的
{
//可以简单地添加新标签,而无需ID
Add(新标记{Text=rawTag});
}
}
如果(tagIds.Count>0)
{
使用(TagServiceClient=new TagServiceClient())
{
List existingTags=client.GetTagsByIds(tagid);
AddRange(existingTags.Select(t=>newtag{Id=t.Id,Text=t.Text}));
}
}
propertyDescriptor.SetValue(bindingContext.Model,标记);
}
BindProperty(controllerContext、bindingContext、propertyDescriptor);
}

检查此项:。希望它能帮助您!

最好的方法是从
DefaultModelBinder
继承并检查您正在处理的属性。如果它是
TagList
类型,请继续应用您需要的任何逻辑。否则,让默认实现完成工作

public class TagListModelBinder : DefaultModelBinder
{
    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor )
    {
        if (propertyDescriptor.PropertyType == typeof(TagList))
        {
            ValueProviderResult value = bindingContext.ValueProvider.GetValue(propertyDescriptor.Name);
            string[] rawTags = value.ToString().Split(',');

            TagList tags = new TagList();
            foreach (string rawTag in rawTags)
            { 
                // for numbers - get them from DB
                // for strings - create new and store in DB
                // then add them to tags
            }

            propertyDescriptor.SetValue(bindingContext.Model, tags);
        }
        else
        {
            base.BindProperty(controllerContext, bindingContext, propertyDescriptor)
        }
    }
}

如果要在ajax调用中发回此数据,则可以准备数据,使其绑定到模型属性标记列表

我假设Tag类的结构是

public class Tag
{
    public string Name {get; set;}
    public string Id {get; set;}
}
在进行ajax调用时,您可以

  • 拆分逗号(,)上隐藏字段的值
  • 将每个标记值添加为

    拆分列表中的Foreach标记

    data.push(“名称”:“标记列表[count].name”、“值”、“要绑定的名称”)

    data.push(“名称”:“标记列表[count].Id”、“值”、“要绑定的Id”)

    计数++


  • 并将此数据与ajax请求一起发布,希望它能绑定到您的模型。

    我应该为DefaultModelBinder注册此类型,还是专门为标记列表类型注册此类型?@IvanL,因为此绑定不会干扰任何其他类型,因此只需替换默认类型应该不会有任何伤害:
    ModelBinders.Binders.DefaultBinder=new TagListModelBinder();
    我尝试了解决方案,但遇到了异常“从类型'System.String'到类型'ROCME.EventDrive.Backend.Models.Shared.Tag'的参数转换失败,因为没有类型转换器可以在这些类型之间转换。”尽管我看到绑定按预期进行,但我还需要以与.ToString()不同的方式处理ValueProviderResult结果是类型名而不是实际使用的值。@IvanL,好吧,这意味着一般的方法是可行的,但实现中有一些问题。但是,如果没有看到实际的代码,很难说什么。你是如何以及在哪里进行失败的转换的?这很奇怪,我没有做任何转换,这是我唯一能做的事情想想看,它在我的view/EditorTemplate中失败了,这里使用的是:
    ViewData.TemplateInfo.FormattedModelValue
    。我将添加我正在使用的代码。我不是使用ajax发布数据,而是直接提交表单
    public class TagListModelBinder : DefaultModelBinder
    {
        protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor )
        {
            if (propertyDescriptor.PropertyType == typeof(TagList))
            {
                ValueProviderResult value = bindingContext.ValueProvider.GetValue(propertyDescriptor.Name);
                string[] rawTags = value.ToString().Split(',');
    
                TagList tags = new TagList();
                foreach (string rawTag in rawTags)
                { 
                    // for numbers - get them from DB
                    // for strings - create new and store in DB
                    // then add them to tags
                }
    
                propertyDescriptor.SetValue(bindingContext.Model, tags);
            }
            else
            {
                base.BindProperty(controllerContext, bindingContext, propertyDescriptor)
            }
        }
    }
    
    public class Tag
    {
        public string Name {get; set;}
        public string Id {get; set;}
    }