LOI HADOPI (Tract du 5 septembre 2009)

Suite à une proposition du site http://www.odebi.org, qui nous invite tous à sortir dans la rue le 5 septembre, voici le tract que j’ai choisi :


Où en sommes-nous ?
TOUJOURS dans la répression, RIEN pour la création

Cette loi vise un but noble : endiguer le téléchargement illégal d'œuvres (musiques, films...) via Internet.
POURTANT :
• Cette loi instaurera une logique de "tout répressif" comme seule réponse aux enjeux de l'ère numérique avec une coupure de l’accès à Internet allant jusqu'à un an, une peine de deux ans de prison et 1500 euros d’amende pour le propriétaire de la ligne accusée de téléchargement illégal. Comme pour les radars automatiques le traitement sera automatisé, confié à des entreprises privées, ce sera à l'accusé de prouver son innocence. Qui dit traitement automatisé, dit aussi risque d'erreurs... D'autant plus qu'il est très facile de se faire passer pour quelqu'un d'autre sur Internet ou de pirater le WiFi du voisin, comme l'a démontré l'association UFC que choisir récemment !
• Cette loi prévoit l'installation d'un "logiciel de sécurisation" payant sur votre ordinateur. Mais il ne s'agira ni plus ni moins que d'un logiciel espion : il pourra contrôler vos communications et vos données sans même que vous le sachiez.
• Cette loi a été censurée par le Conseil Constitutionnel dans sa première version... Et pourtant elle revient devant l'Assemblée presque à l'identique... C’est de l’acharnement !
• Cette loi ne profitera pas aux artistes, mais seulement aux maisons de disques qui récupèrent 75 % du prix HT d'un album. Mais pourquoi vouloir aider à ce point des entreprises qui font déjà des bénéfices monstrueux en finançant les mesures prises avec l’argent  public ?
• Cette loi sera extrêmement difficile à appliquer techniquement et coûtera entre 100 et 200 millions d'euros dans le contexte actuel de crise économique. Le tout sans garantie de résultats puisque les pirates ont déjà développé de nombreuses parades pour la contourner.

LA PEUR DU GENDARME
LE PROFIT DES MAJORS
LE CONTRÔLE DE VOS ORDINATEURS ET COMMUNICATIONS
STOP !
Il existe des alternatives saines qui concilient Internet et rémunération des artistes.

Pour vous informer et savoir comment agir rendez-vous sur :
- La Ligue ODEBI : http://www.odebi.org/hadopi
- Numerama : http://www.numerama.com/
- La Quadrature du Net : http://www.laquadrature.net/

ValidationSummary designable avec asp.net mvc

La methode d’extension Html.ValidationSummary() est certe pratique mais très vite limitée en terme de webdesign pour un rendu professionnel d’un message d’erreur de validation, pour etre plus precis, voici une solution que j’utilise :

Il faut creer un controle validationsummary.ascx (par exemple) à placer dans le repertoire courrant ou dans /shared

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<% if (!ViewData.ModelState.IsValid) { %>
<div class="validation">
<strong><img src="/content/images/icon_error.png" alt=""/>Attention !</strong>
<% foreach (var item in ViewData.ModelState.GetAllErrors()) { %>
<p class="error">
<span><%=item%></span>
</p>
<% } %>
</div>
<% } %>



Ajouter la methode d’extension GetAllErrors dans une classe helper :




/// <summary>
/// Retourne la liste de toutes les erreurs de validation d'un formulaire
/// </summary>
/// <param name="modelState">State of the model.</param>
/// <returns></returns>
public static IEnumerable<string> GetAllErrors(this ModelStateDictionary modelState)
{
var errors = from state in modelState
from error in state.Value.Errors
where state.Value.Errors.Count > 0
select error.ErrorMessage;

return errors;
}





puis dans la page ou se trouve le formulaire il suffit d’appeler un rendu partiel




<%Html.RenderPartial("ValidationSummary"); %>

Favicon.ico, asp.net mvc et 404

Sur un de mes sites j’ai constaté dans les logs IIS qu’un 404 se produisait car les navigateurs veulent obtenir le fichier favicon.ico, voici une solution pour eviter de renvoyer un 404 :

dans global.asax, ajouter une route :

routes.MapRoute(
"FavIcon"
, @"favicon.ico"
, new { controller = "Home", action = "FavIcon" }
);



dans le controller “HomeController” ajouter l’action FavIcon :




public ActionResult FavIcon()
{
var pixel = new byte[35] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61
, 0x01, 0x00, 0x01, 0x00, 0x80, 0x00, 0x00
, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF
, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00
, 0x02, 0x01, 0x44, 0x01, 0x00
, 0x3B };

return this.File(pixel, "image/gif");
}



