blog.pagesd.info

Aller au contenu | Aller au menu | Aller à la recherche

vendredi 23 décembre 2011

Configurer ELMAH pour utiliser SQL Server

Pour avancer un peu plus dans mon utilisation d'ELMAH, j'ai cherché à enregistrer les informations qu'il collecte dans une base de données.

Pour cela, j'ai réalisé quelques essais pour voir comment faire et pour comprendre comment cela fonctionnait :

  • Configuration automatique de SQL Server Compact
  • Configuration semi-automatique SQL Server
  • Configuration manuelle de SQL Server Compact

La suite de ce billet récapitule le fonctionnement propre à chacune de ces méthodes.

ELMAH + Sql Server Compact en automatique

Sous NuGet, je recherche "elmah" puis choisis le package "ELMAH on MS SQL Server Compact". Sa description indique qu'il s'agit d'une configuration pour démarrer rapidement avec une base de données Microsoft SQL Server Compact.

Ca semble être un meilleur choix que "ELMAH on MS SQL Server (requires manual config)" puisque à priori, l'absence de "requires manual config" devant logiquement signifier que je n'aurai rien à faire.

Je clique sur le bouton [Install] et l'installation débute, mais impose l'installation de Sql Server Compact 4.0.8+. Je tique un peu parce qu'il me semblait que j'étais à jour ? Mais bon, [I accept] et le projet référence maintenant 2 packages supplémentaires :

  • ELMAH on MS SQL Server Compact
  • SqlServerCompact

Il suffit alors de relancer l'application et de se rendre sur l'URL elmah.axd pour confirmer que tout a été configuré sans que effectivement j'ai eu quoi que ce soit à faire : "This log is provided by the SQL Server Compact Error Log". Génial !

Si je regarde dans le dossier "App_Data", je constate qu'il contient désormais une base de données "Elmah.sdf". Un double-clic pour l'ouvrir et je peux voir que celle-ci est constitué d'une seule table "ELMAH_Error", avec les colonnes nécessaire pour enregistrer tout le détail des erreurs :

  • ErrorId
  • Application
  • Host
  • Type
  • Source
  • Message
  • User
  • StatusCode
  • TimeUtc
  • Sequence
  • AllXml

Et si maintenant j'étudie ce qui a changé dans l'application, je m'aperçois qu'en fait c'est trois fois rien dans le web.config :

Un :

<connectionStrings>
  ...
  <add name="elmah-sqlservercompact"
       connectionString="Data Source=|DataDirectory|\Elmah.sdf" />
</connectionStrings>

Deux :

<system.data>
  <DbProviderFactories>
    <remove invariant="System.Data.SqlServerCe.4.0" />
    <add name="Microsoft SQL Server Compact Data Provider 4.0"
         invariant="System.Data.SqlServerCe.4.0"
         description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" />
  </DbProviderFactories>
</system.data>

Et trois :

<elmah>
  <errorLog type="Elmah.SqlServerCompactErrorLog, Elmah"
            connectionStringName="elmah-sqlservercompact" />
</elmah>

Rollback

Je désinstalle le package "ELMAH on MS SQL Server Compact" (mais pas les packages dont il dépend) puis le package "SqlServerCompact".

Puis je retourne sur elmah.axd où je peux constater que je suis bien revenu à mon point de départ : "This log is provided by the In-Memory Error Log.". Parfait !

ELMAH + Sql Server en semi-automatique

Ce coup-ci je fais un essai avec l'installation du package NuGet "ELMAH on MS SQL Server (requires manual config)".

Une fois terminé, un nouveau dossier "App_Readme" est apparu dans le projet, avec deux fichiers : - Elmah.SqlServer.sql - Elmah.SqlServer.txt

Et le fichier Elmah.SqlServer.txt contient le texte suivant :

Please note that in order to complete the installation of ELMAH.SqlServer you will have to do the following:

1) Run the Elmah.SqlServer.sql script against your database
2) Edit your web.config with the correct settings in the elmah <connectionString> to connect to your database

Malgré tout, le fichier web.config a déjà été pas mal préparé pour simplifier la configuration :

Un :

<connectionStrings>
  ...
  <add name="elmah-sqlserver" 
       connectionString="Data Source=****;User ID=****;Password=****;Initial Catalog=****;"
       providerName="System.Data.SqlClient" />
</connectionStrings>

Et deux :

<elmah>
  <errorLog type="Elmah.SqlErrorLog, Elmah" 
            connectionStringName="elmah-sqlserver" />
</elmah>

