samedi 3 octobre 2009

xVal - ValidationAspects RulesProvider

Le framework xVal permet de déployer les règles de validation côté serveur vers l'interface web. Il peut utiliser différents frameworks du côté client comme JQuery ou ASP.net. De la même manière il peut s'appuyer sur différents framework de validation pour déduire les règles de validation serveur. Et il s'intègre particulièrement bien à ASP.net MVC !

De son côté ValidationAspects est un framework de validation assez simple d'utilisation.

Ni l'un ni l'autre de ces deux frameworks ne propose d'implémentation les rendant compatibles mais en regardant le source des fournisseurs de règles xVal pour Castle ou NHibernate, on ne met pas bien longtemps à en construire un pour ValidationAspects ... d'ailleur le voici :



using xVal.RuleProviders;
using VA = ValidationAspects;
using xVal.Rules;
using System.Reflection;
using ValidationAspects.Sdk;
using ValidationAspects.Factories;

namespace TestsApp.Validation.xVal
{
public class ValidationAspectsRulesProvider : CachingRulesProvider
{
private readonly RuleEmitterList<ValidatorAttribute> validationRuleEmitters = new RuleEmitterList<ValidatorAttribute>();

public ValidationAspectsRulesProvider()
{
var e = validationRuleEmitters;
e.AddSingle<VA.GreaterThanAttribute>(MakeGreaterThanRule);
e.AddSingle<VA.InRangeAttribute>(MakeInRangeRule);
e.AddMultiple<VA.IsDateAttribute>(x => new Rule[] {
new RequiredRule(),
new DataTypeRule(DataTypeRule.DataType.Date)
});
e.AddSingle<VA.IsEmailAttribute>(x => new DataTypeRule(DataTypeRule.DataType.EmailAddress));
e.AddSingle<VA.LengthInRangeAttribute>(MakeLengthInRangeRule);
e.AddSingle<VA.LessThanAttribute>(MakeLessThanRule);
e.AddSingle<VA.MatchesRegexAttribute>(MakeMatchesRegexRule);
e.AddSingle<VA.MaximumAttribute>(MakeMaximumRule);
e.AddSingle<VA.MaximumLengthAttribute>(MakeMaximumLengthRule);
e.AddSingle<VA.MinimumAttribute>(MakeMinimumRule);
e.AddSingle<VA.MinimumLengthAttribute>(MakeMinimumLengthRule);
e.AddSingle<VA.NotNullAttribute>(x => new RequiredRule());
e.AddSingle<VA.NotNullOrEmptyAttribute>(x => new RequiredRule());
}


protected override RuleSet GetRulesFromTypeCore(Type type)
{
// Rêgles de validation
var rules = from member in type.GetMembers(BindingFlags.Instance | BindingFlags.Public)
// pour les champs et propriétés
where (member.MemberType == MemberTypes.Field || member.MemberType == MemberTypes.Property)
// joints à leurs attributs hérité du framework de validation
from att in GetMemberAttributes(member)
// et joints aux rêgles qui en découle
from rule in ConvertToXValRules(att)
select new { MemberName = member.Name, Rule = rule };
;

return new RuleSet(rules.ToLookup(x => x.MemberName, x => x.Rule));
}

IEnumerable<ValidatorAttribute> GetMemberAttributes(MemberInfo member)
{
return member.GetCustomAttributes(true).Where(att => att is ValidatorAttribute)
.Cast<ValidatorAttribute>();
}

private IEnumerable<Rule> ConvertToXValRules(ValidatorAttribute att)
{
return validationRuleEmitters.EmitRules(att);
}


#region MakeRules

private Rule MakeInRangeRule(VA.InRangeAttribute att)
{
var facto = att.Factory as InRange;
return new RangeRule(Convert.ToDecimal(facto.Minimum), Convert.ToDecimal(facto.Maximum));
}
private Rule MakeGreaterThanRule(VA.GreaterThanAttribute att)
{
var facto = att.Factory as GreaterThan;
return new RangeRule(Convert.ToDecimal(facto.Value), null);
}
private Rule MakeMinimumRule(VA.MinimumAttribute att)
{
var facto = att.Factory as Minimum;
return new RangeRule(Convert.ToDecimal(facto.Value), null);
}
private Rule MakeLessThanRule(VA.LessThanAttribute att)
{
var facto = att.Factory as LessThan;
return new RangeRule(null, Convert.ToDecimal(facto.Value));
}
private Rule MakeMaximumRule(VA.MaximumAttribute att)
{
var facto = att.Factory as Maximum;
return new RangeRule(null, Convert.ToDecimal(facto.Value));
}

private Rule MakeLengthInRangeRule(VA.LengthInRangeAttribute att)
{
var facto = att.Factory as LengthInRange;
return new StringLengthRule(facto.Minimum, facto.Maximum);
}
private Rule MakeMinimumLengthRule(VA.MinimumLengthAttribute att)
{
var facto = att.Factory as MinimumLength;
return new StringLengthRule(facto.Length, null);
}
private Rule MakeMaximumLengthRule(VA.MaximumLengthAttribute att)
{
var facto = att.Factory as MaximumLength;
return new StringLengthRule(null, facto.Length);
}

private Rule MakeMatchesRegexRule(VA.MatchesRegexAttribute att)
{
var facto = att.Factory as MatchesRegex;
return new RegularExpressionRule(facto.Regex);
}

#endregion
}
}



