samedi 31 octobre 2009

ASP.NET MVC : Pas de cache dans le Controller Factory

J’ai récemment expliqué comment changer de Controller Factory dans MVC, mais depuis ce jour il y a un truc qui me tracasse : l’exemple que j’ai donné n’était pas du tout optimisé. En effet, on instancie un nouveau contrôleur à chaque requête, alors qu’on pourrait très bien en instancier un seul et le mettre en cache. Vu que ça prenait que quelques lignes de code, j’ai décidé d’étendre le DefaultControllerFactory pour y ajouter un cache des contrôleurs. Et là, déception, j’ai une exception lorsque lance mon application :

A single instance of controller 'MyMvcApplication.Controllers.HomeController' cannot be used to handle multiple requests. If a custom controller factory is in use, make sure that it creates a new instance of the controller for each request.

A la première requête, la charge se charge correctement, mais lors du chargement de la seconde page (et donc quand le cache est utilisé), le controller refuse de faire son boulot.

Je suis allé faire un petit tour dans le code source pour voir comment était créé le contrôleur, et effectivement à chaque requête une nouvelle instance est créée, comme dans mon ControllerFactory perso. D’après Scott Hanselman, mettre en cache une instance d’un contrôleur pourrait avoir des effets de bord non désirés (source). Ne vous embêtez donc pas à vouloir optimiser plus que ça, le fonctionnement de base fonctionne très bien… ou alors il vous faudra recoder complètement le contrôleur de base de MVC pour le rendre capable de gérer le cache (bon courage).

mardi 27 octobre 2009

Article : les nouveautés d’ASP.NET 4

Pour une fois, on va oublier un peu MVC pour en revenir aux bonnes vieilles WebForm. Au programme de ce nouvel article : les nouveautés d’ASP.NET 4 !

Au programme, de nombreuses optimisations, et quelques nouveautés intéressantes, notamment avec ASP.NET Ajax et le JavaScript.

Découvrez-le sur le site de Bewise :

http://www.bewise.fr/article/138/Les-nouveautes-d-ASP-NET4.aspx

jeudi 22 octobre 2009

Article : Utiliser Ajax avec ASP.NET MVC

Après mon précédent article, qui présentait les bases de ASP.NET MVC, je me suis dit qu’il pourrait être sympa de faire un peu d’Ajax.

Dans cet article, pas de JavaScript ni de WebServices (bien qu’il soit tout à fait possible, et certainement très intéressant, d’en faire avec MVC), je me concentre uniquement sur les moyens de faire de l’Ajax spécifiques à MVC, en utilisant l’AjaxHelper du framework.

Vous allez voir qu’encore une fois, c’est très simple à mettre en place, et la séparation des couches est toujours de la partie puisqu’on utilise toujours les contrôleurs et les vues, de la même manière qu’avec des requêtes http classiques.

Je vous laisse découvrir l’article sur Tech Head Brothers :

http://www.techheadbrothers.com/Articles.aspx/ajaxhelper-aspnet-mvc

lundi 19 octobre 2009

Tip : des ActionLink plus propres avec ASP.NET MVC

Malgré tout le bien que je pense d’ASP.NET MVC (qui est, je le rappelle, le meilleur framework de développement web du monde, que dis-je, de l’univers !), je me vois parfois obligé de reconnaître qu’il a des défauts. L’un des plus ennuyeux est l’utilisation de chaînes de caractères et d’objets anonymes dans les helpers Html, source potentielle d’erreurs, qui ne seront pas détectées à la compilation.

Pour remédier à ce soucis, nous avons la possibilité d’étendre le Html Helper, afin d’ajouter nos propres méthodes de création de liens.

Pour commencer, nous allons créer une classe par contrôleur, dans laquelle nous définirons les méthodes qui renverront les liens vers chaque action. Cette classe va se baser sur le HtmlHelper pour créer les liens, donc n’oublions pas de le passer dans le constructeur :

    public class HomeLinks
    {
       
private HtmlHelper html;
       
public HomeLinks(HtmlHelper html)
        {
           
this.html = html;
        }

       
public String Index(String linkText)
        {
           
return html.ActionLink(linkText, "Index", "Home");
        }

       
public String Details(String linkText, int id)
        {
           
return html.ActionLink(linkText, "Details", "Home", new { id = id });
        }
    }

Une fois cette classe créée, on va ajouter une méthode au HtmlHelper pour pouvoir y accéder depuis notre vue :

    public static class LinkHelper
    {
       
public static HomeLinks HomeLinks(this HtmlHelper Html)
        {
           
return new HomeLinks(Html);
        }

       
public static AccountLinks AccountLinks(this HtmlHelper Html)
        {
           
return new AccountLinks(Html);
        }
    }