Je sais jamais faire, mais sinon, c'est pas compliqué :

  • démarrer SQL Server Management Studio (l'occasion de voir que j'ai des tonnes de base Xxxxx.Models.XxxxxContext crées au cours de différents essais ou tutoriels)
  • créer une nouvelle base "Elmah" (et la passer en Compatibility_Level 80)
  • lancer le script (qui génère pas mal de message d'avertissement)

Ouf ! C'est fait.

Puis enregistrer la chaine de connexion :

<add name="elmah-sqlserver"
     connectionString="Data Source=.\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=Elmah;"
     providerName="System.Data.SqlClient" />

Je peux alors relancer l'application, provoquer une erreur et aller que la page elmah.axd et vérifier que "This log is provided by the Microsoft SQL Server Error Log.". Bravo !

ELMAH + Sql Server Compact en manuel

Après désinstallation du package "ELMAH on MS SQL Server (requires manual config)", je me retrouve à nouveau avec un ELMAH tout simple qui stocke ses erreurs en mémoire. Et au passage, le dossier App_Readme a disparu. Magnifique !

Je peux donc tenter une modification tout ce qu'il y a de plus manuelle du web.config pour utiliser une base de données Sql Server Compact (celui qui est déjà installé sur mon PC).

Un :

<connectionStrings>
  ...
  <add name="elmah-sqlservercompact"
       connectionString="Data Source=|DataDirectory|\Elmah.sdf" />
</connectionStrings>

Et deux :

<elmah>
  <errorLog type="Elmah.SqlServerCompactErrorLog, Elmah"
            connectionStringName="elmah-sqlservercompact" />
</elmah>

Je relance l'application, tente d'accéder à l'URL index.html qui n'existe pas puis direction elmah.axd et ça marche : "This log is provided by the SQL Server Compact Error Log". Magnifique !

Conclusions

Déjà, le système des packages NuGet est bien foutu (au moins en ce qui concerne ELMAH) :

  • ça installe ce qui est nécessaire et ça fait les modifications et configurations qui vont bien où ça va bien.
  • quand on désinstalle, ça sait remettre tout comme il faut, y compris les modifications apportées au web.config :)

Pour l'instant, je vais en rester à la configuration manuelle pour Sql Server Compact. C'est bien suffisant pour les essais que je fais.

Mais finalement, je pense avoir compris pourquoi le package "ELMAH on MS SQL Server Compact" en automatique installe SqlServerCompact. Au moins, lorsque on déploie sur le serveur de production, ça permet que ELMAH soit prêt à fonctionner sur une base de données SQL Server Compact, même si celui-ci n'est pas installé en production. Pas bête !

jeudi 6 octobre 2011

Générer des URLs en minuscules avec ASP.NET MVC

Un des trucs bien de ASP.NET MVC c'est que son système de routes sert aussi pour générer automatiquement les URLs correctes pour les actions des contrôleurs à partir de méthodes telles que Html.ActionLink(), Url.Action()… Un des trucs crispant de ASP.NET MVC, c'est qu'il génère ces URLs en conservant les noms des contrôleurs et des actions tels quels.

Ainsi, si on a une action "Update" dans un contrôleur "ContactsController", cela génèrera l'URL "/Contacts/Update" alors que cela aurait été tellement plus joli de générer une URL "/contacts/update" !

Ce qui laisse 2 solutions :

  • Attendre le jour où ASP.NET MVC gèrera ça de lui-même
  • Se dire que quelques majuscules par ci par là c'est pas si moche que ça
  • N'utiliser que des minuscules pour les noms de contrôleurs et d'actions
  • Améliorer le système de routes pour minusculiser automatiquement les noms des contrôleurs et des actions

Du temps de MVC 1, j'avais déjà fait ça pour certains projets, en reprenant le code proposé par Graham O'Neale dans son billet Lowercase Route URL's in ASP.NET MVC.

Mais je trouve que c'est typiquement le genre de petits trucs sur lequel il ne faut pas perdre de temps et qu'il ne faut pas chercher à gérer soi-même. Et dans ce cas là, l'utilisation d'un package NuGet tout prêt est la solution idéale.

Ce qui tombe bien, puisque Lee Dumond a justement créé un package LowercaseRouteMVC exprès pour ça. Son utilisation est très simple puisqu'il suffit de référencer sa DLL puis de légèrement modifier la façon de déclarer les routes dans le Globas.asax.

Installer

  • Faire un clic droit sur la branche "Référence" du projet et sélectionner le sous-menu "Manage NuGet Packages…".
  • Rechercher "lowercase"
  • Demander à installer le package "LowercaseRouteMVC"
  • Lire et accepter la licence