Enjoy !

Asp.net MVC Editors using lambda expressions

Asp.net MVC c'est génial mais ASP.net MVC 2 sera encore mieux, notamment grâce à une amélioration des helpers et des méthodes d'extensions des vues permettant de typer l'accès aux membres du model grâce aux expressions lambda.

Si vous ne voulez pas attendre et que vous voulez vous aussi pouvoir écrire :


<%= Html.TextBoxFor(Model, m => m.Libelle) %>


la suite vas vous intéresser.

Commencez par écrire une classe permettant de stocker pour un membre de classe, son type, son nom et sa valeur :



class PropertyDef
{
public Type Type { get; private set; }
public string Name { get; private set; }
public object Value { get; private set; }

public PropertyDef(Type type, String name, object value)
{
this.Type = type;
this.Name = name;
this.Value = value;
}
}



Ensuite nous allons devoir créer un helper permettant de parser une expression lambda récupérer précisément ces éléments :



static class LambdaExpressionParser
{
internal static PropertyDef GetPropertyDef<TModel, TValue>(
this Expression<Func<TModel, TValue>> expression, TModel model)
{
ExpressionType nodeType = expression.Body.NodeType;
if (nodeType != ExpressionType.MemberAccess)
throw new InvalidOperationException("MemberAccess expression type needed");

// Récupération de la propriété et de son type
MemberExpression body = (MemberExpression)expression.Body;
MemberInfo member = body.Member;
var name = member.Name;
var type = typeof(TValue);

// Récupération de la valeur
object value = null;
try { value = expression.Compile()(model); }
catch (NullReferenceException) { }

return new PropertyDef(type, name, value);
}
}



Et maintenant, il ne reste plus qu'à encapsuler l'usage d'une méthode d'extension ASP.net MVC dans notre propre méthode d'extension :



public static string TextBoxFor<TModel, TValue>(this HtmlHelper html, TModel model, Expression<Func<TModel, TValue>> expression)
{
var def = LambdaExpressionParser.GetPropertyDef(expression, model);
return System.Web.Mvc.Html.InputExtensions.TextBox(html, def.Name, def.Value);
}



A noter que l'implémentation de MVC 2 sera bien plus pratique puisque les ViewPage vont exposer un HtmlHelper générique qui permet de raccourcir encore la syntaxe (voir l'article de Scott Guthrie).
Et voilà ! vivement ASP.net MVC 2.

dimanche 6 septembre 2009

La formule de la fréquence exacte des notes de musique

Je l’ai cherchée tellement souvent sur le net sans jamais la trouver !

Après toutes ces recherches infructueuse, j’ai décidé de faire confiance à mon intuition : ça doit pas être si compliqué …

Les hypothèses de départ :

Wikipedia donne une formule mais qui se base sur une fréquence de départ, comment fait-on si on veux pas avoir à utiliser une constante de départ, y’a-t-il une formule magique ?

Concentrons nous sur les valeurs exactes connues : 55, 110, 220, 440 … ça doit bien avoir un rapport avec les puissances de 2. Justement en informatique on les connait par cœur : 64, 128, 256, 512 …

