2011-08-23 2 views
0

Un avertissement: J'ai relativement nouveau à MVC et son paradigme et à certains de ses rouages, mais je suis assez à l'aise avec elle. Ceci est ma deuxième application MVC au sol et je suis un peu perplexe sur la façon de résoudre un "problème" trouvé par l'un de nos testeurs.ASP.NET MVC UpdateModel() paramètres de conversion des paramètres

Ce que les utilisateurs obtiennent est un écran d'édition donné une date effective pour les taux quotidiens LIBOR qui proviennent de la trésorerie (pourcentages). Les taux sont toujours entre 0 et 100 et par conséquent j'ai essayé de contraindre cette gamme en utilisant un RangeAttribute dans les métadonnées pour un de mes objets de domaine. J'ai indiqué la gamme comme ceci:

[Required, DisplayName("Published Rate"), Range(typeof(decimal), "0", "100")] 
public object PublishedRate { get; set; } 

Notez que je passe dans les valeurs de chaîne comme RangeAttribute ne dispose pas d'un constructeur surchargé qui prend décimaux. Cela semble fonctionner à merveille jusqu'à ce qu'un utilisateur va et entre quelque chose hors de l'ordinaire, comme:

« 0,000000000000000000000000000000001 »

Cela provoque UpdateModel() à l'échec; le ModelState montre cette erreur (trois fois pour la même valeur ModelState, curieusement):

La conversion des paramètres de type 'System.String' taper 'System.Decimal' a échoué.

Creuser dans les erreurs révèle la cause. La première ligne ci-dessous est ce qui est rapporté par la validation pour le champ. Je l'ai trouvé curieux que cela n'a pas bouillonner au modèle erreurs de validation (à savoir ne se présente pas dans la liste de validation sommaire pour le modèle):

« 0,000000000000000000000000000000001 n'est pas une valeur valide pour décimal. » "La valeur était trop grande ou trop petite pour un nombre décimal."

System.Web.Mvc.ValueProviderResult.ConvertSimpleType() et System.ComponentModel.BaseNumberConverter.ConvertFrom() lèvent les exceptions.

Un utilisateur n'entrera jamais dans une valeur comme celle-ci, mais cela ne me dérangerait pas de savoir s'il existe des mécanismes intégrés à MVC qui pourraient ou vont l'empêcher (côté serveur, c'est-à-dire). Il ne semble pas y avoir de problème avec des chiffres comme ceux-ci, cela ne semble que rompre avec ceux qui sont très petits.

« 0,555555555555555555555555555555555 »

Je ne ai vraiment besoin à la fin de la journée 9 chiffres de précision. La colonne de la table de base de données qui supporte ces valeurs est decimal(9,6). Je sais que je pourrais implémenter un classeur de modèle personnalisé pour mon modèle et collecter manuellement les valeurs de la demande, mais il doit y avoir quelque chose d'un peu plus facile, comme un FilterAttribute personnalisé ou quelque chose qui peut corriger la valeur avant d'être lié à le modèle, je ne suis pas sûr de quoi, et je cherche des suggestions.

Je semble me souvenir d'avoir lu quelques problèmes en essayant de contraindre des valeurs décimales en utilisant un RangeAttribute mais je ne me souviens pas du problème. Peut-être que vous les gourous MVC là-bas pouvez faire la lumière sur la situation.

Répondre

0

Donc, après quelques heures de coups de tête, je me suis installé sur le modèle de liant personnalisé suivant pour les décimales. Il s'assure que toutes les valeurs décimales sont analysables avant de les lier.

public class TreasuryIndexRateDecimalBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     var providerResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 
     if (providerResult != null) 
     { 
      decimal value; 
      if (!decimal.TryParse(providerResult.AttemptedValue, NumberStyles.Float, CultureInfo.CurrentCulture, out value)) 
      { 
       // TODO: Decide whether to show an error 
       // bindingContext.ModelState.AddModelError(bindingContext.ModelName, "error message"); 
       return 0m; 
      } 
      return Math.Round(value, 6); 
     } 
     return base.BindModel(controllerContext, bindingContext); 
    } 
} 

La liaison est mis en place dans Application_Start() pour l'enregistrer pour toutes les valeurs décimales.

protected void Application_Start() 
{ 
    ModelBinders.Binders.Add(typeof(decimal), new TreasuryIndexRateDecimalBinder()); 

    AreaRegistration.RegisterAllAreas(); 
    RegisterRoutes(RouteTable.Routes); 
} 

À moins que quelqu'un ne propose une approche plus intéressante, je pense que je m'en tiendrai là.

0

Vous pouvez utiliser un attribut Regex pour contenir la décimale avec une précision de 9. Cela vous permettra également d'ajouter un message personnalisé lorsque l'expression Regex échoue, comme "Votre valeur peut avoir un maximum de 9 places après la décimale " ou quelque chose de similaire. De plus, si vous avez activé la validation côté client, Regex fonctionnera tant pour la validation côté client que côté serveur.

Questions connexes