0

j'ai un scénario où j'ai une certaine classe de base, nous l'appellerons « PagingCriteriaBase »Modèle personnalisé liant dans Asp.Net de base pour les sous classes

public class PagingCriteriaBase : CriteriaBase 
{ 
    public Int32 CountOfItemsPerPage { get; set; } 
    public SortOrder SortingOrder { get; set; } 
    public String SortBy { get; set; } 
    public Int32 PageNo { get; set; } 
    public PagingCriteriaBase(Int32 pageNo,Int32 countOfItemsPerPage, SortOrder sortingOrder, String sortBy,Int32 draw) 
    { 
     this.PageNo = pageNo>0?pageNo:1; 
     this.CountOfItemsPerPage = countOfItemsPerPage>0?countOfItemsPerPage:10; 
     this.SortBy = sortBy; 
     this.SortingOrder = sortingOrder; 
     this.Draw = draw; 
    } 
} 

et j'ai d'autres classes qui hériteront de " PagingCriteriaBase », par exemple

public class UserCriteria:PagingCriteriaBase 
{ 
    public String Email { get; set; } 
    public String DisplayName { get; set; } 

    public UserCriteria():base(1,0,SortOrder.Asc,"",1) 
    { 

    } 
    public UserCriteria(Int32 pageNo,Int32 countOfItemsPerPage, SortOrder sortingOrder, String sortBy, Int32 draw) 
     :base(pageNo, countOfItemsPerPage,sortingOrder,sortBy,draw) 
    { 
    } 
} 

maintenant, ce que je voudrais faire est que je voulais créer un classeur modèle qui sera utilisé avec les méthodes de l'API Web, et le liant de modèle sera utilisé avec toutes les sous-classes de "PagingCriteriaBase", le but de ce modèle de classeur est de définir certaines propriétés données o provenant de demandes ajax, j'ai essayé de faire ce qui suit:

  1. J'ai créé une classe qui implémente "IModelBinder" comme suit:

    public class PagingModelBinder : IModelBinder 
    { 
    
    public Task BindModelAsync(ModelBindingContext bindingContext) 
    { 
        if (!bindingContext.ModelType.IsSubclassOf(typeof(PagingCriteriaBase))) 
        { 
         return Task.FromResult(false); 
        } 
    
        String startModelName = "start"; 
        String lengthModelName = "length"; 
        var startResult = bindingContext.ValueProvider.GetValue(startModelName); 
        var lengthResult = bindingContext.ValueProvider.GetValue(lengthModelName); 
        Int32 start, length; 
        if (!Int32.TryParse(startResult.FirstValue, out start)) 
        { 
         start = 0; 
        } 
        if (!Int32.TryParse(lengthResult.FirstValue, out length)) 
        { 
         length = SystemProp.PAGE_SIZE; 
        } 
        else 
        { 
         length = 20; 
        } 
        var model = Activator.CreateInstance(bindingContext.ModelType); 
    
        Int32 pageNo = (int)Math.Ceiling((decimal)start/length); 
    
        bindingContext.ModelState.SetModelValue("PageNo", new ValueProviderResult(pageNo.ToString())); 
        bindingContext.ModelState.SetModelValue("CountOfItemsPerPage", new ValueProviderResult(length.ToString())); 
        bindingContext.Model = model; 
        var mProv = (IModelMetadataProvider)bindingContext.HttpContext.RequestServices.GetService(typeof(IModelMetadataProvider)); 
    
        bindingContext.Result = ModelBindingResult.Success(model); 
    
        return Task.CompletedTask; 
    } 
    } 
    
  2. J'ai créé un ModelBinderProvider comme suit:

    public class PagingEntityBinderProvider:IModelBinderProvider 
    { 
    public IModelBinder GetBinder(ModelBinderProviderContext context) 
    { 
        if (context == null) 
        { 
         throw new ArgumentNullException(nameof(context)); 
        } 
    
        if (context.Metadata.ModelType == typeof(PagingCriteriaBase)) 
        { 
         return new BinderTypeModelBinder(typeof(PagingModelBinder)); 
        } 
    
        return null; 
    } 
    } 
    
  3. J'enregistré le modèle de liaison utilisant:

    services.AddMvc(op => op.ModelBinderProviders.Insert(0, new PagingEntityBinderProvider())) ; 
    
  4. Dans ma méthode API Web j'ai fait ce qui suit:

    public IActionResult GetAll([ModelBinder(typeof(PagingModelBinder))]UserCriteria crit) 
    { 
    //Code goes here 
    } 
    

Quand je le liant modèle comme ci-dessus, j'ai découvert qu'une fois le code atteint les méthodes de l'API Web, rien de valeurs dans la classe est changé, par exemple "PageNo" propriété reste 1, Donc ce que je dois faire est d'avoir le liant de modèle définir toutes les propriétés connexes pour l'objet de la sous-classe indépendamment du type de la classe elle-même et à la fin code atteint la méthode API Web, le modèle aura toutes les propriétés définies correctement, pouvez-vous s'il vous plaît me signaler ce que dois-je changer dans mon code pour gérer cela?

S'il vous plaît noter que je suis en utilisant Asp.Net Core 2.0

Répondre

0

Je suppose que ce que vous avez défini aucune propriété du modèle, seulement instancié.

Je pense que nous pouvons faire une dépression toutes les propriétés de la sous-classe avec réflexion et définir la valeur en fonction de la valeur d'état du modèle (en supposant que le nom de la propriété est la même chose avec la clé d'état modèle)

public Task BindModelAsync(ModelBindingContext bindingContext) 
    { 
     ... 
     bindingContext.ModelState.SetModelValue("PageNo", new ValueProviderResult(pageNo.ToString())); 
     bindingContext.ModelState.SetModelValue("CountOfItemsPerPage", new ValueProviderResult(length.ToString())); 

     ModelStateEntry v; 
     foreach (PropertyInfo pi in bindingContext.ModelType.GetProperties()) 
     { 
      if (bindingContext.ModelState.TryGetValue(pi.Name, out v)) 
      { 
       try 
       { 
        pi.SetValue(model, v.RawValue); 
       } 
       catch 
       { 
       } 
      } 
     } 

     bindingContext.Model = model; 
     ... 
    } 

et changer votre PagingEntityBinderProvider

public class PagingEntityBinderProvider : IModelBinderProvider 
{ 
    public IModelBinder GetBinder(ModelBinderProviderContext context) 
    { 
     if (context == null) 
     { 
      throw new ArgumentNullException(nameof(context)); 
     } 

     if (typeof(PagingCriteriaBase).IsAssignableFrom(context.Metadata.ModelType)) 
     { 
      return new BinderTypeModelBinder(typeof(PagingModelBinder)); 
     } 

     return null; 
    } 
} 

et supprimez l'attribut ModelBinder de l'API Web Méthode

public IActionResult GetAll(UserCriteria crit) 
{ 
    //Code goes here 
} 
+1

merci @laksmono, Au début la méthode SetValue de "PropertyInfo" m'a donné une erreur due à différents types entre String et Int32 par exemple, mais j'ai changé le code pour être: pi.SetValue (model, Convert.ChangeType (v .RawValue, pi.PropertyType)) et cela a fonctionné comme prévu. –