Ca colle pas, mais quelques petites observations néanmoins :

  • 55 = 64 – 9
  • 110 = 128 – 18
  • 220 = 256 – 36
  • 440 = 512 – 72
  • f(n) = 2^n - (9*(2^(n-6))) ???

Ca prend forme mais que faire alors des notes intermédiaire entre les La. Il reste juste à appliquer cette formule sur des douzième d’octave et à faire quelques ajustements pour que qu’une fonction puisse prendre le numéro d’octave tel que défini dans la musique contemporaine (l’octave 0 commence à Do 32,70).


static class NoteFrequencyHelper
{
static public double GetNoteFrequency(double octave, double pitch)
{
// Dans cette formule 0=La, donc -9 sur le pitch pour rétabli 0=Do
double absolute_picth = octave + (pitch - 9) / 12d;

return Math.Pow(2, absolute_picth + 6) - 9d * Math.Pow(2, absolute_picth);
}
}


et le test qui vas avec :




[Test]
public void GetNoteFrequencies()
{
string[] note_names = { "Do ", "Do#", "Re ", "Re#", "Mi ", "Fa ", "Fa#", "Sol ", "Sol#", "La ", "La#", "Si " };

var frequencies =
from octave in Enumerable.Range(-1, 9)
from pitch in Enumerable.Range(0, 12)
select new
{
O = octave,
P = pitch,
Name = note_names[pitch],
Freq = NoteFrequencyHelper.GetNoteFrequency((double)octave, (double)pitch)
};

foreach (var f in frequencies)
Console.WriteLine(String.Format("{0}\t{1}:\t{2} Hz", f.Name, f.O, f.Freq));
}





Cela donne :









Do -1: 16,3515978312874 Hz

Do# -1: 17,3239144360545 Hz

Re -1: 18,354047994838 Hz

Re# -1: 19,4454364826301 Hz

Mi -1: 20,6017223070544 Hz

Fa -1: 21,8267644645627 Hz

Fa# -1: 23,1246514194772 Hz

Sol -1: 24,4997147488593 Hz

Sol# -1: 25,9565435987466 Hz

La -1: 27,5 Hz

La# -1: 29,1352350948806 Hz

Si -1: 30,8677063285078 Hz

Do 0: 32,7031956625748 Hz

Do# 0: 34,647828872109 Hz

Re 0: 36,708095989676 Hz

Re# 0: 38,8908729652601 Hz

Mi 0: 41,2034446141087 Hz

Fa 0: 43,6535289291255 Hz

Fa# 0: 46,2493028389543 Hz

Sol 0: 48,9994294977187 Hz

Sol# 0: 51,9130871974932 Hz

La 0: 55 Hz

La# 0: 58,2704701897612 Hz

Si 0: 61,7354126570155 Hz

Do 1: 65,4063913251497 Hz

Do# 1: 69,295657744218 Hz

Re 1: 73,4161919793519 Hz

Re# 1: 77,7817459305202 Hz

Mi 1: 82,4068892282175 Hz

Fa 1: 87,307057858251 Hz

Fa# 1: 92,4986056779086 Hz

Sol 1: 97,9988589954373 Hz

Sol# 1: 103,826174394986 Hz

La 1: 110 Hz

La# 1: 116,540940379522 Hz

Si 1: 123,470825314031 Hz

Do 2: 130,812782650299 Hz

Do# 2: 138,591315488436 Hz

Re 2: 146,832383958704 Hz

Re# 2: 155,56349186104 Hz

Mi 2: 164,813778456435 Hz

Fa 2: 174,614115716502 Hz

Fa# 2: 184,997211355817 Hz

Sol 2: 195,997717990875 Hz

Sol# 2: 207,652348789973 Hz

La 2: 220 Hz

La# 2: 233,081880759045 Hz

Si 2: 246,941650628062 Hz

Do 3: 261,625565300599 Hz

Do# 3: 277,182630976872 Hz

Re 3: 293,664767917407 Hz

Re# 3: 311,126983722081 Hz

Mi 3: 329,62755691287 Hz

Fa 3: 349,228231433004 Hz

Fa# 3: 369,994422711634 Hz

Sol 3: 391,995435981749 Hz

Sol# 3: 415,304697579945 Hz

