Question

Je crée quelques classeurs personnalisés pour les types complexes dans mon modèle. Mon modèle est composé d'objets qui ont leurs propres classeurs séparés. Je veux l'objet de base pour faire son travail sale, puis remplir l'objet complexe, il encapsule en faisant passer le routage standard ModelBinder. Comment puis-je faire?

A titre d'illustration, je l'ai créé un exemple très simple.

Dites mon modèle contient ces objets.

public class Person
{
    public string Name {get; set;}
    public PhoneNumber PhoneNumber {get; set;}
}

public class PhoneNumber
{
    public string AreaCode {get; set;}
    public string LocalNumber {get; set;}
}

et moi avons les liants suivants pour chacun de ces modèles. Non pas que le PersonBinder a besoin pour remplir le PhoneNumber mais ne veut pas dupliquer le code dans le classeur PhoneNumber. Comment faut-il déléguer à revenir à la stardard de routage Binder?

public class PersonBinder: IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext     bindingContext)
    {
        Person person = new Person();
        person.Name = bindingContext.ValueProvider.GetValue(String.Format("{0}.{1}", bindingContext.ModelName, "Name")).AttemptedValue

        // This is where I'd like to have the PhoneNumber object use binding from another customer ModelBinder.
        // Of course the bindingContext.ModelName should be updated to its current value + "PhoneNumber"
        person.PhoneNumber = ???;  // I don't want to explicitly call the PhoneNumberBinder it should go through standard Binding routing.  (ie.  ModelBinders.Binders[typeof(PhoneNumber)] = new PhoneNumberBinder();)

        return person;       
    }
}

public class PhoneNumberBinder: IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext     bindingContext)
    {
        PhoneNumber phoneNumber = new PhoneNumber();
        phoneNumber.AreaCode = bindingContext.ValueProvider.GetValue(String.Format("{0}.{1}", bindingContext.ModelName, "AreaCode")).AttemptedValue
        phoneNumber.LocalNumber = bindingContext.ValueProvider.GetValue(String.Format("{0}.{1}", bindingContext.ModelName, "LocalNumber")).AttemptedValue

        return phoneNumber;
    }
}

Et bien sûr, je me suis inscrit mes ModelBinders dans le fichier Global.asax.cs.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterRoutes(RouteTable.Routes);

    ModelBinders.Binders[typeof(Person)] = new PersonBinder();
    ModelBinders.Binders[typeof(PhoneNumber)] = new PhoneNumberBinder();
}

Merci,

Justin

Était-ce utile?

La solution

Eh bien, je réussi à trouver une solution. S'il vous plaît ne hésitez pas à commenter sa validité.

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
     Person person = new Person();
     person.Name = bindingContext.ValueProvider.GetValue("Name").AttemptedValue

     if (bindingContext.ModelName == String.Empty)
     {
         bindingContext.ModelName = "PhoneNumber";
     }
     else
     {
         bindingContext.ModelName = bindingContext.ModelName + ".PhoneNumber";
     }

     PhoneNumber phoneNumber = new PhoneNumber();
     bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => phoneNumber, phoneNumber.GetType());

     IModelBinder binder = ModelBinders.Binders[typeof(PhoneNumber)];
     if (binder == null)
     {
          binder = ModelBinders.Binders.DefaultBinder;
     }

     person.PhoneNumber = binder.BindModel(controllerContext, bindingContext) as PhoneNumber;

     return person;                         
}

Voici un résumé de ce que je l'ai fait.

  1. Lookup la ModelBinder en utilisant la collection ModelBinders.Binders globalement accessible (fallback par défaut si l'on est pas enregistré)
  2. Créer le ModelMetadataProvider pour le modèle que je suis lier à.
  3. Définissez la propriété ModelName du BindingContext à la propriété modèle que je suis en train de renseigner ( « PhoneNumber »).

Autres conseils

Au lieu d'écrire un liant vous pourriez utilisateur AutoMapper et gérer la construction de modèle complexe dans l'action.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top