Modifier

  • Ouvrir le fichier "Global.asax"
  • Ajouter un using LowercaseRouteMVC; au bon endroit
  • Modifier la procédure "RegisterRoutes" pour remplacer route.MapRoute par route.MapRouteLowercase
using LowercaseRoutesMVC;
  ...
public static void RegisterRoutes(RouteCollection routes)
{
  routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
  
  routes.MapRouteLowercase(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
  );

Terminé

  • Lancer l'exécution par F5
  • Les URLs générées par l'application ne contiennent plus que des noms de contrôleurs et d'actions en minuscules :)

mercredi 28 septembre 2011

Installer ELMAH avec NuGet

Jusqu'à présent, j'ai un peu tendance à utiliser NuGet uniquement pour mettre à jour Entity Framework, jQuery et consorts et dans mes très grands jours pour voir ce que donne un package de ci de là.

Après avoir terminé le chapitre de Professional ASP.NET MVC 3 consacré à NuGet, je me lance et j'en profite pour installer ELMAH. C'est l'exemple donné dans le livre et c'est un outil que j'avais déjà essayé d'utiliser du temps de mes WebForms puis de MVC 1.0 mais que j'avais chaque fois laissé tombé par manque de temps.

Je vais éviter la console pour l'instant et faire l'installation par un clic-droit sur la branche "Références" de mon projet puis en sélectionnant l'option "Manage NuGet Packages...".

elmah01.png

Note : cette option est également disponible quand on fait un clic droit sur la solution ou le nom du projet, mais dans ce cas elle plus difficile à repérer étant donné le plus grand nombre d'options proposées.

Il apparait alors la fenêtre "Manage NuGet Packages" qui liste par défaut tous les packages du monde en commençant par les plus téléchargés. Une fois là, le plus simple est d'utiliser la zone de recherche en haut à droite et d'y taper "elmah" pour n'afficher que les packages appropriés. Malgré tout, il reste encore une quinzaine de packages dans la liste !

elmah02.png

En cliquant sur un package, la colonne de droite est mise à jour et affiche tout un tas d'informations sur le package, avec entre autre sa version, sa description et ses dépendances. Comme rien n'est précisé dans le livre, j'installe le premier résultat obtenu (et donc le plus téléchargé), à savoir "ELMAH" (tout court) en cliquant sur le bouton "Install" qui apparait opportunément lorsque la souris le survole. Et c'est parti !

elmah03.png

Note : si j'avais accédé à la fenêtre "Manage NuGet Packages" par un clic-droit sur la solution, j'aurai eu droit à un préliminaire me demandant d'indiquer pour quels projet je souhaitais installer le package :

elmah04.png

Une fois que l'installation (très rapide) est terminée, la fenêtre "Manage NuGet Packages" est rafraichie et je peux constater par une coche verte que le package "ELMAH" est désormais installé, ainsi que le package "ELMAH Core Library (no config)" dont il dépend.

Je peux alors fermer NuGet en cliquant sur le bouton "Close" en bas à gauche et constater que la librairie "Elmah" est maintenant référencée dans mon projet.

elmah05.png

Et ce n'est pas tout ! Le fichier Web.config a été modifié pour incorporer tous les paramètres nécessaires au bon fonctionnement de Elmah

...
<configuration>
  <configSections>
    <sectionGroup name="elmah">
      <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
      <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
      <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
      <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
    </sectionGroup>
...
    <httpModules>
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
    </httpModules>
    <httpHandlers>
      <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
    </httpHandlers>
  </system.web>
...
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
    </modules>
    <handlers>
      <add name="Elmah" path="elmah.axd" verb="POST,GET,HEAD" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
    </handlers>
  </system.webServer>

Je peux alors lancer l'application et me rendre à l'URL /elmah.axd pour constater que tout fonctionne sans encombre :

elmah06.png

Il ne me reste plus qu'à provoquer quelques erreurs :

  • accéder à un fichier /readme.txt inexistant
  • tester une route /Foo/Bar/1 qui n'existe pas

Puis retourner à l'adresse /elmah.axd pour m'assurer que ces deux erreurs ont bien été prises en compte :

elmah07.png

C'est déjà pas mal pour un début.

Il faut juste que je revois un peu la configuration pour que tout ça soit géré de façon plus pérenne et ne plus avoir "This log is provided by the In-Memory Error Log". Et aussi voir comment faire pour recevoir automatiquement un mél d'Elmah quand un problème survient.