Asp.Net MVC 3自定义模型与变量对象的绑定

时间:2022-11-30 16:46:36

My entities: ( the PersonModel should have an address on type AddressOne or AddressTwo (and maybe others) so the PersonModel has an object type for the address field. )

我的实体:( PersonModel应该有一个AddressOne或AddressTwo类型的地址(可能还有其他),所以PersonModel有一个地址字段的对象类型。)

public class Person
{
    public int PersonId { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public object Address { get; set; }
}

public class AddressOne
{
    public string Street { get; set; }
    public string City { get; set; }
}

public class AddressTwo
{
    public string Province { get; set; }
    public string State { get; set; }
}

the models: (I pass an hidden field in typeOfAddress to match the correct address after the form submit)

模型:(我在typeOfAddress中传递一个隐藏字段,以匹配表单提交后的正确地址)

public class PersonModel
{
    private System.Type _typeOfAddress;
    private object _address;

    [Required]
    public int PersonId { get; set; }
    [Required]
    public string Name { get; set; }
    [Required]
    public string Surname { get; set; }

    public System.Type typeOfAddress
    {
        get { return _typeOfAddress; }
        set { _typeOfAddress = value; }
    }

    public object Address
    { 
        get {
            return _address;
        } 
        set {
            _address = value;
            _typeOfAddress = _address.GetType(); 
        } 
    }
}

public class AddressOneModel
{
    [Required]
    public string Street { get; set; }
    [Required]
    public string City { get; set; }
}

public class AddressTwoModel
{
    [Required]
    public string Province { get; set; }
    [Required]
    public string State { get; set; }
}

My view (for address field I have ad Editor Template that is omitted in this code):

我的观点(对于地址栏我有广告编辑模板,在此代码中省略):

@using (Html.BeginForm()) {

<ul>
<li> 
    PersonId: @Html.EditorFor(model => model.PersonId)
</li>
<li>
    Name: @Html.EditorFor(model => model.Name)
</li>
<li>
    Surname: @Html.EditorFor(model => model.Surname)
</li>
<li>
    Address:
</li>
<li>
    @Html.HiddenFor(model => model.typeOfAddress)
    @Html.EditorFor(model => model.Address)
</li>
</ul>
<button type="submit">Submit</button>

}

and then my controller: (in this example I load AddressOne in the model but should be One or Two depends at the run time...)

然后是我的控制器:(在这个例子中,我在模型中加载了AddressOne但应该是一个或两个取决于运行时......)

    [HttpGet]
    public ActionResult Index()
    {
        PersonModel myPerson = new PersonModel();

        myPerson.PersonId = 1;
        myPerson.Name = "Michael";
        myPerson.Surname = "Douglas";

        AddressOneModel Address = new AddressOneModel();
        Address.Street = "5th Avenue";
        Address.City = "New York";

        myPerson.Address = Address;

        return View(myPerson);
    }

    [HttpPost]
    public ActionResult Index([ModelBinder(typeof(PersonModelBinder))]PersonModel myPerson)
    {
        if (ModelState.IsValid) { 
            // some things here
        }
        return View();
    }

then there is the Model Binder for PersonModel:

然后是PersonModel的Model Binder:

public class PersonModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        PersonModel bindedModel = new PersonModel();

        foreach (var Property in typeof(PersonModel).GetProperties())
        {
            PropertyInfo info = bindedModel.GetType().GetProperty(Property.Name); 
            object castedInfo = new object();

            var uType = info.PropertyType;
            if (uType == typeof(string))
            {
                castedInfo = bindingContext.ValueProvider.GetValue(Property.Name).AttemptedValue.ToString();
            }
            else if (uType == typeof(Type))
            {
                castedInfo = Type.GetType(bindingContext.ValueProvider.GetValue(Property.Name).AttemptedValue.ToString());
            }
            else if (uType == typeof(object))
            {
                string objType = bindingContext.ValueProvider.GetValue("typeOfAddress").AttemptedValue; 
                object address = (object)Activator.CreateInstance(Type.GetType(objType));

                // another foreach as previous
            }
            else
            {
                object uCasted = (object)Activator.CreateInstance(info.PropertyType);
                uCasted = Convert.ChangeType(bindingContext.ValueProvider.GetValue(Property.Name).AttemptedValue, Property.PropertyType);
                castedInfo = uCasted;
            }
            info.SetValue(bindedModel, castedInfo, null);
        }
        return bindedModel;
    }