Notez que j’ai séparé les liens de chaque contrôleur dans des classes distinctes par soucis de clarté, mais ce n’est absolument pas obligatoire : vous pouvez si vous le souhaitez étendre directement le HtmlHelper par vos liens :

    public static String Index(this HtmlHelper Html, String linkText)
    {
       
return Html.ActionLink(linkText, "Index", "Home");
    }

Pour pouvoir appeler vos méthodes depuis vos pages aspx, n’oubliez pas d’ajouter leur namespace dans le web.config :

    <pages>
      <
namespaces>
        <
add namespace="MyMvcApp.LinkHelpers"/>
      </
namespaces>
    </
pages>

Et voilà, plus besoin de faire passer de chaines de caractères en dur dans vos liens, vous pouvez utiliser ces méthodes avec des vrais noms et des paramètres typés !

Ainsi, les 2 lignes suivantes créeront le même lien :

<%= Html.ActionLink("Details pour l'id numero 5", "Details", "Home", new { id = 5 }  %>
<%
= Html.HomeLinks().Details("Details pour l'id numero 5", 5) %>

vendredi 16 octobre 2009

ASP.NET MVC : changer de ControllerFactory

Le framework ASP.NET MVC utilise ce qu’on appelle “convention over configuration”, ce qui signifie qu’on n’a pas besoin de configurer manuellement notre application pour avoir une application qui fonctionne, tant que l’on respecte certaines conventions. Si l’on ne souhaite pas utiliser ces conventions, on a toujours la possibilité de configurer l’application pour travailler autrement.

En pratique, qu’est-ce que ça signifie ?

Lorsque l’on crée un nouveau projet MVC, les contrôleurs sont disposés dans le dossier « Controllers » de l’application, et leur nom doit forcément se terminer par « Controller ». Si on crée un contrôleur dans un autre namespace, ou si son nom est incorrect, le contrôleur ne sera pas reconnu par MVC. Pour pouvoir changer cette convention, on a la possibilité de créer notre propre ControllerFactory, dans lequel on pourra définir nos règles d’appel de nos contrôleurs.

Pour créer un ControllerFactory, il va falloir créer une nouvelle classe qui implémentera l’interface IControllerFactory, contenant 2 méthodes :

IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
et
void ReleaseController(IController controller)

La première va nous permettre de renvoyer une instance d’un contrôleur en fonction de son nom, et éventuellement de paramètres venant de la requête ; la seconde va nous permettre de libérer un contrôleur qui n’est plus utilisé. Le résultat ressemblera à quelque chose comme ça :

    public class CustomControllerFactory : IControllerFactory
    {

       
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
           
if (string.IsNullOrEmpty(controllerName))
               
throw new ArgumentNullException("Controller name can't be empty");

           
String controllerType = String.Concat("MyMvcApplication.CustomController.", controllerName);

           
IController controller = Activator.CreateInstance(Type.GetType(controllerType)) as IController;

           
return controller;
        }

       
public void ReleaseController(IController controller)
        {
           
IDisposable disposableController = controller as IDisposable;
           
if (disposableController != null)
                disposableController.Dispose();
        }

    }

Une fois notre classe créée, il faut l’enregistrer pour qu’elle soit utilisée à la place de la Factory par défaut. Pour ça, on a une méthode SetControllerFactory qu’il nous faut appeler au démarrage de l’application, dans le global.asax :

    protected void Application_Start()
    {
        RegisterRoutes(
RouteTable.Routes);

       
ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));
    }

Une fois ceci fait, nos anciens contrôleurs ne sont plus appelés, la recherche se fera dans le namespace MyMvcApplication.CustomController comme cela a été défini dans notre CustomControllerFactory.

Crossposté vers Tech Head Brothers

samedi 3 octobre 2009

Convertir le temps Unix en DateTime .NET

Si vous faites du .NET, il y a peu de chances que vous ayez besoin d’utiliser le temps Unix. Cependant, si jamais vous en avez besoin, il n’y a pas à ma connaissance de méthode effectuant la conversion dans le framework .NET, il va donc falloir effectuer la conversion à la main. Heureusement, ce n’est pas compliqué.

Le temps Unix est défini par un nombre entier, représentant le nombre de secondes écoulées depuis le début de l’univers, le 1er janvier 1970. Lorsqu’on sait ça, la conversion est toute simple :

    private static DateTime origin = new DateTime(1970, 1, 1);

   
public static DateTime UnixTimeToDateTime(long timespan)
    {
       
return origin.AddSeconds(timespan);
    }

   
public static long DateTimeToUnixTime(DateTime date)
    {
       
TimeSpan ts = date - origin;
       
return (long)ts.TotalSeconds;
    }

Pour la petite histoire, lorsque le temps Unix est codé sur un entier 32 bits, on ne peux coder les dates que jusqu’au 19 janvier 2038, si ce système est encore utilisé ce jour là, on risque d’avoir le fameux bug de l’an 2038, un bug encore pire que le bug de l’an 2000. Heureusement, les systèmes 64 bits devraient se généraliser dans les années à venir pour nous éviter ces problèmes.