le serveur retournera bien une reponse 200 au navigateur avec une image d’un pixel.



A savoir, si le fichier existe, pour eviter de passer par le controller par defaut, il faut ajouter la ligne suivante dans global.asax :




routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });



Une variation pour l’action FavIcon() suite à la juste remarque de Dascritch :




[OutputCache(VaryByParam="none", Duration=3600)]
public ActionResult FavIcon()
{
byte[] result = null;
using (var bitmap = new System.Drawing.Bitmap(16, 16, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
{
var backColor = bitmap.GetPixel(0, 0);
bitmap.MakeTransparent(backColor);
using (var ms = new System.IO.MemoryStream())
{
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
result = ms.GetBuffer();
ms.Close();
}
}
return this.File(result, "image/x-icon");
}




Retourne une image au format 16x16 transparent au format PNG, IE ne la prends pas en compte, Firefox est ok et Chrome affiche un carré noir :(

Detection de rupture de sequence sql

 

Voici une solution, suite à une colle que l’on vient de me poser a propos de la problèmatique suivante avec sql serveur :

Une table contient une colonne de type Int les valeurs de cette colonne doivent etre uniques, lors de l’ajout d’un nouvel enregistrement il faut aller chercher la première rupture de sequence et non pas ajouter la valeur maximale de la colonne + 1, par exemple :

create table Sequence
(
Id int not null
)

insert into Sequence (Id) Values (1)
insert into Sequence (Id) Values (2)
insert into Sequence (Id) Values (8)
insert into Sequence (Id) Values (3)



nous avons le resultat suivant :



1

2


8


3



la nouvelle valeur doit etre 4, voici comment avec une seule requete :




select MIN(A.Precedent) + 1
from (
select ID
, (select max(subsquence.ID) from Sequence as subsquence where subsquence.ID < Sequence.Id) as Precedent
from Sequence
where ID - (select max(subsquence.ID) from Sequence as subsquence where subsquence.ID < Sequence.Id) > 1) as A





Explication :



une premiere requete selectionne les identifiants et l’identifiant de la ligne dont l’identifiant est inférieur à celui en cours :




select ID
, (select max(subsquence.ID) from Sequence as subsquence where subsquence.ID < Sequence.Id) as Precedent
from Sequence



ensuite il suffit d’ajouter une contrainte qui determine que la difference entre ces 2 indentifiants est supérieure à 1 (cas d’une rupture de sequence ).




where ID - (select max(subsquence.ID) from Sequence as subsquence where subsquence.ID < Sequence.Id) > 1





puis de prendre l’identifiant minimum de la liste et ajouter 1 :




select MIN(A.Precedent) + 1
from (...) as A



Le résultat donne bien 4

Binding et “refactorisation”

Un problème qui vient de m’arriver et qui est assez difficile à anticiper via des tests unitaires est le fait que d’utiliser le binding des controles dans une winform.

Par exemple si j’ai une textbox sur laquelle je veux binder le code d’un produit je vais ecrire :

myTextBox.DataBindings.Add("Text", bindingSource, "ProductCode");



Si maintenant je “refactore” ma classe product et change la propriété [ProductCode] par [Code] pour etre plus simple, tout mon projet sera changé, ça va compiler, sauf la ligne précédente il restera toujours “ProductCode”, etant donné que ce code est directement lié à l’interface graphique il est très difficile de reperer le bug via des tests unitaires avant d’ouvrir le formulaire manuellement, c’est du vecu, c’est plutot vos clients qui vous en parlent en premier :(



pour eviter ce problème, voici une solution :




public static class BindingExtensions
{
public static Binding Add<TSource>(this ControlBindingsCollection controlBindingCollection, string propertyName, object bindingSource, Expression<Func<TSource, object>> expression)
{
return controlBindingCollection.Add(propertyName, bindingSource, expression, false, controlBindingCollection.DefaultDataSourceUpdateMode, null, string.Empty, null);
}

public static Binding Add<TSource>(this ControlBindingsCollection controlBindingCollection, string propertyName, object bindingSource, Expression<Func<TSource, object>> expression, bool formattingEnabled)
{
return controlBindingCollection.Add(propertyName, bindingSource, expression, formattingEnabled, controlBindingCollection.DefaultDataSourceUpdateMode, null, string.Empty, null);
}

public static Binding Add<TSource>(this ControlBindingsCollection controlBindingCollection, string propertyName, object bindingSource, Expression<Func<TSource, object>> expression, bool formattingEnabled, DataSourceUpdateMode updateMode)
{
return controlBindingCollection.Add(propertyName, bindingSource, expression, formattingEnabled, updateMode, null, string.Empty, null);
}

public static Binding Add<TSource>(this ControlBindingsCollection controlBindingCollection, string propertyName, object bindingSource, Expression<Func<TSource, object>> expression, bool formattingEnabled, DataSourceUpdateMode updateMode, object nullValue)
{
return controlBindingCollection.Add(propertyName, bindingSource, expression, formattingEnabled, updateMode, nullValue, string.Empty, null);
}

public static Binding Add<TSource>(this ControlBindingsCollection controlBindingCollection, string propertyName, object bindingSource, Expression<Func<TSource, object>> expression, bool formattingEnabled, DataSourceUpdateMode updateMode, object nullValue, string formatString)
{
return controlBindingCollection.Add(propertyName, bindingSource, expression, formattingEnabled, updateMode, nullValue, formatString, null);
}

public static Binding Add<TSource>(this ControlBindingsCollection controlBindingCollection, string propertyName, object bindingSource, Expression<Func<TSource, object>> expression, bool formattingEnabled, DataSourceUpdateMode updateMode, object nullValue, string formatString, IFormatProvider formatInfo)
{
if (bindingSource == null)
{
throw new ArgumentNullException("dataSource");
}
var dataMemberName = ((expression.Body as UnaryExpression).Operand as MemberExpression).Member.Name;
return controlBindingCollection.Add(propertyName, bindingSource, dataMemberName, formattingEnabled, updateMode, nullValue, formatString, formatInfo);
}
}





J’ai ajouté dans mon projet une classe avec un certain nombre de methodes qui etendent l’objet ControlBindingCollection, la difference est que je ne passe plus le nom de la propriété mais utilise une lambda expression de la manière suivante :




myTextbox.DataBindings.Add<Product>("Text", bindingSource, p => p.ProductCode);



En cas de “refacto”, le nouveau nom de propriété sera changé.



Petit bémol avec cette méthode, il n’est plus question d’utiliser le designer intégré avec visual studio 2008, mais il faut choisir entre la maintenabilité et le confort pour le developpeur. Personnelement je n’utilise plus le designer pour tout ce qui concerne le binding.

Methode d’extension asp.net mvc pour ajouter un paramètre dans l’url

 

Voici une petite methode d’extension bien pratique pour pouvoir ajouter un parametre dans l’url courante

/// <summary>
/// Ajoute un parametre et sa valeur dans une URL en tenant compte de sa presence eventuelle
/// </summary>
/// <example>
/// Exemple d'utilisation
/// <code>
/// <![CDATA[
///
/// une url existante est de la forme
/// http://domain.com/test?param1=valeur1
///
/// <a href='<%=Url.AddParameter("param2", "valeur2")%>'>Mon lien</a>
///
/// Donnera le resultat suivant :
///
/// http://domain.com/test?param1=valeur1&param2=valeur2
///
/// <a href='<%=Url.AddParameter("param1", "valeur2")%>'>Mon lien</a>
///
/// Donnera le resultat suivant :
///
/// http://domain.com/test?param1=valeur2
///
/// ]]>
/// </code>
/// </example>
/// <remarks>
/// "value" est urlencodé par la methode, ne pas passer la valeur deja encodée
/// </remarks>
/// <param name="helper">The helper.</param>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
/// <returns>Le lien avec le couple key=value</returns>
public static string AddParameter(this UrlHelper helper, string key, string value)
{
var link = helper.RequestContext.HttpContext.Request.Url.PathAndQuery;
var pattern = string.Format("&*{0}=[^&]*", key);
link = System.Text.RegularExpressions.Regex.Replace(link, pattern, "");
link = link.Trim('?').Trim('&');
var separator = (link.IndexOf("?") == -1) ? "?" : "&";
link += string.Format("{0}{1}={2}", separator, key, helper.Encode(value));
return link;
}

Une incitation au téléchargement ?

L'Attaque du métro 123

J’ai profité de mes vacances pour aller voir le film (l’attaque du metro 123) avec mon épouse, je ne conseille vraiment pas ce film, aucun scenario, violence gratuite (des tonnes de ketchup qui n’apportent rien au film).

En fait ce qui m’a le plus saoulé, c’est la publicité avant de pouvoir voir le film, j’ai chronometré, 27 minutes ! pas une seule bande annonce pour les autres films, non, juste de la publicité bien grace, en passant par des glaces, la pub locale, et autres produits de consomation.

Le prix de la place était de 8 euros 50 soit 17 euros à 2 personnes. Je me demande bien pourquoi les producteurs de films sont encore étonnés que l’on puisse télécharger sur internet, franchement c’est une veritable incitation, c’est carrement désagréable de devoir subir cette publicité, c’est pire que la TV, à la limite je serais d’accord pour sa diffusion, mais dans ce cas le film devrait etre gratuit ou vraiment moins cher.