【问题标题】:How to convert a http-request into the right object?如何将 http-request 转换为正确的对象?
【发布时间】:2011-06-13 22:40:16
【问题描述】:

在我的 ASP.Net MVC3 项目中,我创建了一个绑定基本模型的 ModelBinder。在我的视图中,我从继承自我的基本模型的模型创建一个对象。现在,当我按下提交按钮时,我想知道哪个模型是通过我的 ModelBinder 中的反射创建的,但是如何?

模型绑定器:

public class MBTestBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        //need to know which Model was created -> convert into the right object
        //reflection?
    }
}

型号:

[ModelBinder(typeof(MBTestBinder))]
public class MBTest
{
    public string Name { get; set; }
    public MBTest()  {}
}

public class MBAbl : MBTest
{
    public MBAbl()  {}
    public string House { get; set; }
}

查看:

@model ModelBinderProject.Models.MBTest

@using (Html.BeginForm("Index", "Home")) {
<fieldset>
    <div class="editor-field">
        @Html.EditorForModel(Model)
    </div>
    <p>
        <input type="submit" value="Create" />
    </p>
</fieldset>

控制器:

public ActionResult Create(MBTest testItem)
{
    //on init get a view from a class that hast inherit the class MBTest
    if (testItem.Name == null ) testItem = new MBAbl();

    return View(testItem);
}

编辑:

使用bindingContext.ValueProvider.GetValue("House") 我可以获取表单的值,但bindingContext.ModelType 认为我的模型是MBTest

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-3 c#-4.0 razor modelbinder


    【解决方案1】:

    查看ModelBindingContext 文档。

    基于 cmets 编辑

    public class MBTestBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var result = bindingContext.ValueProvider.GetValue("Name");
    
            if (result == null || string.IsNullOrEmpty(result.AttemptedValue))
               return new MBAbl();
            else
               return new MBTest();
        }
    }
    

    【讨论】:

    • bindingContext.ModelType 仅返回基类 - 不起作用:-(
    • @Eranga UpdateModel(..) 再次调用 ModelBinder,因此 ModelBinder 获得 bindingContext.Model。但这并不影响观点。第一次视图有两种形式(House & Name)。当我按下提交时,modelbinder 没有检测到继承类,只检测到 basemodel。
    • @myName 更新了答案。您可以添加任何自定义逻辑来确定BindModel 方法中的模型
    • @Eranga 好吧,它有效,但这不是重点。我还可以在我的模型中添加一个整数变量来指定模型并使用 switch/case 来确定该模型是否已创建。但是必须有更好的解决方案来找出创建了什么模型。我不想为从我的 basclass 继承的每个类编辑 modelbinder ;-)
    • 那么您如何建议框架应该知道要创建什么对象?用魔法?我的意思是,如果你把它发挥到极致,你还不如在你的控制器中拥有一个名为 Create(object o) 的方法?
    【解决方案2】:

    最后,我通过在模型中携带模型名称并在模型绑定器中动态创建正确模型的解决方法解决了这个问题。 如果您知道更好的解决方案,请告诉我:-)

    家庭控制器:

    // CREATE
    public ActionResult About(MBTest testItem)
    {
        if (testItem == null)
        {
            testItem = new MBAbl();
            testItem.Model = "MBAbl";
        }
    
        return View(testItem);
    }
    

    型号:

    public class MBTest
    {
        public MBTest()  {}
    
        [HiddenInput]
        public string Model { get; set; }
    
        public string Name { get; set; }
    }
    
    public class MBAbl : MBTest
    {
        public MBAbl()  {}
    
        public string House { get; set; }
    }
    
    public class MBAb2 : MBTest
    {
        ...
    }
    

    模型绑定器:

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (controllerContext == null) throw new ArgumentNullException("controllerContext");
        if (bindingContext == null) throw new ArgumentNullException("bindingContext");
    
        //string 'Model' is needed in the base class
        var modelType = bindingContext.ValueProvider.GetValue("Model");
    
        if (modelType != null && !string.IsNullOrEmpty(modelType.AttemptedValue))
        {
            string projectName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
    
            Type classtype = Type.GetType(string.Format("{0}.Models.{1}", projectName, modelType.AttemptedValue));
            PropertyInfo[] properties = classtype.GetProperties();
    
            var classObject = classtype.GetConstructor(new Type[] { }).Invoke(null);
    
            foreach (PropertyInfo propertie in properties)
            {
                var value = bindingContext.ValueProvider.GetValue(propertie.Name).AttemptedValue;
                classtype.GetProperty(propertie.Name).SetValue(classObject, value, null);
            }
    
            return classObject;
        }
        return null;
    }
    

    【讨论】:

      【解决方案3】:

      试试这个:

      public class ModelBinder : DefaultModelBinder, IModelBinder
      {
          public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
          {
              var typeValue = bindingContext.ValueProvider.GetValue("ModelType");
              var type = Type.GetType("Namespace.a.b." + typeValue.AttemptedValue.ToString());
      
              var model = Activator.CreateInstance(type);
      
              //Change the model
              bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type);
              bindingContext.ModelMetadata.Model = model;
      
              //Here, we used the default model binder of the mvc
              return base.BindModel(controllerContext, bindingContext);;
          }
      }
      

      【讨论】:

      • 您应该在答案中添加描述,而不仅仅是发布代码。
      猜你喜欢
      • 2021-10-14
      • 1970-01-01
      • 1970-01-01
      • 2012-05-14
      • 2015-04-24
      • 1970-01-01
      • 1970-01-01
      • 2014-10-26
      • 1970-01-01
      相关资源
      最近更新 更多