Is this the correct way to implement the binding of PersonModel? And what about validation in [Post] controller?

这是实现PersonModel绑定的正确方法吗?那么[Post]控制器中的验证呢?

I seen also a way to use DefaultBinder in a way like this:

我也看到了一种以这种方式使用DefaultBinder的方法:

[ModelBinderType(typeof(PersonModel))]
public class PersonModelBinder : DefaultModelBinder
{
     //...
}

but i don't find any reference of ModelBinderType in MVC3!! Any suggestion?

但我没有在MVC3中找到任何ModelBinderType的参考!有什么建议吗?

1 个解决方案

#1


2  

It seems like you're trying to do this the hard way. You shouldn't need a model binder. What I would do is add each type of address to the model and on the page display the one that is not null. This would save you a lot of hassle.

看起来你正在努力做到这一点。你不应该需要一个模型绑定器。我要做的是将每种类型的地址添加到模型中,并在页面上显示非空的地址。这样可以省去很多麻烦。

public class PersonModel : IValidatableObject 
{
    private System.Type _typeOfAddress;
    private object _address;

    [Required]
    public int PersonId { get; set; }
    [Required]
    public string Name { get; set; }
    [Required]
    public string Surname { get; set; }

    public System.Type typeOfAddress
    {
        get { return (AddressOne ?? AddressTwo ?? AddressThree).GetType(); }
    }

    public AdressOneModel AddressOne {get;set;}
    public AdressTwoModel AddressTwo {get;set;}
    public AdressThreeModel AddressThree {get;set;}
}

Then maybe on the page do this

然后也许在页面上这样做

@using (Html.BeginForm()) 
{
    <ul>
    <li> 
        PersonId: @Html.EditorFor(model => model.PersonId)
    </li>
    <li>
        Name: @Html.EditorFor(model => model.Name)
    </li>
    <li>
        Surname: @Html.EditorFor(model => model.Surname)
    </li>
    <li>
        Address:
    </li>
    <li>
    @if(model.AddressOne != null)
    {
        Html.EditorFor(model => model.AddressOne)
    }
    else if(model.AddressTwo != null)
    {
        Html.EditorFor(model => model.AddressTwo)
    }
    </li>
    </ul>
    <button type="submit">Submit</button>
}

But it really depends on why you're doing this

但这实际上取决于你为什么要这样做

#1


2  

It seems like you're trying to do this the hard way. You shouldn't need a model binder. What I would do is add each type of address to the model and on the page display the one that is not null. This would save you a lot of hassle.

看起来你正在努力做到这一点。你不应该需要一个模型绑定器。我要做的是将每种类型的地址添加到模型中,并在页面上显示非空的地址。这样可以省去很多麻烦。

public class PersonModel : IValidatableObject 
{
    private System.Type _typeOfAddress;
    private object _address;

    [Required]
    public int PersonId { get; set; }
    [Required]
    public string Name { get; set; }
    [Required]
    public string Surname { get; set; }

    public System.Type typeOfAddress
    {
        get { return (AddressOne ?? AddressTwo ?? AddressThree).GetType(); }
    }

    public AdressOneModel AddressOne {get;set;}
    public AdressTwoModel AddressTwo {get;set;}
    public AdressThreeModel AddressThree {get;set;}
}

Then maybe on the page do this

然后也许在页面上这样做

@using (Html.BeginForm()) 
{
    <ul>
    <li> 
        PersonId: @Html.EditorFor(model => model.PersonId)
    </li>
    <li>
        Name: @Html.EditorFor(model => model.Name)
    </li>
    <li>
        Surname: @Html.EditorFor(model => model.Surname)
    </li>
    <li>
        Address:
    </li>
    <li>
    @if(model.AddressOne != null)
    {
        Html.EditorFor(model => model.AddressOne)
    }
    else if(model.AddressTwo != null)
    {
        Html.EditorFor(model => model.AddressTwo)
    }
    </li>
    </ul>
    <button type="submit">Submit</button>
}

But it really depends on why you're doing this

但这实际上取决于你为什么要这样做