La 3: 440 Hz

La# 3: 466,16376151809 Hz

Si 3: 493,883301256124 Hz

Do 4: 523,251130601197 Hz

Do# 4: 554,365261953744 Hz

Re 4: 587,329535834815 Hz

Re# 4: 622,253967444162 Hz

Mi 4: 659,25511382574 Hz

Fa 4: 698,456462866008 Hz

Fa# 4: 739,988845423269 Hz

Sol 4: 783,990871963499 Hz

Sol# 4: 830,60939515989 Hz

La 4: 880 Hz

La# 4: 932,327523036179 Hz

Si 4: 987,766602512249 Hz

Do 5: 1046,50226120239 Hz

Do# 5: 1108,73052390749 Hz

Re 5: 1174,65907166963 Hz

Re# 5: 1244,50793488832 Hz

Mi 5: 1318,51022765148 Hz

Fa 5: 1396,91292573202 Hz

Fa# 5: 1479,97769084654 Hz

Sol 5: 1567,981743927 Hz

Sol# 5: 1661,21879031978 Hz

La 5: 1760 Hz

La# 5: 1864,65504607236 Hz

Si 5: 1975,5332050245 Hz

Do 6: 2093,00452240479 Hz

Do# 6: 2217,46104781497 Hz

Re 6: 2349,31814333926 Hz

Re# 6: 2489,01586977665 Hz

Mi 6: 2637,02045530296 Hz

Fa 6: 2793,82585146403 Hz

Fa# 6: 2959,95538169308 Hz

Sol 6: 3135,96348785399 Hz

Sol# 6: 3322,43758063956 Hz

La 6: 3520 Hz

La# 6: 3729,31009214472 Hz

Si 6: 3951,066410049 Hz

Do 7: 4186,00904480958 Hz

Do# 7: 4434,92209562995 Hz

Re 7: 4698,63628667853 Hz

Re# 7: 4978,03173955329 Hz

Mi 7: 5274,04091060591 Hz

Fa 7: 5587,65170292807 Hz

Fa# 7: 5919,91076338615 Hz

Sol 7: 6271,92697570798 Hz

Sol# 7: 6644,87516127913 Hz

La 7: 7040 Hz

La# 7: 7458,62018428943 Hz

Si 7: 7902,13282009799 Hz



Arffff, c’est tellement bien le dimanche.

mercredi 6 mai 2009

Determinism & SchemaBinding

J’ai décidément mis longtemps à trouver pourquoi une fonction toute simple que j’utilisait pour remplir un colonne calculée sous SQL Server (histoire de poser un index dessus), n’était pas déterministe !

Et bien la preuve avec le Script ci dessous, le déterminisme d’une fonction n’est possible que si elle est “schemabound” :




use TEST

GO
create function IsNotDeterministic()
returns bit
AS
Begin
return 0
End

GO

select 'Une fonction non shemabound ne peut être déterminisme :',
OBJECTPROPERTY ( OBJECT_ID(N'IsNotDeterministic') , N'IsSchemaBound') as 'ShemaBound',
OBJECTPROPERTY ( OBJECT_ID(N'IsNotDeterministic') , N'IsDeterministic') as 'Deterministic'

GO

drop function IsNotDeterministic

GO

GO
create function IsDeterministic()
returns bit
with schemabinding
AS
Begin
return 1
End

GO

select 'Une fonction schemabound a plus de chance :',
OBJECTPROPERTY ( OBJECT_ID(N'IsDeterministic') , N'IsSchemaBound') as 'ShemaBound',
OBJECTPROPERTY ( OBJECT_ID(N'IsDeterministic') , N'IsDeterministic') as 'Deterministic'

GO

drop function IsDeterministic

GO


L’option shemabinding permet à SQL Server d’être ‘rassurer’ quand à la disponibilité des objets liés, ils ne sont pas modifiables, ni supprimables, ils sont là …. ouff.

Résultat du script :

ShemaBound Deterministic
------------------------------------------------------- ----------- -------------
Une fonction non shemabound ne peut être déterminisme : 0 0

(1 ligne(s) affectée(s))

ShemaBound Deterministic
------------------------------------------- ----------- -------------
Une fonction schemabound a plus de chance : 1 1

(1 ligne(s) affectée(s))