2012-07-23 21 views
5

Meine Entitäten: (die PersonModel sollte eine Adresse auf Typen AddressOne oder AddressTwo hat (und vielleicht auch andere), so dass die PersonModel hat einen Objekttyp für das Adressfeld.)Asp.Net MVC 3 Benutzerdefinierte Modell Bindung mit variabler Objekt

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; } 
} 

die Modelle: (ich gehe ein verstecktes Feld in typeOfAddress die korrekte Adresse nach der Form übereinstimmen abschicken) (ich habe Anzeige Editor-Vorlage, die in diesem Code für Adressfeld weggelassen)

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; } 
} 

Meine Ansicht :

@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> 

} 

und dann mein Controller: (in diesem Beispiel I AddressOne im Modell laden, soll aber ein oder zwei hängt an der Laufzeit ... sein)

[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(); 
    } 

dann gibt es das Modell Binder für PersonModel :

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; 
    } 

Ist dies der richtige Weg, um die Bindung von PersonModel zu implementieren? Und was ist mit der Validierung im [Post] -Controller?

ich gesehen auch einen Weg DefaultBinder in einer Art und Weise, wie diese zu nutzen:

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

aber ich keinen Hinweis von ModelBinderType in MVC3 finden !! Irgendein Vorschlag?

Antwort

2

Es scheint, als ob Sie versuchen, dies auf die harte Tour zu tun. Sie sollten keinen Modellbinder benötigen. Ich würde jeden Adresstyp zum Modell hinzufügen und auf der Seite den Wert anzeigen, der nicht null ist. Dies würde Ihnen viel Ärger ersparen.

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;} 
} 

Dann vielleicht auf der Seite tun, um diese

@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> 
} 

Aber es hängt wirklich davon ab, warum Sie diese

tun