<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1146316188254265608</id><updated>2026-02-13T12:05:25.623+01:00</updated><category term="Dojo"/><category term="ASP.NET MVC"/><category term="Autre"/><category term="GreaseMonkey"/><category term="OGame"/><category term=".NET"/><category term="ASP.NET"/><category term="EntityFramework.Patterns"/><category term="Visual Studio"/><category term="WCF"/><category term="Claymore"/><category term="Javascript"/><category term="Nuget"/><category term="SSAS"/><category term="AOP"/><category term="AllyStats"/><category term="BBB"/><category term="CSS"/><category term="Cache"/><category term="Elasticsearch"/><category term="Electronique"/><category term="Entity Framework"/><category term="IIS"/><category term="Kibana"/><category term="MVP"/><category term="NoSql"/><category term="ORM"/><category term="SMDBehavior"/><category term="SQL"/><category term="SSIS"/><category term="VSTS"/><category term="Afterthought"/><category term="Angular"/><category term="Azure"/><category term="BI"/><category term="Blogger"/><category term="C#"/><category term="CIL"/><category term="Continuous deployment"/><category term="Couchbase"/><category term="Dependency Injection"/><category term="DevTest lab"/><category term="ETL"/><category term="Google Charts"/><category term="IC"/><category term="IIS Express"/><category term="IOT"/><category term="Logstash"/><category term="MSBuild"/><category term="Mercurial"/><category term="Micro Framework"/><category term="Mono"/><category term="Mono.Cecil"/><category term="OData"/><category term="Obsidian"/><category term="Octopus"/><category term="SSRS"/><category term="SignalR"/><category term="Subsonic"/><category term="TPL.Dataflow"/><category term="Ubuntu"/><category term="VM"/><category term="Virtual Earth"/><category term="Webjobs"/><category term="dynamic"/><category term="ngTables"/><title type='text'>Memory Leaks</title><subtitle type='html'>Blog sur les technos Microsoft.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default?start-index=26&amp;max-results=25'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>65</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-4936438813703886692</id><published>2018-04-03T00:13:00.000+02:00</published><updated>2018-04-03T00:14:43.078+02:00</updated><title type='text'>J&#39;recommence ailleurs, je git mon blog!</title><content type='html'>&lt;br /&gt;
Voila, ça fait maintenant 8 ans que de temps en temps je postais un article ici sur les techno Microsoft.&lt;br /&gt;
&lt;br /&gt;
Malheureusement, &lt;a href=&quot;https://www.blogger.com&quot;&gt;blogger&lt;/a&gt; n&#39;a plus beaucoup évolué depuis un sacré bon moment et ne match plus trop avec mes attentes.&lt;br /&gt;
&lt;br /&gt;
J&#39;aurais du prendre cette décision il y a déjà plusieurs années, mais cette fois-ci c&#39;est fait,  je déménage vers &lt;a href=&quot;http://www.mymemoryleaks.fr/&quot;&gt;http://www.mymemoryleaks.fr/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
On se retrouve &lt;a href&quot;http://www.mymemoryleaks.fr/&quot;&gt;la-bas&lt;/a&gt;?&lt;br /&gt;
&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/4936438813703886692/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/4936438813703886692' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/4936438813703886692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/4936438813703886692'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2018/04/jrecommence-ailleurs-je-git-mon-blog.html' title='J&#39;recommence ailleurs, je git mon blog!'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-1698090388055688175</id><published>2018-02-09T23:52:00.000+01:00</published><updated>2018-02-09T23:57:51.560+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Azure"/><category scheme="http://www.blogger.com/atom/ns#" term="VSTS"/><category scheme="http://www.blogger.com/atom/ns#" term="Webjobs"/><title type='text'>Déployer un webjob avec VSTS</title><content type='html'>&lt;br /&gt;
&lt;br /&gt;
Si vous avez déjà eu besoin de déployer un &lt;a href=&quot;https://docs.microsoft.com/fr-fr/azure/app-service/web-sites-create-web-jobs&quot;&gt;azure webjob&lt;/a&gt; via vsts, vous avez du tomber sur ce &lt;a href=&quot; https://medium.com/@thomashellstrom/building-azure-webjobs-in-vsts-4306e141df49&quot;&gt;bon blog post de Thomas Hellstrøm&lt;/a&gt;. Néanmoins, en suivant telles quelles les instructions de notre ami Thomas, vous risquer de casser la webapp qui host votre webjob. &lt;br /&gt;
&lt;br /&gt;
Ce blog post va prendre la tournure d’une recette de cuisine, d’un pense bête ; cela m’évitera de me reposer la même question dans quelques mois, et j&#39;espère secrètement que cela puisse aider certains d&#39;entre vous.&lt;br /&gt;
&lt;br /&gt;
On commence donc par utiliser la fonction « Publish as Azure Webjob » à partir de Visual Studio 2017. &lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=1oxmVOgeleLcE0HoiBmqXgw4NdZPzV1f6&quot; width=&quot;600&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
Pas la peine d’aller au bout du deploy, ce tool va ajouter le package nuget &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.Web.WebJobs.Publish/&quot;&gt;Microsoft.Web.WebJobs.Publish&lt;/a&gt; et créer le fichier « webjob-publish-settings.json » dans le répertoire properties de votre projet.&lt;br /&gt;
&lt;br /&gt;
On passe ensuite sur le build sur VSTS. Thomas nous propose de définir les arguments suivants sur la tache msbuild :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:ps&quot;&gt;/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true 
/p:SkipInvalidConfigurations=true /p:Configuration=Release
&lt;/pre&gt;&lt;br /&gt;
Notez le paramètre « /p:WebPublishMethod=Package », qui produira un fichier zip.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=1Y9grjF4l84j-rI2G-7wRxUalCeD3h2cJ&quot; width=&quot;600&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
Et en jetant un œil dans le fichier zip, mauvaise surprise, on est en train de packager le dossier bin avec des dll qui vont venir écraser celles qui appartiennent à la webapp.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=13Jx4y2OZzK3HOhF9C1Bnl7yMs6fs_-DQ&quot; width=&quot;600&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
Du coup j’vous propose de corriger ça. &lt;br /&gt;
On commence par changer les arguments de la tache msbuild. &lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=1-t4EzYGYxTRwzM5iLDSSJzQSPEUDRs3L&quot; width=&quot;600&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:ps&quot;&gt;/p:DeployOnBuild=true /p:WebPublishMethod=FileSystem 
/p:publishUrl=&quot;$(build.artifactstagingdirectory)&quot; /p:DeployDefaultTarget=WebPublish 
&lt;/pre&gt;&lt;br /&gt;
Ce qui va produire le même contenu que le fichier zip mais directement sur le système de fichier.&lt;br /&gt;
&lt;br /&gt;
Puis on ajoute une tache delete file, qui se chargera de supprimer le dossier /bin que nous voulons éviter de déployer.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=13y7Jd2gEmFBlOKOeAr2EVsypWOf63FTZ&quot; width=&quot;600&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Voila, cette fois ci nous y sommes. J’espère que cela pourra vous aider!&lt;br /&gt;
&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/1698090388055688175/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/1698090388055688175' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/1698090388055688175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/1698090388055688175'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2018/02/deployer-un-webjob-avec-vsts.html' title='Déployer un webjob avec VSTS'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-8165414889367533222</id><published>2018-01-30T00:14:00.000+01:00</published><updated>2018-01-30T00:30:55.172+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="DevTest lab"/><category scheme="http://www.blogger.com/atom/ns#" term="IC"/><category scheme="http://www.blogger.com/atom/ns#" term="VM"/><category scheme="http://www.blogger.com/atom/ns#" term="VSTS"/><title type='text'>VSTS – Quand y’a plus de crédits, y’en a encore.</title><content type='html'>&lt;br /&gt;
Ça, c’est la poisse:  &lt;code&gt;Your account has no free minutes remaining&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
Le scénario est à se pendre, tu montes ton projet en intégration continue et après quelques (dizaines) de commit tu te retrouves dans l’impossibilité de complétera une PR ou juste vérifier que le dernier commit n’a pas introduit de régressions. &lt;br /&gt;
&lt;br /&gt;
Du coup je me propose de présenter ici, comment créer à moindre frais un agent de build sur-vitaminé. Et le fait d’avoir une machine un peu costaud, n’est pas un moindre mal ; qui ne s’est pas arraché les cheveux en attendant que l’agent de build hosté veuille bien se lancer et faire son travail… ?&lt;br /&gt;
&lt;br /&gt;
Plutôt que de créer nous même une vm, installer windows, msbuild et tout le nécessaire a un agent de build, on va plutôt utiliser azure &lt;a href=&quot;https://azure.microsoft.com/fr-fr/services/devtest-lab/&quot;&gt;DevTest Lab&lt;/a&gt;. L’idée est de tirer parti des template de vm qui sont mises a notre dispo.&lt;br /&gt;
&lt;br /&gt;
Après avoir créé votre première instance DevTest lab, on ajoute une vm basée sur l’image Visual Studio Community 2017 (latest release) on Windows Server 2016 (x64).&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://drive.google.com/uc?export=download&amp;id=1yq-8OdL7oeffvZ-lsW8Ll01dy0n6g8KQ&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://drive.google.com/uc?export=download&amp;id=1yq-8OdL7oeffvZ-lsW8Ll01dy0n6g8KQ&quot; width=&quot;600&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On va vous demander un login et un mot de passe pour le compte admin de la future vm.&lt;br /&gt;
Je vous conseille de stocker votre mot de passe dans le coffre-fort « my secret » pour une plus grande sécurité. (ce n’est donc pas mon mot de passe que vous voyez 😊)&lt;br /&gt;
&lt;br /&gt;
Bon il nous faut maintenant choisir les caractéristiques de la vm. J’ai opté pour 32 GO de ram et 8 vcpu, une D8S_V3, elle ne sera allumée que quelques minutes le temps de faire le build, donc elle ne nous coutera pas bien cher.&lt;br /&gt;
&lt;br /&gt;
Place aux artefacts, il convient de voir cela comme des scripts additionnels qui installeront d’autres programmes/services sur votre vm. Ça tombe bien, l’artefact VSTS Build agent nous procure le service de build qui convient.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://drive.google.com/uc?export=download&amp;id=1uhrvXnuNP5G6U7X66SdH3tj7XSmK380K&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://drive.google.com/uc?export=download&amp;id=1uhrvXnuNP5G6U7X66SdH3tj7XSmK380K&quot; width=&quot;600&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Quelques précisions, le champs VSTS account name doit se conformer au pattern suivant : &lt;code&gt;https://{{vsts_account_name}}.visualstudio.com&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Le secret correspond une clé privée que vous pourrez crée en vous rendant à l’adresse &lt;code&gt;https://{{vsts_account_name}}.visualstudio.com/_details/security/tokens&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Finalement, l’agent pool doit être un pool pré-existant. A vérifier/créer ici : &lt;code&gt;https://{{vsts_account_name}}.visualstudio.com/_admin/_AgentPool&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Petit plus, dans le cas ou vous envisagez de builder des projets front, profitez de cette étape pour ajouter l’artefact NODE JS.&lt;br /&gt;
&lt;br /&gt;
Bon, aller y’a plus qu’a cliquer sur OK, attendre quelques minutes et l’agent devrait apparaitre dans le pool que vous avez choisi.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://drive.google.com/uc?export=download&amp;id=1fLWtBjZ32fLL-ilmRq1GqPr3-dm8DK3j&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://drive.google.com/uc?export=download&amp;id=1fLWtBjZ32fLL-ilmRq1GqPr3-dm8DK3j&quot; width=&quot;600&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Quoi qu’il en soit pas de panique, si vous vous êtes trompé sur un paramètre des artefacts, il sera toujours possible de retenter l’installation a postériori ou bien de procéder a l’installation manuellement.&lt;br /&gt;
&lt;br /&gt;
Dernier point, si vos crédits azure ne vous permettent pas de laisser cette vm allumée tout le temps, voici deux petites commandes qui vous permettront d’allumer et d’éteindre la vm a volonté. (a utiliser dans une console &lt;a href=&quot;https://docs.microsoft.com/fr-fr/cli/azure/install-azure-cli?view=azure-cli-latest&quot;&gt;azure cli&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:ps&quot;&gt;az lab vm {{command}} --lab-name {{devtestlab}} --name {{vm-name}} 
--resource-group {{resource-group}}
&lt;/pre&gt;command : start ou stop&lt;br /&gt;
devtestlab : le nom de votre instance DevTest lab&lt;br /&gt;
vm-name : le nom de votre vm&lt;br /&gt;
resource-group : le nom du resource group ou est installé la vm.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/8165414889367533222/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/8165414889367533222' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/8165414889367533222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/8165414889367533222'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2018/01/vsts-quand-ya-plus-de-credit-yen-encore.html' title='VSTS – Quand y’a plus de crédits, y’en a encore.'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-2590624891092221896</id><published>2016-12-12T12:46:00.000+01:00</published><updated>2016-12-12T15:09:56.101+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Angular"/><category scheme="http://www.blogger.com/atom/ns#" term="Javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="ngTables"/><category scheme="http://www.blogger.com/atom/ns#" term="OData"/><title type='text'>OData &amp; ngTable : un duo de choc</title><content type='html'>&lt;br /&gt;
Dernièrement, j’ai pas mal fait joujou avec &lt;a href=&quot;http://www.odata.org/documentation/&quot;&gt;OData&lt;/a&gt;. &lt;br /&gt;
C’est quand même super plaisant de pouvoir requêter une source de données via une URL et avec une richesse proche de ce que l’on connait avec du SQL.&lt;br /&gt;
Une fois n’est pas coutume je ne vais pas parler de .NET mais plutôt partager avec vous un bout de javascript qui met en évidence la facilité avec laquelle vous pourrez brancher des tables &lt;a href=&quot;http://ng-table.com/&quot;&gt;ngtable&lt;/a&gt; avec votre backend odata.&lt;br /&gt;
&lt;br /&gt;
Trêve de bavardage, on passe au code :&lt;br /&gt;
&lt;br /&gt;
&lt;script async src=&quot;http://jsfiddle.net/mymemoryleaks/r5hfj5b2/12/embed/js,html,result/dark/&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
Pour cette illustration, j&#39;ai utilisé le web service &lt;a href=&quot;http://services.odata.org/&quot;&gt;services.odata.org&lt;/a&gt; qui expose la base Northwind (sample Microsoft) que l&#39;on a tous croisés un jour.&lt;br /&gt;
&lt;br /&gt;
Juste un mot sur le code, évidemment c&#39;est le service odataTableService qui fait la glue entre OData et ngTable; c&#39;est lui qui permet de réaliser les filtrages et les sorts. Une fois que ce service est disponible dans votre app, regardez avec quelle simplicité, votre controller peut créer une table : &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:js&quot;&gt;$scope.tableParams = odataTableService.createTableParams({
      endPoint: &#39;http://services.odata.org/V3/Northwind/Northwind.svc/Products&#39;
    });
&lt;/pre&gt;&lt;br /&gt;
Je me demande vraiment pourquoi OData n&#39;a pas plus que ça le vent en poupe.&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/2590624891092221896/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/2590624891092221896' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/2590624891092221896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/2590624891092221896'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2016/12/odata-ngtable-un-duo-de-chox.html' title='OData &amp; ngTable : un duo de choc'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-2397553588961823242</id><published>2016-09-01T22:07:00.000+02:00</published><updated>2016-09-01T22:18:48.387+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Continuous deployment"/><category scheme="http://www.blogger.com/atom/ns#" term="Octopus"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL"/><title type='text'>Packager un projet SQL pour Octopus</title><content type='html'>&lt;br /&gt;
Que ce soit manuellement ou de manière automatique, lorsque l&#39;on parle de déploiement il va nous falloir définir un package de déploiement.&lt;br /&gt;
&lt;br /&gt;
Dans l&#39;univers Octopus, les packages de déploiement sont des fichiers avec une extension .nupkg. Voyons comment en créer un pour un projet de Base de données.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Ajouter une dépendance vers Octopack&lt;/h2&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/OctopusDeploy/OctoPack&quot;&gt;Octopack&lt;/a&gt; est l’utilitaire que nous allons utiliser pour générer ce package de déploiement. Démystifions le terme, octopack produit un fichier qui n’est autre qu’un zip, contenant les fichiers à déployer ainsi qu’un ensemble de métadonnées et potentiellement des scripts powershell. &lt;br /&gt;
Bref, rien de bien extraordinaire.&lt;br /&gt;
&lt;br /&gt;
Pour l’installer dans notre projet de base de données, nous allons utiliser Nuget, qui est un gestionnaire de dépendances très performant et bien connu des développeurs. Cependant il n’est pas facilement accessible lorsqu’on travailler sur un projet SQL/SSIS/SSRS/SSAS.&lt;br /&gt;
&lt;br /&gt;
Pour tromper Visual Studio nous allons commencer par ajouter un projet C# de type console pour faire simple&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=0B3FYDprTEqfhX2MtUFgtaWkzSnc&quot; width=&quot;500px&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
Ajoutons sur ce projet C# une dépendance vers Octopack.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=0B3FYDprTEqfhWW5GRURBWXZOaGc&quot; width=&quot;500px&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
Dans la nouvelle fenêtre on cherche le package Octopack, et on l’installe.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=0B3FYDprTEqfhYTBIVkZQenpZWkU&quot; width=&quot;500px&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
Après avoir acquitté la fenêtre de preview d’install, la fenêtre «Output» de visual Studio devrait vous confirmer que l’installation s’est bien passée.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=0B3FYDprTEqfhNVVFYnBwZEs1bmc&quot; width=&quot;500px&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
Il aurait été formidable de pouvoir l’installer directement dans notre projet de base, mais nous allons devoir transpirer un peu plus pour arriver à nos fins.&lt;br /&gt;
Ready ?? Ouvrons le fichier csproj de l’application console et copions la portion de msbuild qui correspond à Octopack&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=0B3FYDprTEqfhT0RybERZZi1hWnc&quot; width=&quot;500px&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
Puis, copions la discrètement dans notre fichier sqlproj, de la même manière à la fin de celui-ci.&lt;br /&gt;
Un petit rebuild pour vérifier que tout fonctionne toujours bien… et TADAM y’a toujours pas de package de déploiement généré.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Créer le package&lt;/h2&gt;&lt;br /&gt;
Bon si vous avez été un peu curieux, vous aurez remarqué que la portion de msbuild que l’on a copiée a pour but d’importer un autre fichier msbuild (qui se trouve dans le répertoire packages\OctoPack.3.4.1\tools\OctoPack.targets)&lt;br /&gt;
&lt;br /&gt;
En baragouinant un peu le msbuild, on comprend assez vite que la variable &lt;code&gt;RunOctoPack&lt;/code&gt; est initialisée à &lt;code&gt;false&lt;/false&gt; et c’est elle qui déclenche ou non la génération du package.&lt;br /&gt;
&lt;br /&gt;
Alors évidemment, une solution possible est de modifier cette variable à true. Néanmoins cela induit qu’un package de déploiement sera créé a chaque build du projet. Ce n’est vraisemblablement pas ce que vous souhaitez.&lt;br /&gt;
&lt;br /&gt;
Je vous propose plutôt d’ouvrir une console DOS et une fois dans le répertoire du projet, tapez la commande suivante : &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:bash&quot;&gt;msbuild ContinuousBI.Sql.sqlproj /t:Build /p:RunOctoPack=true&lt;/pre&gt;&lt;br /&gt;
Si tout s’est bien passé vous devriez avoir une sortie similaire a celle-ci : &lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=0B3FYDprTEqfhVUh0aGctS2RJb0k&quot; width=&quot;500px&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
Cette fois ci, si vous jetez un œil dans le sous-dossier obj/octopacked de votre projet vous y découvrirez un fichier .nupkg qui est le package de déploiement &lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;A quoi ressemble mon package ?&lt;/h2&gt;&lt;br /&gt;
Pour aller un peu plus loin nous pouvons jeter un œil à ce qui a été produit pour nous par Octopack. &lt;br /&gt;
Je vous propose d’utiliser &lt;a href=&quot;https://npe.codeplex.com/downloads/get/clickOnce/NuGetPackageExplorer.application&quot;&gt;nuget package explorer&lt;/a&gt;&lt;br /&gt;
Ouvrez le et glissez déposez le fichier .nupkg, vous devriez obtenir un résultat semblable à celui-ci.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=0B3FYDprTEqfhTTFubGpDVU9wa3M&quot; width=&quot;500px&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
C’est confirmé, le dacpac issu de la compilation à bien été reconnu ; il est embarqué dans package de déploiement.&lt;br /&gt;
&lt;br /&gt;
Nous verrons dans le prochain post comment le déployer avec Octopus.&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/2397553588961823242/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/2397553588961823242' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/2397553588961823242'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/2397553588961823242'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2016/09/packager-un-projet-sql-pour-octopus.html' title='Packager un projet SQL pour Octopus'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-3544845483115652000</id><published>2016-05-11T23:34:00.000+02:00</published><updated>2016-05-11T23:40:18.201+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="BBB"/><category scheme="http://www.blogger.com/atom/ns#" term="Electronique"/><title type='text'>Prolific usb to ttl et windows 10</title><content type='html'>&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=0B3FYDprTEqfhdWZ0NHAxcGRMalk&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Dernièrement j&#39;ai ressorti ma &lt;a href=&quot;https://beagleboard.org/black&quot;&gt;BeableBone Black&lt;/a&gt; histoire de faire une peu de veille techno. J&#39;vous raconterai un de ces quatre en quoi monter une boite peut vite cramer tout votre temps libre, mais c&#39;est pour la bonne cause. &lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=0B3FYDprTEqfhR3hTSnd4Z0FXNGM&quot; width=&quot;300px&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Bref pour en revenir à la Beagle, je ressors mon câble série que j&#39;utilise pour me connecter à la console. Je fais les branchements et go sur le site de &lt;a href=&quot;http://www.prolific.com.tw/US/ShowProduct.aspx?p_id=225&amp;pcid=41&quot;&gt;Prolific&lt;/a&gt; pour récupérer le dernier driver pour Windows 10.&lt;br /&gt;
&lt;br /&gt;
Tiens! bizarre, même après un reboot je n&#39;ai toujours rien qui s&#39;affiche dans mon terminal.&lt;br /&gt;
En creusant, je m&#39;aperçois que le driver du câble n&#39;est pas reconnu.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://drive.google.com/uc?export=download&amp;id=0B3FYDprTEqfhWTJhdmlPLTE0Q0k&quot; width=&quot;600px&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
S&#39;en suit plusieurs tentatives de réinstallation et de reboot infructueuses.&lt;br /&gt;
&lt;br /&gt;
Je cherche un peu sur Internet, pas mal de personnes ont des soucis avec des versions contrefaites acheté sur des sites asiatiques. Le mien vient de chez &lt;a href=&quot;https://www.adafruit.com/product/954&quot;&gt;Adafruit&lt;/a&gt;, et il fonctionnait parfaitement il y a quelques mois, sur Windows 8.&lt;br /&gt;
&lt;br /&gt;
Ho... tiens réessayons sur cet ancien PC. Ca fonctionne parfaitement!&lt;br /&gt;
Énorme je récupère l&#39;installer du driver qui se trouve sur ce dernier; &lt;br /&gt;
Je repasse sur mon PC équipé de Windows 10, désinstalle le driver en place, reboot, installe l&#39;ancien driver (fonctionnant sur Windows 8) et surprise, ca fonctionne.&lt;br /&gt;
&lt;br /&gt;
Si ça c&#39;est pas de l&#39;obsolescence programmée! Honteux!&lt;br /&gt;
Rien que pour ça, je vous recommande plutôt d&#39;investir dans un câble concurrent comme ce &lt;a href=&quot;https://www.adafruit.com/products/70&quot;&gt;FTDI&lt;/a&gt;. J&#39;en possède un également et fonctionne tout aussi bien.&lt;br /&gt;
&lt;br /&gt;
Du coup, je vous dépose le driver fonctionnel, &lt;a href=&quot;https://drive.google.com/uc?export=download&amp;id=0B3FYDprTEqfhanJlSTBZY3ZnZnc&quot;&gt;ici&lt;/a&gt;. J&#39;espères que cela pourra aider quelqu&#39;un.&lt;br /&gt;
&lt;br /&gt;
Tiens, en prime je poste ici le schéma de branchement du câble Prolific avec la beagle.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Le fil noir va sur le pin 1 (GND)&lt;/li&gt;
&lt;li&gt;le fil vert sur le pin 4 (RECEIVE)&lt;/li&gt;
&lt;li&gt;le fil blanc sur le pin 5 (TRANSMIT)&lt;/li&gt;
&lt;/ul&gt;Ne branchez surtout pas le fil rouge, c&#39;est du 5V, vous grilleriez la beagle!!&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/3544845483115652000/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/3544845483115652000' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/3544845483115652000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/3544845483115652000'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2016/05/prolific-usb-to-ttl-et-windows-10.html' title='Prolific usb to ttl et windows 10'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-5646201105795767330</id><published>2015-07-24T14:51:00.002+02:00</published><updated>2015-07-24T15:06:10.630+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><category scheme="http://www.blogger.com/atom/ns#" term="dynamic"/><title type='text'>Comment invoquer une méthode dont on connait le nom à l’exécution sur un dynamic?</title><content type='html'>Comment invoquer une méthode dont on connait le nom à l&#39;exécution sur un dynamic?&lt;br /&gt;
&lt;br /&gt;
Le mot clé dynamic en C# n&#39;est pas nouveau, il a vu le jour avec C# 4 et pourtant il n’apparaît pas si souvent que ça dans les bouts de code que je fréquente.&lt;br /&gt;
&lt;br /&gt;
Dernièrement je l&#39;ai recroisé en utilisant &lt;a href=&quot;http://signalr.net/&quot;&gt;SignalR&lt;/a&gt;; les hubs qui sont générés sont des objets dynamic. &lt;br /&gt;
&lt;br /&gt;
Quoi qu&#39;il en soit, dernièrement j&#39;ai eu besoin d&#39;invoquer une méthode dont le nom ne m&#39;était connu qu&#39;à l&#39;exécution.  &lt;br /&gt;
Croyez-moi, j&#39;y ai passé un petit moment avant d&#39;y arriver... Cela révèle vraisemblablement ma grande ignorance :)&lt;br /&gt;
&lt;br /&gt;
Ce blog post prendra donc la forme d&#39;un post-it qui me fera gagner du temps la prochaine fois que je me frotterai a cette bête-là. Si pour vous les classes &lt;a href=&quot;https://msdn.microsoft.com/fr-fr/library/microsoft.csharp.runtimebinder(v=vs.110).aspx&quot;&gt;Binder&lt;/a&gt; et &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callsite(v=vs.110).aspx&quot;&gt;CallSite&lt;/a&gt; n&#39;ont plus de secret ce blog post vous semblera vraisemblablement bien terne.&lt;br /&gt;
&lt;br /&gt;
Posons le problème, on me donne un objet dynamic auquel une méthode est ajoutée à l&#39;exécution &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;private string sentence = &amp;quot;Hello world&amp;quot;;

        public dynamic BuildObj()
        {
            dynamic myDynObj = new ExpandoObject();
            myDynObj.SayHello = new Func&amp;lt;string&amp;gt;(() =&amp;gt; sentence);
            return myDynObj;
        }
&lt;/pre&gt;&lt;br /&gt;
Si j&#39;avais connaissance de la méthode lors de la compilation je pourrais l&#39;appeler ainsi :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;[Test]
        public void CallDirectlyMethod()
        {
            dynamic myObj = BuildObj();

            var ret = myObj.SayHello();
            Assert.That(ret, Is.EqualTo(sentence));
        }
&lt;/pre&gt;&lt;br /&gt;
Malheureusement la signature de la méthode ne m&#39;est connue qu&#39;à l&#39;exécution. &lt;br /&gt;
Ok, premier réflexe je sors l&#39;attirail de la reflection.... mais les résultats restent catastrophiques : &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;[Test]
        public void CallMethodWithReflectionFails()
        {
            dynamic myObj = BuildObj();
            Type t = myObj.GetType();
            var method = t.GetMethod(&amp;quot;SayHello&amp;quot;, BindingFlags.Default | BindingFlags.Instance | BindingFlags.InvokeMethod  | BindingFlags.NonPublic);
            Assert.That(method, Is.Null);
        }
&lt;/pre&gt;&lt;br /&gt;
Quels que soient les bindings flags, impossible de trouver la méthode... FAIL!!&lt;br /&gt;
&lt;br /&gt;
Voici, donc la combinaison magique, un savant mélange de Runtime.Binder et CallSite... &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;[Test]
        public void CallMethodWithCallSite()
        {
            dynamic myObj = BuildObj();

            var callSiteBinder = Binder.InvokeMember(CSharpBinderFlags.None, &amp;quot;SayHello&amp;quot;,
                Enumerable.Empty&amp;lt;Type&amp;gt;(), myObj.GetType(),
                new []
                {
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
                });

            var callSite = CallSite&amp;lt;Func&amp;lt;CallSite, object, object&amp;gt;&amp;gt;.Create(callSiteBinder);
            string ret = callSite.Target(callSite, myObj);

            Assert.That(ret, Is.EqualTo(sentence));
        }
&lt;/pre&gt;&lt;br /&gt;
Ok, essayons de décrypter un peu ce code qui semble un peu alambiqué.&lt;br /&gt;
Binder.InvokeMember va nous permettre à l&#39;exécution de pointer la bonne méthode un peu comme le ferait typeof(myObj).GetMethod()&lt;br /&gt;
Le premier paramètre permet de spécifier la manière dont est traité le type de retour. Dans le cas d&#39;une Action nous aurions pu utiliser CSharpBinderFlags.ResultDiscarded. Dans notre cas, une Func, CSharpBinderFlags.None fonctionne bien.&lt;br /&gt;
&lt;br /&gt;
puis viens en seconde position, évidement le nom de la méthode a appelé, passée sous forme de chaine.&lt;br /&gt;
&lt;br /&gt;
En troisième position, il conviendra de fournir la liste des arguments de types à nécessaire dans le cas d&#39;une méthode générique.&lt;br /&gt;
&lt;br /&gt;
Viens ensuite le type sur lequel effectuer l&#39;invocation, ce qui permet de pointer une surcharge.&lt;br /&gt;
&lt;br /&gt;
Et finalement les informations sur les paramètres attendus et le type de retour (le premier élément du tableau); &lt;br /&gt;
&lt;br /&gt;
La création du CallSite&amp;lt;Func&amp;lt;CallSite, object, object&amp;gt;&amp;gt; permet d&#39;arrêter la signature du delegate que l&#39;on cherche à appeler. Notez, que le dernier argument générique &quot;object&quot; devrait etre &quot;string&quot;, car il représente le type de retour de la func... mais pour une raison qui m&#39;échappe l&#39;utilisation de string comme type de retour entraîne une erreur au runtime, alors que le retour de la func est bien affecté à une variable string à la ligne du dessous... il faut bien garder un peu de magie :)&lt;br /&gt;
&lt;br /&gt;
Ok, évidemment il ne nous reste plus qu&#39;à effectuer l&#39;invocation, ce qui est réalisé via le code callSite.Target(callSite, myObj);&lt;br /&gt;
&lt;br /&gt;
J&#39;espère que ce post évitera quelques cheveux blancs a ceux qui se trouveront confronté au problème.</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/5646201105795767330/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/5646201105795767330' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/5646201105795767330'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/5646201105795767330'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2015/07/comment-invoquer-une-methode-dont-on.html' title='Comment invoquer une méthode dont on connait le nom à l’exécution sur un dynamic?'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-3125965987368391268</id><published>2015-06-01T12:31:00.000+02:00</published><updated>2015-06-01T14:03:23.244+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="BBB"/><category scheme="http://www.blogger.com/atom/ns#" term="IOT"/><category scheme="http://www.blogger.com/atom/ns#" term="Mono"/><category scheme="http://www.blogger.com/atom/ns#" term="Ubuntu"/><title type='text'>BeagleBone Black du carton à Mono</title><content type='html'>&lt;br /&gt;
&lt;a href=&quot;http://beagleboard.org/BLACK&quot;&gt;L’IOT&lt;/a&gt;, on en parle partout, de plus en plus ; évidemment l’univers Microsoft n’est pas en retrait sur ce domaine avec la mise à disposition de Windows 10 sur le &lt;a href=&quot;https://msdn.microsoft.com/fr-fr/Library/Windows/Hardware/dn914597.aspx?f=255&amp;amp;MSPPError=-2147217396#raspberry_pi_2&quot;&gt;Raspberry&lt;/a&gt; ou encore le &lt;a href=&quot;https://msdn.microsoft.com/fr-fr/Library/Windows/Hardware/dn914597.aspx?f=255&amp;amp;MSPPError=-2147217396#minnowboard_max&quot;&gt;MinnowBoard MAX&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Vous trouverez pas mal de blog post autour du raspberry… je vais donc plutôt vous présenter comment vous lancer dans le développement .NET embarqu&amp; sur cette magnifique plateforme qu’est le &lt;a href=&quot;http://beagleboard.org/BLACK&quot;&gt;BeagleBone Black (BBB)&lt;/a&gt;. Au travers de cet article je vous propose d’étudier les différentes étapes à réaliser pour pouvoir lancer votre premier « Hello World » embarqué.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCWu8Fun-Vw5jmvoBe6jBR_FRkw_cImBqGhXjvo6GCfhXjoovkUXuLsHjoLO7n-GoLu5kBgsxlboPI_j_kNGsG7nWm14BLCMu3Ug9vmzNfGVomQekMlZ_MZEoCtimE7GqKF8K5lcEE-E9H/s1600/bbb_overview.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;220&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCWu8Fun-Vw5jmvoBe6jBR_FRkw_cImBqGhXjvo6GCfhXjoovkUXuLsHjoLO7n-GoLu5kBgsxlboPI_j_kNGsG7nWm14BLCMu3Ug9vmzNfGVomQekMlZ_MZEoCtimE7GqKF8K5lcEE-E9H/s320/bbb_overview.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Tout d’abord il n’y a pas de Windows 10 sur le BBB, en tout cas pour l’instant, mais très honnêtement l’installation d’Ubuntu que je vous propose est à la portée de tous.&lt;br /&gt;
&lt;br /&gt;
&lt;h1&gt;Matériel nécessaire&lt;/h1&gt;&lt;br /&gt;
Je commence par un petit coup de pub pour le site &lt;a href=&quot;https://www.adafruit.com/&quot;&gt; AdaFruit&lt;/a&gt; ou vous trouverez tout le matos que vous pouvez imaginer pour nos petits joujoux.&lt;br /&gt;
&lt;br /&gt;
Aller Go ! Pour faciliter la visualisation de ce qui se passe sur votre BBB je vous conseille d’investir dans un câble &lt;a href=&quot;https://www.adafruit.com/products/70&quot;&gt;Serial TTL-232 en usb&lt;/a&gt;. Sans celui-ci vous devrez attendre que le BeagleBone ai récupéré une IP et vous y connecter (en ssh par exemple) et interagir avec.&lt;br /&gt;
&lt;br /&gt;
Pour brancher le câble prenez comme repère le fil noir qui doit venir se placer sur le pin J1 de votre BBB.&lt;br /&gt;
&lt;br /&gt;
Installez les drivers FTDI pour prendre en compte l’adaptateur usb. Ils se trouvent &lt;a href=&quot;http://www.ftdichip.com/Drivers/VCP.htm&quot;&gt;ici&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Finalement en utilisant &lt;a href=&quot;http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html&quot;&gt;Putty&lt;/a&gt;, configuré comme ci-dessous la console s’affiche enfin sur votre pc.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD-pwyLuopodRFxha5GdlqxCda6i-QNV2rZkhwn3QrkTof8MZW9HV3n_8PHj6ddeW4F0cKCbP9b1ULQPfEa_tlCX2MwaMLCQJdbgk5pGYIdrfgAY-LG6Q6PLq5qcBAHegbobjbq5mjGFL9/s1600/putty.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD-pwyLuopodRFxha5GdlqxCda6i-QNV2rZkhwn3QrkTof8MZW9HV3n_8PHj6ddeW4F0cKCbP9b1ULQPfEa_tlCX2MwaMLCQJdbgk5pGYIdrfgAY-LG6Q6PLq5qcBAHegbobjbq5mjGFL9/s320/putty.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Si l’idée de brancher un câble Ethernet sur votre BeagleBone vous donne de l’urticaire, je vous conseille ce &lt;a href=&quot;https://www.adafruit.com/products/70&quot;&gt;dongle usb&lt;/a&gt;. Il est directement reconnu sous Ubuntu.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h1&gt;Installation d’Ubuntu&lt;/h1&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjV55OuvFzc9r8lQ86dapUl1PVWyYwdWJ4SkU-SnE30_LAmROwuw-SKl22QGCr8I9PtThbjkkRhhwVQTPybW1Bp-tHlSUv4HqRy_Sc6-ojJuoRg82X4k5K_yctoGjHYZ9KhPumowG32dqEe/s1600/ubuntu.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;141&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjV55OuvFzc9r8lQ86dapUl1PVWyYwdWJ4SkU-SnE30_LAmROwuw-SKl22QGCr8I9PtThbjkkRhhwVQTPybW1Bp-tHlSUv4HqRy_Sc6-ojJuoRg82X4k5K_yctoGjHYZ9KhPumowG32dqEe/s200/ubuntu.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Nous allons installer dans la mémoire eMMC la version 14.04 d’Ubuntu spécialement conçue pour la BBC. Après avoir &lt;a href=&quot;https://rcn-ee.com/rootfs/2015-05-08/flasher/BBB-eMMC-flasher-ubuntu-14.04.2-console-armhf-2015-05-08-2gb.img.xz&quot;&gt;téléchargé&lt;/a&gt; le fichier img.xz, il vous faudra le décompresser avec un outil comme &lt;a href=&quot;http://www.7-zip.org/&quot;&gt;7zip&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
L’image ainsi extraite pourra être copiée sur une micro sd avec &lt;a href=&quot;http://sourceforge.net/projects/win32diskimager/files/latest/download&quot;&gt;Win 32 Disk Imager&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Lorsque la copie se termine, insérer la micro sd dans le port prévu à cet effet sur la BBB. Tout en appuyant avec votre index sur le bouton « boot » (le plus proche du port Ethernet), alimentez la BeagleBone. Laissez le doigt appuyé jusqu’à ce que les diodes clignotent. &lt;br /&gt;
&lt;br /&gt;
Il faut 5 bonnes minutes pour que l’installation se termine ; mais grâce au câble TTL vous serez aux premières loges pour suivre l’installation.&lt;br /&gt;
&lt;br /&gt;
&lt;h1&gt;Mise à jour du Système et installation de mono&lt;/h1&gt;&lt;br /&gt;
Ok, si vous en êtes arrivé là, c’est du tout cuit. &lt;br /&gt;
&lt;br /&gt;
Nous allons commencer par mettre à jour le système grâce package manager &lt;a href=&quot;https://wiki.debian.org/Apt&quot;&gt;APT&lt;/a&gt;. A partir de la console tapez les commandes suivantes : &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:shell&quot;&gt;sudo apt-get update
sudo apt-get upgrade
&lt;/pre&gt;&lt;br /&gt;
Après quelques minutes le système est prêt, on peut passer à Mono. Le runtime devrait être suffisant étant donné que l’on va se contenter d’exécuter des binaires créer sur votre machine de dev. Pour l’installation on tape donc : &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:shell&quot;&gt;sudo apt-get install mono-runtime&lt;/pre&gt;&lt;br /&gt;
&lt;h1&gt;Création de l’exécutable et déploiement sur le BBB&lt;/h1&gt;&lt;br /&gt;
Je vous laisse écrire votre premier Hello Beagle World dans Visual Studio ; en créant un projet de type console et en targettant le Framework 4.5; &lt;br /&gt;
&lt;br /&gt;
Une fois compilé, j’ai opté pour un déploiement type « bin-deploy » en utilisant un transfert via &lt;a href=&quot;http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html&quot;&gt;PSCP&lt;/a&gt; &lt;br /&gt;
&lt;br /&gt;
Une fois PSCP copié, vous pourriez copier le fichier avec une ligne de commande comme celle-ci : &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:ps&quot;&gt;pscp.exe &quot;C:\ BBB\ HelloWorld\bin\Debug\HelloWorld.exe&quot; ubuntu@192.168.10.2:/home/ubuntu&lt;/pre&gt;&lt;br /&gt;
Le premier paramètre étant le ficher à transmettre le second l’url de destination au format : &lt;br /&gt;
&lt;br /&gt;
user@hote:/chemin_de_destination&lt;br /&gt;
&lt;br /&gt;
En dessert, après tous ces efforts, nous pouvons enfin exécuter sur le Beagle notre Hello World en tapant : &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:ps&quot;&gt;Mono HelloWorld.exe&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/3125965987368391268/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/3125965987368391268' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/3125965987368391268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/3125965987368391268'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2015/06/beaglebone-black-du-carton-mono.html' title='BeagleBone Black du carton à Mono'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-6678579582565280874</id><published>2014-12-23T10:39:00.000+01:00</published><updated>2014-12-23T15:17:24.733+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="BI"/><category scheme="http://www.blogger.com/atom/ns#" term="Elasticsearch"/><category scheme="http://www.blogger.com/atom/ns#" term="Kibana"/><category scheme="http://www.blogger.com/atom/ns#" term="NoSql"/><title type='text'>Kibana : Explorez vos données.</title><content type='html'>&lt;p&gt;Cet article fait partie d’une sérié dédiée à &lt;a href=&quot;http://www.elasticsearch.org/&quot;&gt;Elasticsearch&lt;/a&gt;, reportez vous à &lt;a href=&quot;http://mymemoryleaks.blogspot.com/2014/12/serie-elasticsearch.html&quot;&gt;l’article sommaire&lt;/a&gt; pour accéder facilement aux autres posts.&lt;p&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.elasticsearch.org/overview/kibana/&quot;&gt;Kibana&lt;/a&gt; est la brique de visualisation qui gravite autour d’Elasticsearch. Voici, quelques exemple de représentations faites avec Kibana : &lt;br /&gt;
&lt;br /&gt;
&lt;a href=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimMaI2-3EC3zCDDQi_XRKSvbN1OXrp6Pv_Z32ivsBT6-5ZMlyV9bSCQDyqGB5BXSZQO5yhcWkv_fr-DYd2RomY4f2kBR1vBEMiqlKgXL_zsIr49Fymhf3Vzl0JbMS98xCA3N1me0A7OWZX/s1600/kibana1.png&#39; dojotype=&#39;dojox.image.Lightbox&#39; group=&#39;Kibana&#39; title=&#39;1&#39;&gt;&lt;br /&gt;
&lt;img src=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimMaI2-3EC3zCDDQi_XRKSvbN1OXrp6Pv_Z32ivsBT6-5ZMlyV9bSCQDyqGB5BXSZQO5yhcWkv_fr-DYd2RomY4f2kBR1vBEMiqlKgXL_zsIr49Fymhf3Vzl0JbMS98xCA3N1me0A7OWZX/s1600/kibana1.png&#39; width= alt=&#39;Kibana 1&#39;/&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
&lt;a href=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi27-f3l-OXXvtMd7EvnqMepPiV5smNUbHkbLhV7xJ1P5bxNcvZNH2-86WJgViOzkO559u9uzr7xMF6hsefIPfVYX-LU5_A176OAQ00RV66N-WWiSZs7k2lIPgQ6WeP1UbdyypjApTpPnBt/s1600/kibana2.png&#39; dojotype=&#39;dojox.image.Lightbox&#39; group=&#39;Kibana&#39; title=&#39;2&#39;&gt;&lt;br /&gt;
&lt;img src=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi27-f3l-OXXvtMd7EvnqMepPiV5smNUbHkbLhV7xJ1P5bxNcvZNH2-86WJgViOzkO559u9uzr7xMF6hsefIPfVYX-LU5_A176OAQ00RV66N-WWiSZs7k2lIPgQ6WeP1UbdyypjApTpPnBt/s1600/kibana2.png&#39; alt=&#39;Kibana 2&#39;/&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
&lt;a href=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjP92KKQY3UCjNF-Clk3QnjvNDe8bmCvmJAbdQDp3fO2jrSEGq1qohEZfWe0NEGsjm-BzMsNydYOiFYC_O7WfngP1q3WHWCKdX4lbS0gWoZzFUKG8pE4sZhFAe65PRofhk5x-6jgpMm1At5/s1600/kibana3.png&#39; dojotype=&#39;dojox.image.Lightbox&#39; group=&#39;Kibana&#39; title=&#39;3&#39;&gt;&lt;br /&gt;
&lt;img src=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjP92KKQY3UCjNF-Clk3QnjvNDe8bmCvmJAbdQDp3fO2jrSEGq1qohEZfWe0NEGsjm-BzMsNydYOiFYC_O7WfngP1q3WHWCKdX4lbS0gWoZzFUKG8pE4sZhFAe65PRofhk5x-6jgpMm1At5/s1600/kibana3.png&#39; alt=&#39;Kibana 3&#39;/&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;L’exploration de données et la réalisation de dashboard ne nécessitent aucun code, ce qui permet de donner la main aux fonctionnels ; De plus Kibana et Elastocsearch permettent d’avoir des rapports real time, se mettant à jour à mesure que les données sont stockées.&lt;/p&gt;&lt;p&gt;Pour les lecteurs qui connaissent bien la stack SQL Serveur, on pourrait le comparer à un Report Builder sous stéroïdes et surtout qui tiendrait (mieux) ses promesses de simplicités et d’accessibilité pour les non-techniciens&lt;/p&gt;&lt;p&gt;Je me propose dans ce billet de découvrir ensemble les fonctionnalités de « data discovering » sur un &lt;a href=&quot;https://www.data.gouv.fr/fr/datasets/base-de-donnees-des-accidents-corporels-de-la-circulation/&quot;&gt;dataset public&lt;/a&gt; recensant les accidents corporels  de la circulation&lt;/p&gt;&lt;p&gt;Si ces données vous intéressent, je vous invite d’ailleurs à jeter un œil à la très bonne session (&lt;a href=&quot;https://www.youtube.com/watch?v=2rB7CbCVb1U&quot;&gt;video&lt;/a&gt;, &lt;a href=&quot;https://onedrive.live.com/?cid=11D07374EB30D233&amp;id=11D07374EB30D233%21915&quot;&gt;slides&lt;/a&gt;) de &lt;a href=&quot;http://patriceharel.blogspot.com/&quot;&gt;Patrice Harel&lt;/a&gt; sur le mining avec SSAS et qui s’appui sur le même jeu de données.&lt;/p&gt;&lt;br /&gt;
&lt;h1&gt;Installation&lt;/h1&gt;&lt;p&gt;Commençons par l’installation qui comme pour les autres composants de la stack est triviale :&lt;br /&gt;
Tout commence évidement par le téléchargement du binaire &lt;a href=&quot;http://www.elasticsearch.org/overview/kibana/installation/&quot;&gt;ici&lt;/a&gt;, suivi de la décompression de l’archive.&lt;br /&gt;
Si votre instance elasticsearh ne tourne pas sur le même serveur qui hébergera Kibana ou si elle écoute sur un port non standard, il vous faudra modifier le fichier de configuration config/kibana.yml. &lt;br /&gt;
Dans mon cas, je ne touche à rien!&lt;br /&gt;
Puis à l’aide d’une fenêtre commande, il nous faudra exécuter /bin/kibana après s’être placé dans le répertoire ou a été décompressé l’archive.&lt;br /&gt;
Finalement pointons notre navigateur sur l’url &lt;a href=&quot;#&quot;&gt;http://localhost:5601&lt;/a&gt;&lt;br /&gt;
&lt;/p&gt;&lt;h1&gt;Exploration&lt;/h1&gt;&lt;p&gt;S’il s’agit de la première fois que vous lancez Kibana, cet écran vous sera présenté, dans lequel il vous faudra choisir un index (équivalent de base de données) ainsi qu’une colonne typée date.&lt;br /&gt;
Ce dernier point est extrêmement important, car Kibana part du principe qu’il est naturel pour l’esprit humain et plus facile de découvrir des données lorsqu’elles sont représentées sur une frise.&lt;br /&gt;
&lt;a href=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBT7u77-sG6Alwhyl7ejqYcbWoLosb_l4umZYdNUo4SnPBsmUbQboccJ7BYv-4MJiP2JiLK1Z5RAQkN0u6-8kOqCgP20YqCPtZNbKt_O8SBpBv8isR82eg4zKDjp597JuWPUcqPYo3cI2P/s1600/kibana_configIndex.png&#39; dojotype=&#39;dojox.image.Lightbox&#39; group=&#39;filters&#39; title=&#39;configure&#39;&gt;&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBT7u77-sG6Alwhyl7ejqYcbWoLosb_l4umZYdNUo4SnPBsmUbQboccJ7BYv-4MJiP2JiLK1Z5RAQkN0u6-8kOqCgP20YqCPtZNbKt_O8SBpBv8isR82eg4zKDjp597JuWPUcqPYo3cI2P/s1600/kibana_configIndex.png&quot; width=&quot;650px&quot; /&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
Dans notre dataset, nous ne disposons malheureusement pas de la date de l’accident, qui aurait été le candidat idéal en tant que « time field ». &lt;br /&gt;
Pour l’exemple, nous nous rabattrons sur le champ @timestamp représentant l’instant ou a été inséré l’événement dans notre index.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;On se retrouve propulsé dans nos données via l’écran suivant : &lt;br /&gt;
&lt;a href=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcGk4tnd631SKIp90NCRo30TIhZ3jeMWuKGyNv75bxOCgvRjciXF-dojPdZZBqh4RMoMGU990RB4kLgKRjqRCS5smglo4eYbZmX3tV6-hj3LUgN8WjVbo2-R6W4m4Z6H_4W7BGujDdd-pz/s1600/kibana_zones.png&#39; dojotype=&#39;dojox.image.Lightbox&#39; group=&#39;filters&#39; title=&#39;explore&#39;&gt;&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcGk4tnd631SKIp90NCRo30TIhZ3jeMWuKGyNv75bxOCgvRjciXF-dojPdZZBqh4RMoMGU990RB4kLgKRjqRCS5smglo4eYbZmX3tV6-hj3LUgN8WjVbo2-R6W4m4Z6H_4W7BGujDdd-pz/s1600/kibana_zones.png&quot; width=&quot;650px&quot; /&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
On reconnait très vite plusieurs sections dans cette interface :&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;La colonne de gauche qui contient les champs à disposition (1).&lt;/li&gt;
&lt;li&gt;Tout en haut (2), une zone de filtre ; n’oublions pas qu’elasticsearch est un moteur de recherche…&lt;/li&gt;
&lt;li&gt;L’indicateur du nombre d’enregistrements après filtrage (3).&lt;/li&gt;
&lt;li&gt;La frise temporelle sur laquelle on regarde les événements (4).&lt;/li&gt;
&lt;li&gt;Finalement la vue tableau de données au centre. Notons que pour l’instant elle nous représente la version brute des données, car nous n’avons pas encore choisit de colonnes à afficher.&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;Commençons  par cliquer sur les barres du graph afin d’effectuer un drilldown au niveau temps.&lt;br /&gt;
&lt;a href=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgA8M5RRR1aQkxWHwgQ-0xU7TAnLC8IUhU5Nm7EvLksk7e-A-RR6KLH6HKb76MuGfc_ryWST060L1aYlqgbPPhuOCjERx4mQuw1dBIGmkrbeOacgL4l_kMRQMDdl4YhGPmd8sBALyIRbTJ2/s1600/kibana_timeseries.png&#39; dojotype=&#39;dojox.image.Lightbox&#39; group=&#39;filters&#39; title=&#39;times series&#39;&gt;&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgA8M5RRR1aQkxWHwgQ-0xU7TAnLC8IUhU5Nm7EvLksk7e-A-RR6KLH6HKb76MuGfc_ryWST060L1aYlqgbPPhuOCjERx4mQuw1dBIGmkrbeOacgL4l_kMRQMDdl4YhGPmd8sBALyIRbTJ2/s1600/kibana_timeseries.png&quot; width=&quot;650px&quot; /&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
Instantanément cela nous permet de découvrir la répartition des data dans le temps. Notez, que les clics que nous avons fait sur le graph sont interprétés comme une clause de filtrage, diminuant les événements auxquels on s’intéresse.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Pour avoir un aperçu du contenu des champs, je vous conseille de cliquer sur le nom d&#39;un champ dans la colonne de gauche ; comme ceci :&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9jd5vIQ024cl5w9cBYG9gjmTKDkP9HSA8JJPM2ypGGmYdPRf7WQO0ju_F9t6Y43-one4TlTZf4S5e1xsuZlBpdCJS1xVQFpg5HByhs8oZT04klCVg_c3T7rUGo90w6OatB48HKJAnaplT/s1600/kibana_FieldCount.png&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Les informations et actions présentées ici sont une vraie mine d’or.&lt;br /&gt;
En plus d&#39;un premier comptage des données sous-jacentes, on peut par exemple se concentrer sur les événements qui ont eu lieu sur l’A31 en cliquant sur l&#39;icone loupe+. Evidemment, la frise temporelle et les données sont mis à jour.&lt;br /&gt;
&lt;a href=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs9e7m3abKr8goPbSNl9h_PigIanDO3YFyzbkIcHgs3rjA-SU9O-Gyxa8j09fR0_JRlsKFK27nmmW9RQaRndDN8qVobZerXHPknnGDUnb4oWeWKFAtBxKjhtbUgCDE-QWJWrrpOf6RuLxf/s1600/kibana_filteredtimeseries.png&#39; dojotype=&#39;dojox.image.Lightbox&#39; title=&#39;time series&#39;&gt;&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs9e7m3abKr8goPbSNl9h_PigIanDO3YFyzbkIcHgs3rjA-SU9O-Gyxa8j09fR0_JRlsKFK27nmmW9RQaRndDN8qVobZerXHPknnGDUnb4oWeWKFAtBxKjhtbUgCDE-QWJWrrpOf6RuLxf/s1600/kibana_filteredtimeseries.png&quot; width=&quot;650px&quot;/&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Maintenant, intéressons nous au champ tbl qui représente le nombre de blessés légers dans un accident.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkURR-YL75TJvoQf0WW3wzMSGuY7Y_jYSXDuS25gB5irq5A031gRG2xxf3DplDi4IbZR5FLBzCBX5RZxde95-uSIscUyHMiiy5q5AK_ciMZ73FjhA4gLFn0j5qi5NHGkdnMAYf9IJVMPS-/s1600/kibana_tbl.png&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
En cliquant sur « Visualize », on obtient la répartition top 20, sous forme d’histogramme, du nombre de blessés légers sur l’ensemble des événements de la base.&lt;br /&gt;
&lt;a href=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbiY9Q9WdFzlLp_D16ohbN0NbZSOncFN-z5B2vYhNQuw2FOJ1rS5-sdSJlBQhv-flJz5h3MXLUqv_fh6we4yYfwkWWQMfpCC5EnnM1SChxQ_YoswG4SiN2bgQNC05huI2FMIV1miDECOEL/s1600/kibana_visualize.png&#39; dojotype=&#39;dojox.image.Lightbox&#39; title=&#39;Visualize&#39;&gt;&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbiY9Q9WdFzlLp_D16ohbN0NbZSOncFN-z5B2vYhNQuw2FOJ1rS5-sdSJlBQhv-flJz5h3MXLUqv_fh6we4yYfwkWWQMfpCC5EnnM1SChxQ_YoswG4SiN2bgQNC05huI2FMIV1miDECOEL/s1600/kibana_visualize.png&quot; width=&quot;650px&quot;/&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
Ici aussi cette visualisation, nous permet d’appréhender rapidement la teneur de nos données.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Finalement jetons un œil, au filtre qui se trouve tout en haut de l’interface de Kibana. Par défaut, vous y trouverez une *. Attention, il n’y a pas ici d’analogie avec SQL, ici l’étoile signifie sans filtre.&lt;br /&gt;
Nous pourrions par exemple nous intéresser à une commune en particulier, celle de Cergy par exemple (95002). Il nous suffira pour ce faire de saisir le filtre suivant : &lt;br /&gt;
&lt;pre class=&quot;brush:javascript&quot;&gt;codeinsee:=95002&lt;/pre&gt;&lt;a href=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsyEK_nQx1TQl2Po7WbJ0XFfAiqRcYDigv5xWkzJ7tVn6GqCRWVLkSz8ZmcdkwNC5m3BdGJoGKQ0sDW_rHoTYaj-piCfGZXliBAcuFT30GCwbpi8Hsb453XWLs359Ylx-F8CGKhU3xawFW/s1600/kibana_QueryEqual.png&#39; dojotype=&#39;dojox.image.Lightbox&#39; group=&#39;filters&#39; title=&#39;Equals filter&#39;&gt;&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsyEK_nQx1TQl2Po7WbJ0XFfAiqRcYDigv5xWkzJ7tVn6GqCRWVLkSz8ZmcdkwNC5m3BdGJoGKQ0sDW_rHoTYaj-piCfGZXliBAcuFT30GCwbpi8Hsb453XWLs359Ylx-F8CGKhU3xawFW/s1600/kibana_QueryEqual.png&quot; width=&quot;650px&quot;/&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
Ou bien les accidents impliquant plus de 2 morts&lt;br /&gt;
&lt;pre class=&quot;brush:javascript&quot;&gt;ttu&amp;#233;:&amp;gt;2&lt;/pre&gt;&lt;a href=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3Qt9VwEZHk77EoO8x3OEQM0f2U8GxH8pqgTZIwGZIVTp8HL5Xu0K-wBc9xT2nIjQ0XoFQOpmCloH5FHqkjtpewNosK6DXbdGhITxeAdgOTGAmRmrYgWLoBq6xIYER4dHUQafSwYQboAH5/s1600/kibana_QueryGreater.png&#39; dojotype=&#39;dojox.image.Lightbox&#39; group=&#39;filters&#39; title=&#39;Greater filter&#39;&gt;&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3Qt9VwEZHk77EoO8x3OEQM0f2U8GxH8pqgTZIwGZIVTp8HL5Xu0K-wBc9xT2nIjQ0XoFQOpmCloH5FHqkjtpewNosK6DXbdGhITxeAdgOTGAmRmrYgWLoBq6xIYER4dHUQafSwYQboAH5/s1600/kibana_QueryGreater.png&quot; width=&quot;650px&quot;/&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
Ou encore les accidents impliquant plus de 2 morts dans l’Oise :&lt;br /&gt;
&lt;pre class=&quot;brush:javascript&quot;&gt;ttu&amp;#233;:&amp;gt;2 AND codeinsee [60000 TO 69999]&lt;/pre&gt;&lt;a href=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoOT3M1PKJfdC0oGrSrr42PkZYALOVZuWwDNm83QOpylfIQfPUskxZhePIlxW-pvHT_ffGSRkJ3j87q6CNIipbySb7h-xSovpdYZEKcrUsOSWMbSJ7zy0J3PCcKQuWzTC59cpUgUUfmaLs/s1600/kibana_QueryRange.png&#39; dojotype=&#39;dojox.image.Lightbox&#39; group=&#39;filters&#39; title=&#39;Range filter&#39;&gt;&lt;br /&gt;
&lt;img src=&#39;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoOT3M1PKJfdC0oGrSrr42PkZYALOVZuWwDNm83QOpylfIQfPUskxZhePIlxW-pvHT_ffGSRkJ3j87q6CNIipbySb7h-xSovpdYZEKcrUsOSWMbSJ7zy0J3PCcKQuWzTC59cpUgUUfmaLs/s1600/kibana_QueryRange.png&#39; width=&quot;650px&quot;/&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Voila qui clos ce premier article sur Kibana, en espérant vous avoir donné envie d’essayer ce superbe outil.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/6678579582565280874/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/6678579582565280874' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/6678579582565280874'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/6678579582565280874'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2014/12/kibana-explorez-vos-donnees.html' title='Kibana : Explorez vos données.'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimMaI2-3EC3zCDDQi_XRKSvbN1OXrp6Pv_Z32ivsBT6-5ZMlyV9bSCQDyqGB5BXSZQO5yhcWkv_fr-DYd2RomY4f2kBR1vBEMiqlKgXL_zsIr49Fymhf3Vzl0JbMS98xCA3N1me0A7OWZX/s72-c/kibana1.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-7183755155035218922</id><published>2014-12-23T10:37:00.001+01:00</published><updated>2014-12-23T10:40:59.413+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Elasticsearch"/><category scheme="http://www.blogger.com/atom/ns#" term="Kibana"/><category scheme="http://www.blogger.com/atom/ns#" term="Logstash"/><category scheme="http://www.blogger.com/atom/ns#" term="NoSql"/><title type='text'>Série Elasticsearch</title><content type='html'>&lt;p&gt;Ce post fait office de sommaire à toute une série d’articles que j’ai bon espoir d’écrire sur cette toute fin d’année 2014 et le début 2015.&lt;/p&gt;&lt;p&gt;Mais pourquoi parler d’Elasticsearch, moi qui ne traite que de technos Microsoft sur ce blog?&lt;/p&gt;&lt;p&gt;Cela part du constat qu’a mon humble avis, la stack BI Microsoft pèche sur deux points : &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Premièrement, il n’existe pas d’outils permettant une exploration décente des données non encore nettoyées, rangées, retraitées etc.… d’ailleurs, plus la volumétrie est importante et plus ce point est difficilement adressable.&lt;br /&gt;
(i.e : sur de petites volumétries, j’en entends déjà me dire qu’Excel peut avoir ce rôle, avec un enchevêtrement de tableaux croisés dynamiques etc… )&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;L’outillage de reporting est assez pauvre et n’est vraiment pas penser pour être à destination des fonctionnels.&lt;br /&gt;
Je m’explique Reporting Services fait le job lorsqu’il s’agit de réaliser un document pro format, mais nécessite des compétences techniques que nos fonctionnels ne disposent pas ; et c’est bien normal.&lt;br /&gt;
Vous aurez probablement également entendu parler de la version « User Friendly » de « Reporting Services », j’ai nommé Report Builder. La tentative est louable, mais le résultat n’est pas la à hauteur. &lt;br /&gt;
Encore une fois dans les faits, bien peut de fonctionnels ont les connaissances, l’envie et le temps de l’utiliser.&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;C’est avec ces regrets dans l’âme, que je me retrouve lors de la conférence &lt;a href=&quot;http://ncraft.io&quot;&gt;ncraft 2014&lt;/a&gt; à assister à une superbe session d’&lt;a href=&quot;http://code972.com/blog&quot;&gt;Itamar Syn-Hershko&lt;/a&gt; consacrée au couple Elasticsearch et Kibana. &lt;/p&gt;&lt;p&gt;Je vous passe les détails de &lt;a href=&quot;https://www.youtube.com/watch?v=s_1IiYQyB20&quot;&gt;cette présentation&lt;/a&gt;, mais effet whaou garanti vers la fin de la session lorsque Kibana rentre en scène.&lt;/p&gt;&lt;p&gt;Certain doivent se dire qu’il m’a fallu presque 1 an pour commencer à sortir un article, quelle productivité !&lt;/p&gt;&lt;p&gt;Pour être tout à fait franc, il y a 1 an il manquait encore quelques features indispensable a mon sens pour que Kibana puisse jouer un rôle aussi important que ce pour quoi il à été conçu. L’exemple le plus probant était l’impossibilité de réaliser un « distinc count » ; un « show stopper » pour qui compte faire un peu de BI sérieusement.&lt;/p&gt;&lt;p&gt;Voila pour le petit historique et mes états d’âmes ; Kibana est arrivé à maturité selon moi dans ses cas d’utilisation standard et cela mérité bien qu’on s’y intéresse ainsi qu’a l’écosystème qui gravite autour.&lt;/p&gt;&lt;p&gt;Voici enfin l’heure du menu : &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://mymemoryleaks.blogspot.com/2014/12/kibana-explorez-vos-donnees.html&quot;&gt;1ere Partie : Explorez vos données avec Kibana&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2eme Partie : Chargez vos données, les yeux fermés avec Logstash&lt;/li&gt;
&lt;li&gt;3eme Partie : Introduction à Elasticsearch&lt;/li&gt;
&lt;li&gt;4eme Partie : Changement de mapping et Reindexation&lt;/li&gt;
&lt;li&gt;5eme Partie : Reporting avancé &amp; Dashbording (Kibana)&lt;/li&gt;
&lt;li&gt;6eme Partie : Transformation de données (Logstash)&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;Il y’a de forte chance que ce sommaire soit agrémenté d’autres articles dans le futur ; le domaine étant extrêmement large.&lt;/p&gt;&lt;p&gt;Dernier point, l’ordre des premiers articles peut vous paraître étrange ; j’ai voulu partir de ce qui apportera le plus de valeur ajouté aux fonctionnels pour finir par ce qui requiers le plus de compétences techniques.&lt;/p&gt;&lt;p&gt;Il ne me reste qu&#39;a vous souhaiter une bonne lecture, et n&#39;hésitez pas a me laisser vos commentaires.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/7183755155035218922/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/7183755155035218922' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/7183755155035218922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/7183755155035218922'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2014/12/serie-elasticsearch.html' title='Série Elasticsearch'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-6183422271543389951</id><published>2014-04-11T15:13:00.002+02:00</published><updated>2014-04-11T16:23:49.017+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="Cache"/><category scheme="http://www.blogger.com/atom/ns#" term="Couchbase"/><title type='text'>Utiliser Couchbase comme serveur de cache</title><content type='html'>&lt;p&gt;Dernièrement, je vous présentais une façon simple d&#39;utiliser le &lt;a href=&quot;http://mymemoryleaks.blogspot.fr/2014/04/poor-mans-cache.html&quot;&gt;cache dans vos applications .NET&lt;/a&gt;&lt;br /&gt;
Cependant cette solution possède plusieurs inconvénients. En voici quelque uns : &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Le cache est lié au processus système de votre application (executable / IIS etc...). Si votre programme plante ou est fermé, vous perdez votre cache&lt;/li&gt;
&lt;li&gt;Si vos besoins en mémoire augmentent, cette solution n&#39;est pas scalable&lt;/li&gt;
&lt;li&gt;Rien n&#39;est mis a disposition pour monitorer votre cache&lt;/li&gt;
&lt;li&gt;Vous n&#39;avez pas d&#39;interface de gestion du cache (augmentation de la mémoire allouée etc...)&lt;/li&gt;
&lt;li&gt;Vous ne pouvez pas invalider le cache sans arrêter l&#39;application.&lt;/li&gt;
&lt;li&gt;etc...&lt;/li&gt;
&lt;/ul&gt;Bref, vous avez compris, c&#39;est une solution pour démarrer petit.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Aujourd&#39;hui, je voudrais partager avec vous une solution qui répond à tous les manques évoqués plus haut et plus encore.&lt;br /&gt;
Couchbase est une base NoSQL Key/Value; la value ayant comme particularité d&#39;être un document json.&lt;br /&gt;
Couchbase est issu du mariage heureux de Membase (cache mémoire avec réplication des caches, persistance et interface d’admin Web sexy) et &lt;br /&gt;
CouchDB (NoSQL orienté document). Ce qui nous intéresse plus particulièrement aujourd&#39;hui sont les fonctionnalités qui en font un bon serveur de cache.&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
&lt;h3&gt;Installation&lt;/h3&gt;&lt;br /&gt;
&lt;p&gt;Pour l&#39;installer, tout commence par &lt;a href=&quot;http://www.couchbase.com/couchbase-server/overview&quot;&gt;télécharger le setup ici&lt;/a&gt;&lt;/p&gt;Je vous passe le scénario d&#39;installation qui a le bon gout de se faire en &quot;Next&quot; &gt; &quot;Next&quot; &gt; &quot;Next&quot;&lt;br /&gt;
&lt;br /&gt;
Passons à la configuration : &lt;br /&gt;
&lt;br /&gt;
Dans la première étape, il vous faudra spécifier l&#39;emplacement des fichiers (base et index) ainsi que la mémoire dévolue à Couchbase.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLKjGGtGbmy4lrggFJZKqTaGAlBtexbItEz_As-ub0sLF5-e1GwwisAnUU23xZMEhvg_7CTisePHGua8lnozwWJ_J1KH8zy-gWqhtecNGF0TJ75ictrqJhR28Q6MyshpglDIFCYSiBgoVC/s1600/config_couchbase.png&quot; imageanchor=&quot;1&quot; &gt;&lt;img width=&quot;704px&quot; border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLKjGGtGbmy4lrggFJZKqTaGAlBtexbItEz_As-ub0sLF5-e1GwwisAnUU23xZMEhvg_7CTisePHGua8lnozwWJ_J1KH8zy-gWqhtecNGF0TJ75ictrqJhR28Q6MyshpglDIFCYSiBgoVC/s1600/config_couchbase.png&quot; alt=&quot;configure server&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Un peu plus loin nous allons créer le l&#39;espace qui accueillera les objets que l&#39;on va mettre en cache (bucket).&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirOLh344WXLfHgP6ejP6PvwvPKr9BnS9WO9GaRv5kUKU-dgSfvcwLXGiJIvzScMK_t4eTQ8CYKAJT798wrfdhuw57WJdlovnxKjezgQjk_bcbouNtFs0LS1k67-ZZtI-EAdS4chcntGlpd/s1600/bucket.png&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; width=&quot;704px&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirOLh344WXLfHgP6ejP6PvwvPKr9BnS9WO9GaRv5kUKU-dgSfvcwLXGiJIvzScMK_t4eTQ8CYKAJT798wrfdhuw57WJdlovnxKjezgQjk_bcbouNtFs0LS1k67-ZZtI-EAdS4chcntGlpd/s1600/bucket.png&quot; alt=&quot;bucket&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Quelques instant plus tard vous voila avec un Couchbase flambant neuf sur votre machine.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3nTU4dVFuqtFCfDDoFjduUh9nCA88qY5Ljqj-CibBnjWxyuCzr1BsqvOy7i2AkjE8-lQmRH8mbazMVO_RanHeIK3xxQNwgmKnej02JQLMP90nTOKNXSfZ26WDvskQbHfaVg6vO4HWbesU/s1600/complete.png&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; width=&quot;704px&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3nTU4dVFuqtFCfDDoFjduUh9nCA88qY5Ljqj-CibBnjWxyuCzr1BsqvOy7i2AkjE8-lQmRH8mbazMVO_RanHeIK3xxQNwgmKnej02JQLMP90nTOKNXSfZ26WDvskQbHfaVg6vO4HWbesU/s1600/complete.png&quot; alt=&quot;up and running&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Note : si la page ne s&#39;ouvre pas automatiquement dans votre browser, la console d&#39;admin de couchbase se trouve a l&#39;adresse suivante : &lt;a href=&quot;http://localhost:8091/&quot;&gt;http://localhost:8091/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Implementation&lt;/h3&gt;&lt;br /&gt;
&lt;p&gt;Couchbase dispose d&#39;un très bel écosystème qui gravite autour, et la plateforme .NET ne fait pas exception.&lt;br /&gt;
Je me propose d&#39;adapter le cache manager vu dans le &lt;a href=&quot;http://mymemoryleaks.blogspot.fr/2014/04/poor-mans-cache.html&quot;&gt;précédent article.&lt;/a&gt;&lt;br /&gt;
Pour rappel nous avions l&#39;interface suivante :&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;public interface ICacheManager
{
    T GetOrInsert&amp;lt;T&amp;gt;(string key, Func&amp;lt;T&amp;gt; callback) where T : class;
}
&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;Passons à l&#39;implémentation. Il va nous falloir un driver, que l&#39;on peut aisément installer via &lt;a href=&quot;http://www.nuget.org/&quot;&gt;nuget&lt;/a&gt; : &lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgohiDE27m9XWM7ndl8tAnxqR2EC3IfWENa6Dwxxm8UbMCke0iASya9PJDREZHyB183bdY-N3Td9EByR3cMThlT9sxoG6F7pp0_DREIyPYla7FXNJ-8owURHN1RlrcUr2TG97KtTPEZNUtg/s1600/nuget_couchbase.png&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgohiDE27m9XWM7ndl8tAnxqR2EC3IfWENa6Dwxxm8UbMCke0iASya9PJDREZHyB183bdY-N3Td9EByR3cMThlT9sxoG6F7pp0_DREIyPYla7FXNJ-8owURHN1RlrcUr2TG97KtTPEZNUtg/s1600/nuget_couchbase.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
son utilisation est des plus simple, avec des méthodes explicites comme Get() et Store().&lt;br /&gt;
Voici une implémentation de cache respectant notre interface basée sur Couchbase.&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;public class CouchbaseCacheManager : ICacheManager
    {

        private readonly CouchbaseClient _client;

        public CouchebaseCacheManager()
        {
            _client = new CouchbaseClient();
        }

        public T GetOrInsert&amp;lt;T&amp;gt;(string key, Func&amp;lt;T&amp;gt; callback) where T : class
        {
            T elmnt;
            try
            {
                if (_client.KeyExists(key))
                    return _client.Get&amp;lt;T&amp;gt;(key);
                elmnt = callback();
                _client.Store(StoreMode.Add, key, elmnt);
            }
            catch (Exception)
            {
                elmnt = callback();
            }
            return elmnt;
        }
    }
&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;Et vous, quel type de cache utilisez vous dans vos projets? &lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/6183422271543389951/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/6183422271543389951' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/6183422271543389951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/6183422271543389951'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2014/04/couchbase-cache.html' title='Utiliser Couchbase comme serveur de cache'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLKjGGtGbmy4lrggFJZKqTaGAlBtexbItEz_As-ub0sLF5-e1GwwisAnUU23xZMEhvg_7CTisePHGua8lnozwWJ_J1KH8zy-gWqhtecNGF0TJ75ictrqJhR28Q6MyshpglDIFCYSiBgoVC/s72-c/config_couchbase.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-7530338812596821373</id><published>2014-04-04T17:10:00.001+02:00</published><updated>2014-04-04T17:11:42.336+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="Cache"/><category scheme="http://www.blogger.com/atom/ns#" term="Dependency Injection"/><title type='text'>Poor man&#39;s cache</title><content type='html'>&lt;p&gt;Depuis la version 4 du framework .NET, la gestion d&#39;un cache est profondement encrée dans l&#39;adn de notre framework.&lt;br /&gt;
Il devient alors extrêmement facile de stocker en mémoire à peu près n&#39;importe quoi.&lt;br /&gt;
Je vous livre dans ce court billet, une implémentation extrêmement simple que j&#39;utilise souvent dans mes projets.&lt;br /&gt;
Commençons par définir une interface, qui nous permettra &lt;a href=&quot;http://blog.ploeh.dk/tags.html#Dependency Injection-ref&quot;&gt;d&#39;injecter&lt;/a&gt; notre cache manager un peu partout : &lt;br /&gt;
&lt;/p&gt;&lt;pre class=&quot;brush:csharp&quot;&gt;public interface ICacheManager
{
    T GetOrInsert&amp;lt;T&amp;gt;(string key, Func&amp;lt;T&amp;gt; callback) where T : class;
}
&lt;/pre&gt;&lt;p&gt;et finalement voici une implémentation extra simple de notre cache manager&lt;/p&gt;&lt;pre class=&quot;brush:csharp&quot;&gt;public class CacheManager : ICacheManager
{
    public T GetOrInsert&amp;lt;T&amp;gt;(string key, Func&amp;lt;T&amp;gt; callback) where T : class
    {
        ObjectCache cache = MemoryCache.Default;
        if (cache.Contains(key))
            return cache[key] as T;
        T elmnt = callback();
        cache.Add(new CacheItem(key, elmnt), new CacheItemPolicy());
        return elmnt;
    }
}
&lt;/pre&gt;&lt;p&gt;Voici un exemple d&#39;utilisation.&lt;/p&gt;&lt;pre class=&quot;brush:csharp&quot;&gt;IEnumerable&amp;lt;Product&amp;gt; products = _cache.GetOrInsert(&amp;quot;Ma_Clef_Unique_Cache&amp;quot;, 
() =&amp;gt; { return _productService.GetFrenchProducts(); } );
&lt;/pre&gt;&lt;p&gt;Simple non?&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/7530338812596821373/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/7530338812596821373' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/7530338812596821373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/7530338812596821373'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2014/04/poor-mans-cache.html' title='Poor man&#39;s cache'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-1995835899282812420</id><published>2014-03-28T23:23:00.001+01:00</published><updated>2014-03-28T23:29:49.989+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="IIS"/><category scheme="http://www.blogger.com/atom/ns#" term="IIS Express"/><title type='text'>IISExpress : Servir des pages vers l’extérieur.</title><content type='html'>&lt;p&gt;Nul doute, IISExpress nous a simplifié la vie au quotidien de par sa facilité d&#39;utilisation et son intégration à Visual Studio.&lt;br /&gt;
Aujourd&#39;hui, je devais travailler à rendre un site compatible avec l&#39;ipad. Ni une ni deux, je lance safari et pointe vers l&#39;ip de ma machine de dev.&lt;br /&gt;
Et boom une belle erreur, me prévient que IISExpress ne servira de pages qu&#39;en local.&lt;/p&gt;&lt;p&gt;Voici comment je l&#39;ai configuré afin de pouvoir tester sur mon Ipad.&lt;/p&gt;&lt;h3&gt;1 - Configurons notre site web afin qu&#39;il soit bindé sur toutes les IP de notre machine de dev.&lt;/h3&gt;&lt;p&gt;Pour ce faire ouvrons le fichier de config de IISExpress qui se trouve sur : %userprofile%\My Documents\IISExpress\config\applicationhost.config&lt;br /&gt;
Recherchons la config de notre site&lt;/p&gt;&lt;br /&gt;
&lt;pre class=&quot;brush:xml&quot;&gt;&amp;lt;site name=&amp;quot;MonSite&amp;quot; id=&amp;quot;10&amp;quot;&amp;gt;
&amp;lt;application path=&amp;quot;/&amp;quot; applicationPool=&amp;quot;Clr4IntegratedAppPool&amp;quot;&amp;gt;
&amp;lt;virtualDirectory path=&amp;quot;/&amp;quot; physicalPath=&amp;quot;C:\!Project\MonSite&amp;quot; /&amp;gt;
&amp;lt;/application&amp;gt;
&amp;lt;bindings&amp;gt;
&amp;lt;binding protocol=&amp;quot;https&amp;quot; bindingInformation=&amp;quot;*:44300:localhost&amp;quot; /&amp;gt;
&amp;lt;/bindings&amp;gt;
&amp;lt;/site&amp;gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;remplaçons le binding afin que le site soit servi quelque soit l&#39;ip sur laquelle arrive la requete&lt;/p&gt;&lt;br /&gt;
&lt;pre class=&quot;brush:xml&quot;&gt;&amp;lt;site name=&amp;quot;MonSite&amp;quot; id=&amp;quot;10&amp;quot;&amp;gt;
&amp;lt;application path=&amp;quot;/&amp;quot; applicationPool=&amp;quot;Clr4IntegratedAppPool&amp;quot;&amp;gt;
&amp;lt;virtualDirectory path=&amp;quot;/&amp;quot; physicalPath=&amp;quot;C:\!Project\MonSite&amp;quot; /&amp;gt;
&amp;lt;/application&amp;gt;
&amp;lt;bindings&amp;gt;
&amp;lt;binding protocol=&amp;quot;https&amp;quot; bindingInformation=&amp;quot;*:44300:*&amp;quot; /&amp;gt;
&amp;lt;/bindings&amp;gt;
&amp;lt;/site&amp;gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;h3&gt;2 - Réservons l&#39;url au niveau du kernel (HTTP.sys)&lt;/h3&gt;&lt;p&gt;Cela se fait via la ligne de commande suivante, a executée dans une console en mode admin.&lt;/p&gt;&lt;blockquote&gt;&lt;br /&gt;
netsh http add urlacl url=https://*:44300/ user=everyone&lt;br /&gt;
&lt;br /&gt;
&lt;/blockquote&gt;&lt;p&gt;Note : pour ceux qui travaillent sur un windows en français il faudra alors taper &lt;/p&gt;&lt;blockquote&gt;&lt;br /&gt;
netsh http add urlacl url=https://*:44300/ user=&quot;tout le monde&quot;&lt;br /&gt;
&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
&lt;h3&gt;3 - Autoriser le trafic au travers du firewall&lt;/h3&gt;&lt;p&gt;De nouveau une commande à exécuter via une console en mode admin :&lt;/p&gt;&lt;blockquote&gt;&lt;br /&gt;
netsh firewall add portopening TCP 44300 IISExpressWeb enable ALL&lt;br /&gt;
&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
&lt;p&gt;Voila, j&#39;espère que cette astuce pourra vous éviter de rester coincé si vous devez exposer un site hebergé sur votre machine de dev&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/1995835899282812420/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/1995835899282812420' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/1995835899282812420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/1995835899282812420'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2014/03/iisexpress-servir-des-pages-vers.html' title='IISExpress : Servir des pages vers l’extérieur.'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-8212132247047623169</id><published>2013-11-17T22:01:00.002+01:00</published><updated>2013-11-17T22:01:53.046+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="AOP"/><category scheme="http://www.blogger.com/atom/ns#" term="Entity Framework"/><category scheme="http://www.blogger.com/atom/ns#" term="EntityFramework.Patterns"/><title type='text'>EntityFramework.Patterns 0.8 est compatible EF 6</title><content type='html'>&lt;p&gt;Ça faisait longtemps que je n&#39;avais pas remis les mains dans ce projet, plus d&#39;un an pour être exact. Le passage à Entity Framework 5 n&#39;avait pas posé de soucis car aucun breaking changes dans l&#39;API n&#39;avait bloqué l&#39;utilisation de la librairie. C&#39;est surement ce qui explique le nombre &quot;plutôt important&quot; (7500) download sur &lt;a href=&quot;https://www.nuget.org/packages/EntityFramework.Patterns/&quot;&gt;nuget gallery&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Mais avec EF 6 c&#39;est une autre histoire, tout un tas de nouvelles fonctionnalités très sympa, mais aussi une api qui a pas mal bougé... ainsi plusieurs utilisateurs sur &lt;a href=&quot;https://efpatterns.codeplex.com/&quot;&gt;codeplex&lt;/a&gt;, m&#39;ont tout naturellement contacté pour me demander de mettre à jour EntityFramework.Patterns.&lt;/p&gt;&lt;p&gt;C&#39;est chose faite, la version 0.8 est désormais disponible via &lt;a href=&quot;https://www.nuget.org/packages/EntityFramework.Patterns/&quot;&gt;nuget&lt;/a&gt; ou sous forme &lt;a href=&quot;https://efpatterns.codeplex.com/releases/view/114986&quot;&gt;binaire&lt;/a&gt; et est compatible avec la dernière version d&#39;EF&lt;/p&gt;&lt;p&gt;Ça signifie que mes chers utilisateurs vont pouvoir profiter des gains de performances apportées par EF 6; Quant au projet sur lequel je travaille actuellement, j&#39;espère bien upgrader EF dès demain... &lt;a href=&quot;http://ryvonnet.wordpress.com/&quot;&gt;Romain&lt;/a&gt;, si tu m&#39;entends :p &lt;/p&gt;&lt;p&gt;Dans un avenir proche, je pense ajouter un bout d&#39;API asynchrone aux repository d&#39;EntityFramework.Patterns.&lt;/p&gt;&lt;p&gt;Bon upgrade de package !!&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/8212132247047623169/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/8212132247047623169' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/8212132247047623169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/8212132247047623169'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2013/11/entityframeworkpatterns-08-est.html' title='EntityFramework.Patterns 0.8 est compatible EF 6'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-5642658490644897665</id><published>2013-10-31T18:18:00.000+01:00</published><updated>2013-10-31T18:41:22.846+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="ETL"/><category scheme="http://www.blogger.com/atom/ns#" term="SSIS"/><category scheme="http://www.blogger.com/atom/ns#" term="TPL.Dataflow"/><title type='text'>SSIS vs TPL.Dataflow</title><content type='html'>&lt;p&gt;Il y a quelques jours je tweetais de joie, après être tombé sur la msdn concernant &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/hh228603(v=vs.110).aspx&quot;&gt;TPL.Dataflow&lt;/a&gt;&lt;br /&gt;
L&#39;API propose un système de pipeline que l&#39;on peut aisément imaginer utiliser dans un process d&#39;ETL.&lt;/p&gt;&lt;p&gt;Ni une ni deux, je m&#39;imagine délaisser SSII lors de mes prochaines alims de base de données et enfin pouvoir unit tester mon ETL.&lt;br /&gt;
L&#39;accueil fait par mes collègues purement BI fut plutôt frileux... n&#39;est ce pas David :)&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3AKlm9CIhNEN1aUFJd2X0gdXgomuELfI4AdHj6PzIWR7TggZ88Rx7iZtJi2D172irmp6daATWMEgf2Xo0DGJD7M5mN4QVq4EogJdTe7_OhlUiJVibQwwhNcU6kf-5OG12nECm99Cavsb6/s1600/djoub.png&quot; /&gt;&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Au rayon des réponses constructives, &lt;a href=&quot;http://fbro.wordpress.com&quot;&gt;Fred Brossard&lt;/a&gt;, me fait revenir très vite sur terre, en demandant à voir les perfs du framework.&lt;/p&gt;&lt;p&gt;C&#39;est ce que je me propose de présenter ici avec un exemple simple.&lt;br /&gt;
L&#39;idée est d&#39;importer le snapshot de &lt;a href=&quot;http://meta.stackoverflow.com/questions/198915/is-there-a-direct-download-link-with-a-raw-data-dump-of-stack-overflow-not-a-t&quot;&gt;septembre des posts de stackoverflow&lt;/a&gt;; d&#39;abord avec notre bon vieux SSIS puis avec TPL.Dataflow.&lt;/p&gt;&lt;p&gt;En entrée on a donc un bon gros fichier XML de 170MO correspondant aux nouveaux posts du mois.&lt;/p&gt;&lt;p&gt;Commençons par SSIS, rien de sorcier, une XML source qui se déverse directement dans une SQL Destination pointant vers ma jolie table.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOlH4Ytp4Fu19fHXCsRpI4NASMf_Yb2qpMuek8EK7SvwCiWe_KFQXiRViCl29wpCfqjr5CFpTKVRyZ1O0Y7OYC9kiko4iAMf2W4VL_IdHRfZPkOB2Lbwgv9e_AoqNB48wItHhy3s8SFOfA/s1600/ssis.png&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Ce qui nous donne env. 150K lignes intégrées en env. 20 sec&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV72j6VHNmHKpK13Cule3UmsrCqyWK1Bc56Zu0K4Km2ijSF897bsADdLvR3oUdYmrwZG8puEzjdDhrQ0AtAUDqdmEP0TEZ8qM_e24xHi5r2uMq14HDQ9x5NS5cZRXdTYvFPYgcuSYsmYhy/s1600/ssis_executed.png&quot; /&gt;&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpHJsIyTyHO2mdqzWWj270seZgjH8Z-Qwq74mB7L9FtT-1l9TL9PURJijt3s1tr6Jjt0nzn1bzeAk1og65Sb7QYoPs2RoO6oytl9Q5IMaFLHsD9T0FeDVmoXKjdqJHoPBn6I9sPegQ8FUB/s1600/ssis_elapsed.png&quot; /&gt;&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Ok, passons à la version C#. Ce que je vous livre ici est une version non optimisée et naive d&#39;un algo d&#39;import avec TPL.Dataflow.&lt;br /&gt;
&lt;br /&gt;
Commencons par créer nos taches :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;// XML datasource 
            var inputBlock = new BufferBlock&amp;lt;XDocument&amp;gt;();

            // Split xml, one for each &amp;lt;row&amp;gt; element
            var xDocumentToXmlRow = new TransformManyBlock&amp;lt;XDocument, XElement&amp;gt;(
                x =&amp;gt; x.Root.DescendantNodes().OfType&amp;lt;XElement&amp;gt;());

            // Convert xml &amp;lt;row&amp;gt; element to a Post object.
            var xmlRowToObjectBlock = new TransformBlock&amp;lt;XElement, Post&amp;gt;(
                x =&amp;gt; x.FromXElement&amp;lt;Post&amp;gt;(),
                new ExecutionDataflowBlockOptions {MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded});

            // a buffer of 10000 elements
            var batch = new BatchBlock&amp;lt;Post&amp;gt;(10000);

            // SQL destination, using bulk insert.
            var sqlBulk = new ActionBlock&amp;lt;Post[]&amp;gt;(x =&amp;gt;
                {
                    using (SqlBulkCopy sbc = new SqlBulkCopy(&amp;quot;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=Stackoverflow;Data Source=(local)&amp;quot;, SqlBulkCopyOptions.TableLock))
                    {
                        sbc.DestinationTableName = &amp;quot;Posts&amp;quot;;

                        // Number of records to be processed in one go
                        sbc.BatchSize = 10000;

                        // commit to the server
                        sbc.WriteToServer(x.ToList().ToDataTable());
                        sbc.Close();
                    }
                },
            new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded });
&lt;/pre&gt;&lt;br /&gt;
Il nous faut maintenant ordonnancer ces taches, comme nous le faisons dans SSIS en reliant les taches entre elles.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;using (inputBlock.LinkTo(xDocumentToXmlRow))
            using (xDocumentToXmlRow.LinkTo(xmlRowToObjectBlock))
            using (xmlRowToObjectBlock.LinkTo(batch))
            using (batch.LinkTo(sqlBulk))
            {
                inputBlock.Completion.ContinueWith(t =&amp;gt; xDocumentToXmlRow.Complete());
                xDocumentToXmlRow.Completion.ContinueWith(t =&amp;gt; xmlRowToObjectBlock.Complete());
                xmlRowToObjectBlock.Completion.ContinueWith(t =&amp;gt; batch.Complete());
                batch.Completion.ContinueWith(t =&amp;gt; sqlBulk.Complete());

                var inputfile = XDocument.Load(@&amp;quot;C:\!PoC\Stackoverflow\Sourcefiles\Posts.xml&amp;quot;);
                inputBlock.Post(inputfile);

                inputBlock.Complete();
                sqlBulk.Completion.Wait();
            }

&lt;/pre&gt;&lt;br /&gt;
Aller, sans plus attendre, voici le résultat de l’exécution :&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWJpm649KF6Cyx36Ix802pbsJ0K5w1RJuM4aWH5EZL3JB7eQ21lECR8WYuavT-eA1ei7dM_6o5rNyVKDYgjCeUrieztDSOheMJ4aj2ufIncqjaNerrOSZ_MFH0Zt6W2e9T2zfSoi1KT3Nv/s1600/TPL.Dataflow_executed.png&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Je suis sur que vous êtes aussi étonnés que moi... TPL est plus rapide (de quelques 15%) par rapport à SSIS dans ce cas simple.&lt;br /&gt;
Pour être tout à fait franc, je ne m&#39;y attendais pas du tout. Je pensais qu&#39;il y aurait vraisemblablement une 20 aine de % d&#39;écart, mais en faveur de SSIS.&lt;br /&gt;
&lt;br /&gt;
Bien que cet exemple simplissime ne puisse pas permettre de généraliser, TPL.Dataflow semble apporter des performances suffisantes, si non meilleures qu&#39;SSIS; &lt;br /&gt;
mais surtout, cet API va nous permettre d’écrire des tests unitaires sur nos jobs d&#39;intégration. C&#39;est ce que je vous présenterai dans un prochain article.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;Et vous, avez vous déjà utilisé TPL.Dataflow? Pourriez-vous l&#39;utiliser dans vos projets? A la lumière de ce post, que pensez vous de ces performances?&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/5642658490644897665/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/5642658490644897665' title='9 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/5642658490644897665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/5642658490644897665'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2013/10/ssis-vs-tpldataflow.html' title='SSIS vs TPL.Dataflow'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3AKlm9CIhNEN1aUFJd2X0gdXgomuELfI4AdHj6PzIWR7TggZ88Rx7iZtJi2D172irmp6daATWMEgf2Xo0DGJD7M5mN4QVq4EogJdTe7_OhlUiJVibQwwhNcU6kf-5OG12nECm99Cavsb6/s72-c/djoub.png" height="72" width="72"/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-880692374344894893</id><published>2012-09-05T16:58:00.000+02:00</published><updated>2012-09-05T16:58:22.387+02:00</updated><title type='text'>Entity Framework Cache</title><content type='html'>&lt;p&gt;Malgré la version 5 d&#39;Entity Framework sortie il y a peu de temps, beaucoup déplorent l’absence d’un mécanisme de cache implémenté dans le Framework.&lt;/p&gt;&lt;p&gt;Pour ceux qui ont un peu creusé le sujet, il y a bien les &lt;a href=&quot;http://code.msdn.microsoft.com/EFProviderWrappers-c0b88f32&quot;&gt;&quot;Tracing and Caching Provider Wrappers for Entity Framework&quot;&lt;/a&gt; parus début 2011. Cependant, ce n’est pas la solution ultime ; à l’époque Code First n’existait pas ce qui rend cette librairie incompatible avec Code First.&lt;p&gt;&lt;p&gt;Pour être tout à fait franc, le code des wrappers est disponible, je pense donc qu’en bidouillant un peu, ça doit être possible d’adapter le code pour Code First.&lt;/p&gt;&lt;p&gt;A l’occasion de la sortie d’&lt;a href=&quot;http://efpatterns.codeplex.com/&quot;&gt;EntityFramework.Patterns 0.7&lt;/a&gt;, je vous propose de voir ensemble comme utiliser les fonctionnalités de cache fournies par cette librairie.&lt;p&gt;&lt;p&gt;Soit le contexte suivant :&lt;/p&gt;&lt;pre class=&quot;brush:csharp&quot;&gt;    public class EfContext : DbContext
    {
        public DbSet&amp;lt;User&amp;gt; Users { get; set; }
 
        public EfContext()
        {
            Database.SetInitializer(new DropCreateDatabaseIfModelChanges&amp;lt;EfContext&amp;gt;());
        }
    }
&lt;/pre&gt;&lt;p&gt;Et l’entité User tel que :&lt;/p&gt;&lt;pre class=&quot;brush:csharp&quot;&gt;    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual ICollection&amp;lt;UserRole&amp;gt; UserRoles { get; set; }  
    }
&lt;/pre&gt;&lt;p&gt;On peut facilement utiliser le cache en mémoire (il est possible d’en utiliser d’autre) fournit par EntityFramework.Patterns pour mettre en cache une collection de User.&lt;/p&gt;&lt;pre class=&quot;brush:csharp&quot;&gt;            // On charge tous les users et on les stocke dans le cache.
            using (EfContext ctx = new EfContext())
            {
                IEnumerable&amp;lt;User&amp;gt; usrs = ctx.Users.ToCache();
            }
 
            // autre code...
 
            // Cette fois ci, on r&amp;#233;cup&amp;#232;re les users &amp;#224; partir du cache.
            using (EfContext ctx = new EfContext())
            {
                IEnumerable&amp;lt;User&amp;gt; usrs = ctx.Users.FromCache();
            }
&lt;/pre&gt;&lt;p&gt;Simple non ?&lt;/p&gt;&lt;p&gt;Pour ceux qui préfèrent éviter l’accès direct au context d’Entity Framework et qui isolent leur accès à la base dans des repository, EntityFramework.Patterns vous facilitera la tâche également.&lt;/p&gt;&lt;p&gt;Il vous suffit de wrapper votre Repository&lt;T&gt; avec le CacheableRepository qui vous apporte les fonctionnalités de cache.&lt;/p&gt;&lt;pre class=&quot;brush:csharp&quot;&gt;            using (EfContext ctx = new EfContext())
            {
                DbContextAdapter adpt = new DbContextAdapter(ctx);
 
                IRepository&amp;lt;User&amp;gt; repo =
                    new CacheableRepository&amp;lt;User&amp;gt;(
                        new Repository&amp;lt;User&amp;gt;(adpt)
                        );
 
                // On charge tous les utilisateurs.
                // Par defaut le CacheableRepository va mettre en cache le resultset
                // en provenance de la base et le r&amp;#233;utilisera le cas &amp;#233;ch&amp;#233;ant plus tard.
                IEnumerable&amp;lt;User&amp;gt; usrs = repo.GetAll();
 
                // autre code.
 
                // Cette fois-ci, les users proviennent du cache. Il n&amp;#39;y a pas d&amp;#39;acc&amp;#232;s en base.
                usrs = repo.GetAll();
            }
&lt;/pre&gt;&lt;p&gt;Comme vous le voyez le CacheableRepository fait appel au cache pour vous ; et vous permet de ne pas avoir à gérer la suppression d’éléments dans le cache lorsque les éléments ont étés modifiés/supprimés/insérés etc… &lt;/p&gt;&lt;p&gt;Je reviendrais ultérieurement dans un prochain post sur les mécanismes avancés du cache proposés par EntityFramework.Patterns.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/880692374344894893/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/880692374344894893' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/880692374344894893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/880692374344894893'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2012/09/entity-framework-cache.html' title='Entity Framework Cache'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-4921929042336737796</id><published>2011-10-14T13:58:00.000+02:00</published><updated>2011-10-17T15:47:00.765+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><title type='text'>Implémenter une sécurité à base de rôles avec Windows Authentication &amp; SQL Server</title><content type='html'>&lt;br /&gt;
Ces derniers jours j&#39;ai été confronté à une problématique très intéressante; j&#39;aimerais la partager avec vous aujourd&#39;hui et vous soumettre la solution que j&#39;ai imaginé pour y répondre.&lt;br /&gt;
&lt;br /&gt;
Mon client souhaitait restreindre l&#39;accès à son site/application intranet aux seuls membres d&#39;un groupe Windows prédéfini. &lt;br /&gt;
Le hic est que le site fonctionne avec des rôles définis en base de données, laissant ainsi libre champs aux admins de l&#39;appli d&#39;attribuer et révoquer des droits aux autres utilisateurs. Évidement, il était hors de question de devoir passer par l&#39;IT pour changer les droits des utilisateurs à l&#39;avenir.&lt;br /&gt;
&lt;br /&gt;
Si l&#39;on transpose la demande en termes techniques, on a besoin du &lt;a href=&quot;http://msdn.microsoft.com/fr-fr/library/system.web.security.windowstokenroleprovider.aspx&quot;&gt;WindowsTokenRoleProvider&lt;/a&gt; pour autoriser l&#39;accès au site et pour tout le reste il faut se reposer sur un &lt;a href=&quot;http://msdn.microsoft.com/fr-fr/library/system.web.security.sqlroleprovider.aspx&quot;&gt;SqlRoleProvider&lt;/a&gt;.&lt;br /&gt;
Comme vous le savez, ce genre de configuration n&#39;est pas prise en charge par le modèle de provider tel que nous le connaissons jusqu&#39;à présent.&lt;br /&gt;
&lt;br /&gt;
En cherchant sur la toile si ce genre de situation à déjà été traitée (ne réinventons pas la roue carrée), vous tomberez très certainement sur &lt;a href=&quot;http://weblogs.asp.net/scottgu/pages/Recipe_3A00_-Implementing-Role_2D00_Based-Security-with-ASP.NET-2.0-using-Windows-Authentication-and-SQL-Server.aspx&quot;&gt;un article de Scott Guthrie&lt;/a&gt; qui traite d&#39;un problème très similaire. Dans l&#39;article &lt;a href=&quot;http://weblogs.asp.net/scottgu/&quot;&gt;l&#39;homme à la chemise rouge&lt;/a&gt; nous montre comment, sans code, utiliser les rôles issus de la base de données et n&#39;autoriser l&#39;accès au site &lt;u&gt;qu&#39;aux utilisateurs identifiés&lt;/u&gt;. Et c&#39;est bien sur ce dernier point que nos problématiques diffèrent car dans mon cas, il ne suffit pas d&#39;être identifié sur le domaine, mais il faut aussi faire partie d&#39;un groupe d&#39;utilisateurs.&lt;br /&gt;
&lt;br /&gt;
J&#39;ai donc remonté mes manches, et quitte à écrire du code j&#39;ai tenté de trouver une solution générique permettant de combiner des RoleProvider.&lt;br /&gt;
&lt;br /&gt;
Commençons par définir un RoleProviderDecorator qui comme son nom l&#39;indique suit le pattern &lt;a href=&quot;http://en.wikipedia.org/wiki/Decorator_pattern&quot;&gt;Decorator&lt;/a&gt;.&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;public class RoleProviderDecorator&amp;lt;TSurrogateRoleProvider&amp;gt; : RoleProvider
        where TSurrogateRoleProvider : RoleProvider, new()
    {

        protected TSurrogateRoleProvider _surrogate;

        public override void Initialize(string name, NameValueCollection config)
        {
            if (config == null)
                throw new ArgumentNullException(&amp;quot;config&amp;quot;);

            base.Initialize(name, config);

            _surrogate = new TSurrogateRoleProvider();

            InitializeInnerProvider(_surrogate, name, config);
        }

        protected virtual void InitializeInnerProvider(RoleProvider innerProvider, string name, NameValueCollection config)
        {
            innerProvider.Initialize(name, config);
        }
        
        public override bool IsUserInRole(string username, string roleName)
        {
            return _surrogate.IsUserInRole(username, roleName);
        }
        
        public override string[] GetRolesForUser(string username)
        {
            return _surrogate.GetRolesForUser(username).ToArray();
        }
        
        public override void CreateRole(string roleName)
        {
            _surrogate.CreateRole(roleName);
        }
        
        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            return _surrogate.DeleteRole(roleName, throwOnPopulatedRole);
        }
        
        public override bool RoleExists(string roleName)
        {
            return _surrogate.RoleExists(roleName);
        }
        
        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            _surrogate.AddUsersToRoles(usernames, roleNames);
        }
        
        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            _surrogate.RemoveUsersFromRoles(usernames, roleNames);
        }
        
        public override string[] GetUsersInRole(string roleName)
        {
            return _surrogate.GetUsersInRole(roleName).ToArray();
        }
        
        public override string[] GetAllRoles()
        {
            return _surrogate.GetAllRoles().ToArray();
        }
        
        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            return
                _surrogate.FindUsersInRole(roleName, usernameToMatch).ToArray();
        }
        
        public override string ApplicationName
        {
            get { return _surrogate.ApplicationName; }
            set { _surrogate.ApplicationName = value; }
        }
    }
&lt;/pre&gt;&lt;br /&gt;
L&#39;idée du décorateur, vous l&#39;aurez compris, est de déléguer l’exécution des méthodes au vrai RoleProvider passé sous forme de &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms379564%28v=vs.80%29.aspx&quot;&gt;Generic&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Maintenant définissons un RoleProvider qui se charge d&#39;utiliser de manière sous-jacente deux RoleProvider :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;public abstract class UnionRoleProvider&amp;lt;TPrimaryRoleProvider, TSecondaryRoleProvider&amp;gt; : RoleProviderDecorator&amp;lt;TPrimaryRoleProvider&amp;gt;
        where TPrimaryRoleProvider : RoleProvider, new()
        where TSecondaryRoleProvider : RoleProvider, new()
    {
        private TSecondaryRoleProvider _secondSurrogate;

        public override void Initialize(string name, NameValueCollection config)
        {
            if (config == null)
                throw new ArgumentNullException(&amp;quot;config&amp;quot;);

            base.Initialize(name, config);

            _secondSurrogate = new TSecondaryRoleProvider();
            InitializeInnerProvider(_secondSurrogate, name, config);
        }

        public override bool IsUserInRole(string username, string roleName)
        {
            return _surrogate.IsUserInRole(username, roleName) || _secondSurrogate.IsUserInRole(username, roleName);
        }

        public override string[] GetRolesForUser(string username)
        {
            return _surrogate.GetRolesForUser(username).Union(_secondSurrogate.GetRolesForUser(username)).ToArray();
        }

        public override void CreateRole(string roleName)
        {
            _surrogate.CreateRole(roleName);
            _secondSurrogate.CreateRole(roleName);
        }

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            return _surrogate.DeleteRole(roleName, throwOnPopulatedRole) &amp;amp;&amp;amp; _surrogate.DeleteRole(roleName, throwOnPopulatedRole);
        }

        public override bool RoleExists(string roleName)
        {
            return _surrogate.RoleExists(roleName) || _secondSurrogate.RoleExists(roleName);
        }

        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            _surrogate.AddUsersToRoles(usernames, roleNames);
            _secondSurrogate.AddUsersToRoles(usernames, roleNames);
        }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            _surrogate.RemoveUsersFromRoles(usernames, roleNames);
            _secondSurrogate.RemoveUsersFromRoles(usernames, roleNames);
        }

        public override string[] GetUsersInRole(string roleName)
        {
            return _surrogate.GetUsersInRole(roleName).Union(_secondSurrogate.GetUsersInRole(roleName)).ToArray();
        }

        public override string[] GetAllRoles()
        {
            return _surrogate.GetAllRoles().Union(_secondSurrogate.GetAllRoles()).ToArray();
        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            return
                _surrogate.FindUsersInRole(roleName, usernameToMatch)
                    .Union(_secondSurrogate.FindUsersInRole(roleName, usernameToMatch))
                    .ToArray();
        }
    }
&lt;/pre&gt;&lt;br /&gt;
Dans mon cas, seul un des deux RoleProvider doit pouvoir écrire dans son médium de stockage. &lt;br /&gt;
L&#39;autre doit être en lecture seule. Pour ce faire, j&#39;introduis un ReadOnlyRoleProvider : &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;public class ReadOnlyRoleProvider&amp;lt;TSurrogateRoleProvider&amp;gt; : RoleProviderDecorator&amp;lt;TSurrogateRoleProvider&amp;gt;
        where TSurrogateRoleProvider : RoleProvider, new()
    {

        public override void CreateRole(string roleName){}

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            return true;
        }

        public override void AddUsersToRoles(string[] usernames, string[] roleNames){}

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames){}
&lt;/pre&gt;&lt;br /&gt;
Ça y est on a fait 90% du boulot.&lt;br /&gt;
&lt;br /&gt;
Dans le fichier web.config on veut écrire ceci : &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:xml&quot;&gt;&amp;lt;roleManager enabled=&amp;quot;true&amp;quot; defaultProvider=&amp;quot;MyRoleProvider&amp;quot;&amp;gt;
      &amp;lt;providers&amp;gt;
        &amp;lt;clear/&amp;gt;
        &amp;lt;add name=&amp;quot;MyRoleProvider &amp;quot; type=&amp;quot;Providers.MyRoleProvider &amp;quot; connectionStringName=&amp;quot;cnx&amp;quot; applicationName=&amp;quot;MyApp&amp;quot; /&amp;gt;
      &amp;lt;/providers&amp;gt;
    &amp;lt;/roleManager&amp;gt;
&lt;/pre&gt;&lt;br /&gt;
Étant donné que l&#39;on ne peut pas utiliser de classe générique dans la config, on va simplement en spécialiser une :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;public class MyRoleProvider : UnionRoleProvider&amp;lt;SqlRoleProvider, SilentWindowsTokenRoleProvider&amp;lt;WindowsTokenRoleProvider&amp;gt;&amp;gt;
    {

        protected override void InitializeInnerProvider(RoleProvider innerProvider, string name, NameValueCollection config)
        {
            NameValueCollection cfg = config;
            if (innerProvider is ReadOnlyRoleProvider&amp;lt;WindowsTokenRoleProvider&amp;gt;)
            {
                cfg = new NameValueCollection(config);
                cfg.Remove(&amp;quot;connectionStringName&amp;quot;);
            }
            
            base.InitializeInnerProvider(innerProvider, name, cfg);
        }
    }
&lt;/pre&gt;&lt;br /&gt;
Ouf, 99% du boulot. Vous pouvez maintenant exécuter et ça va fonctionner... jusqu&#39;à ce que vous utilisiez une des méthodes suivantes : &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;GetUsersInRole&lt;/li&gt;
&lt;li&gt;GetAllRoles&lt;/li&gt;
&lt;li&gt;FindUsersInRole&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Tout simplement parce que le  &lt;a href=&quot;http://msdn.microsoft.com/fr-fr/library/system.web.security.windowstokenroleprovider.aspx&quot;&gt;WindowsTokenRoleProvider&lt;/a&gt; ne supporte pas ces opérations.&lt;br /&gt;
Ok, voici le tout dernier % à réaliser : &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;public class SilentWindowsTokenRoleProvider&amp;lt;TSurrogateRoleProvider&amp;gt; : ReadOnlyRoleProvider&amp;lt;TSurrogateRoleProvider&amp;gt;
        where TSurrogateRoleProvider : RoleProvider, new()
    {

        public override string[] GetUsersInRole(string roleName)
        {
            return new string[]{};
        }

        public override string[] GetAllRoles()
        {
            return new string[]{};
        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            return new string[]{};
        }
    }
&lt;/pre&gt;&lt;br /&gt;
Voila 100% de la solution; beaucoup de code aujourd&#39;hui, j&#39;espère que ça ne vous a pas trop démotivé.&lt;br /&gt;
&lt;br /&gt;
Si vous avez une solution autre, ou contestez mon approche n&#39;hésitez pas à laisser un commentaire.&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/4921929042336737796/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/4921929042336737796' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/4921929042336737796'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/4921929042336737796'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2011/10/implementer-une-securite-base-de-roles.html' title='Implémenter une sécurité à base de rôles avec Windows Authentication &amp; SQL Server'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-5058619291898102502</id><published>2011-10-07T16:55:00.001+02:00</published><updated>2011-10-17T15:57:45.962+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Afterthought"/><category scheme="http://www.blogger.com/atom/ns#" term="AOP"/><category scheme="http://www.blogger.com/atom/ns#" term="Entity Framework"/><category scheme="http://www.blogger.com/atom/ns#" term="EntityFramework.Patterns"/><title type='text'>Entity Framework et AOP</title><content type='html'>&lt;p&gt;Cela fait des mois que je repousse la publication d&#39;un post sur l&#39;&lt;a href=&quot;http://en.wikipedia.org/wiki/Aspect-oriented_programming&quot;&gt;AOP&lt;/a&gt;, car je ne voulais pas vous resservir le sempiternel exemple de mise en place d&#39;une gestion de log applicatif simplifiée. &lt;br /&gt;
Si vous voulez vous rafraichir les idées sur le sujet je vous conseille de jeter un œil sur l&#39;article d&#39;&lt;a href=&quot;http://ayende.com/blog/3474/logging-the-aop-way&quot;&gt;Ayende Rahien sur le sujet&lt;/a&gt;&lt;br /&gt;
&lt;/p&gt;Avec le framework .NET, il existe au moins 6 façons différentes d&#39;ajouter un brin d&#39;AOP dans vos programmes; &lt;br /&gt;
Pour mémoire il s&#39;agit de : &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Remoting Proxies&lt;/li&gt;
&lt;li&gt;Dériver votre classe de ContextBoundObject&lt;/li&gt;
&lt;li&gt;Passer par un dynamique proxy ( ex : Castle Dynamic Proxy)&lt;/li&gt;
&lt;li&gt;Utiliser l&#39;API de profiling de .NET&lt;/li&gt;
&lt;li&gt;Injection d&#39;IL après compilation&lt;/li&gt;
&lt;li&gt;Injection d&#39;IL au runtime&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Dans cet article on s&#39;intéressera particulièrement a l&#39;injection post compilation, tout simplement car c&#39;est la plus performante (le code lié à l&#39;aspect est directement inscrit dans l&#39;assembly finale et rien ne le distingue du reste du code) et aussi car c&#39;est la façon la plus sexy a mon gout de faire de l&#39;AOP (c&#39;est une raison comme une autre, non?).&lt;br /&gt;
&lt;br /&gt;
Bon revenons à nos moutons.&lt;br /&gt;
&lt;br /&gt;
Sur presque tous les projets sur lesquels je suis intervenu ces dernières années, lorsqu&#39;on modélise les entités qui devront être persistées en base, on leur adjoint au moins quatre propriétés :&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Created By (string)&lt;/li&gt;
&lt;li&gt;Created (datetime)&lt;/li&gt;
&lt;li&gt;Last Updated By (string)&lt;/li&gt;
&lt;li&gt;Last Updated (datetime)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
J&#39;ai pour habitude de nommer cette construction, une entité &quot;Auditable&quot;, ce qui se traduit en code par l&#39;interface suivante : &lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;public interface IAuditable
    {
        string CreatedBy { get; set; }
        DateTime Created { get; set; }
        string UpdatedBy { get; set; }
        DateTime? Updated { get; set; }
    }
&lt;/pre&gt;&lt;br /&gt;
Vous l&#39;aurez compris, l&#39;idée ici, est de stocker la date et l&#39;utilisateur ayant créé ou modifié l&#39;entité en question et ceci a chaque accès base. &lt;br /&gt;
Je vous laisse imaginer le travail rébarbatif que cela peut vite devenir si l&#39;on doit tout gérer à la main et si notre modèle est composé de dizaines voire de centaines d&#39;entités.&lt;br /&gt;
&lt;br /&gt;
Je vous propose donc une idée afin de se faciliter la vie grâce à l&#39;AOP. &lt;br /&gt;
Il est à noter que bien que l&#39;exemple ci-dessous s’appuie sur Entity Framework, le mécanisme est très certainement transposable (avec adaptation) aux autres ORM.&lt;br /&gt;
&lt;br /&gt;
On commence par utiliser Entity Framework Code First, et on ajoute notre framework AOP préféré&lt;br /&gt;
&lt;pre class=&quot;brush:powershell&quot;&gt;Install-Package EntityFramework
Install-Package Afterthought
&lt;/pre&gt;&lt;br /&gt;
&lt;blockquote&gt;En attendant qu&#39;un de mes patch soit accepté et intégré à &lt;a href=&quot;https://github.com/vc3/Afterthought&quot;&gt;Afterthought&lt;/a&gt;, il vous faudra remplacer la dll d&#39;Afterthought par la mienne disponible &lt;a href=&quot;http://fabrice.michellonet.free.fr/MyMemoryLeaks/Posts/44/afterthought.zip&quot;&gt;ici&lt;/a&gt;.&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
Nuget a rajouté quelques dll et références dans votre projet et modifié également le post build event de votre projet; &lt;br /&gt;
Désormais à chaque compilation, Afterthought scannera les assemblies à la recherche de taches d&#39;injection d&#39;IL à effectuer.&lt;br /&gt;
&lt;br /&gt;
Voyons comment demander à Afterthought d&#39;injecter l&#39;interface IAuditable sur nos entités.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;public class AuditableAmender&amp;lt;T&amp;gt; : Amendment&amp;lt;T, T&amp;gt;
    {

        public AuditableAmender()
        {
            Properties.Add&amp;lt;string&amp;gt;(&amp;quot;CreatedBy&amp;quot;);
            Properties.Add&amp;lt;DateTime&amp;gt;(&amp;quot;Created&amp;quot;);
            Properties.Add&amp;lt;string&amp;gt;(&amp;quot;UpdatedBy&amp;quot;);
            Properties.Add&amp;lt;DateTime?&amp;gt;(&amp;quot;Updated&amp;quot;);

            Implement&amp;lt;IAuditable&amp;gt;();
        }
    }
&lt;/pre&gt;&lt;br /&gt;
Le code me semble assez clair sans avoir a revenir longuement dessus; On demande simplement à Afterthought d&#39;injecter les propriétés nécessaires à l&#39;implémentation de l&#39;interface IAuditable.&lt;br /&gt;
&lt;br /&gt;
Bien créons un attribut de marquage, que nous placerons sur nos entités :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;[AttributeUsage(AttributeTargets.Class)]
    public class AuditableAttribute : Attribute { }
&lt;/pre&gt;&lt;br /&gt;
il nous reste encore deux tâches à réaliser; &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Préciser les assemblies à introspecter&lt;/li&gt;
&lt;li&gt;Permettre à Afterthought de découvrir les classes qui doivent être modifiées et surtout comment.&lt;/li&gt;
&lt;/ul&gt;Cela se fait dans une même classe : &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;[AttributeUsage(AttributeTargets.Assembly)]
    public class AmendAttribute : Attribute, IAmendmentAttribute
    {
        IEnumerable&amp;lt;ITypeAmendment&amp;gt; IAmendmentAttribute.GetAmendments(Type target)
        {
            if (target.GetCustomAttributes(typeof(AuditableAttribute), true).Length &amp;gt; 0)
            {
                ConstructorInfo constructorInfo = typeof(AuditableAmender&amp;lt;&amp;gt;).MakeGenericType(target).GetConstructor(Type.EmptyTypes);
                if (constructorInfo != null)
                    yield return (ITypeAmendment)constructorInfo.Invoke(new object[0]);
            }
        }
    }
&lt;/pre&gt;En clair, pour chaque classe qui implémente IAuditable, on va faire appel à la classe AuditableAmender (créée précédemment) pour modifier la classe.&lt;br /&gt;
En appliquant cet attribut sur l&#39;assembly qui contient vos entités, Afterthought effectuera son travail d&#39;injection.&lt;br /&gt;
&lt;br /&gt;
Désormais si l&#39;on applique l&#39;attribut Auditable sur une de nos entités comme suit :&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;[Auditable]
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class Context : DbContext
    {
        public virtual DbSet&amp;lt;Product&amp;gt; Products { get; set; }

        public Context()
        {
            Database.SetInitializer(new DropCreateDatabaseIfModelChanges&amp;lt;Context&amp;gt;());
        }
    }
&lt;/pre&gt;&lt;br /&gt;
Ce qui produit bien en base la table suivante : &lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;http://fabrice.michellonet.free.fr/MyMemoryLeaks/Posts/44/EF_Table.png&quot; alt=&quot;table&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
et dans l&#39;assembly finale (vu avec Reflector)&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;http://fabrice.michellonet.free.fr/MyMemoryLeaks/Posts/44/Asm.png&quot; alt=&quot;assembly&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
Évidemment, en généralisant ce principe il est possible de facilement faire évoluer votre modèle sans avoir à travailler parfois de manière répétitive.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Vous retrouverez cette fonctionnalité (il vous suffit de marquer votre entité avec l&#39;attribut) dans la librairie &lt;a href=&quot;http://efpatterns.codeplex.com/&quot;&gt;EntityFramework.Patterns&lt;/a&gt; que je maintiens et disponible via &lt;a href=&quot;http://nuget.org/List/Packages/EntityFramework.Patterns&quot;&gt;nuget&lt;/a&gt;.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Que pensez-vous de cette technique?&lt;br /&gt;
Utilisez-vous un autre framework (&lt;a href=&quot;http://www.sharpcrafters.com/&quot;&gt;Postsharp&lt;/a&gt;) pour réaliser ce genre de tâche?&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/5058619291898102502/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/5058619291898102502' title='4 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/5058619291898102502'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/5058619291898102502'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2011/10/entity-framework-et-aop.html' title='Entity Framework et AOP'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-7833601605957993703</id><published>2011-09-26T23:21:00.000+02:00</published><updated>2011-09-26T23:21:31.607+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET MVC"/><category scheme="http://www.blogger.com/atom/ns#" term="Javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="SignalR"/><title type='text'>Live charting avec SignalR</title><content type='html'>&lt;p&gt;&lt;a href=&quot;https://github.com/SignalR&quot;&gt;SignalR&lt;/a&gt; is awesome ! Oui il va falloir vous habituer à entendre dire que cette librairie est un petit bijou.&lt;/p&gt;&lt;br /&gt;
&lt;img alt=&quot;tweet signalr&quot; src=&quot;http://fabrice.michellonet.free.fr/MyMemoryLeaks/Posts/43/SignalR_awesome.png&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Mais qu&#39;est-ce qu&#39;elle a de si bien cette librairie SignalR ?&lt;/b&gt;&lt;/p&gt;SignalR fournit une couche d&#39;abstraction au-dessus des &lt;a href=&quot;http://en.wikipedia.org/wiki/WebSocket&quot;&gt;WebSocket&lt;/a&gt; et des &lt;a href=&quot;http://en.wikipedia.org/wiki/Long_polling#Long_polling&quot;&gt;long polling connections&lt;/a&gt; pour les développeurs .NET et fonctionne sous IIS sans avoir à installer un autre service à côté.&lt;br /&gt;
&lt;br /&gt;
Jusqu&#39;alors il existait bien des solutions commerciales de ces technos dans l&#39;écosystème .NET mais aucune n&#39;avait vraiment convaincu, souvent par manque d&#39;intégration forte entre le client et le serveur; rendant la communication entre les deux fastidieuse.&lt;br /&gt;
Avec SignalR c&#39;est tout le contraire, le code serveur et le code client ne semble faire qu&#39;un. Les lignes de code glissent du serveur vers le navigateur, sans aucune lourdeur. C&#39;est &lt;b&gt;SIMPLE&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Comme d&#39;hab, rien de mieux qu&#39;un petit bout de code pour démontrer ça.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Bon, si vous avez lu le titre vous avez une petite idée de ce que l&#39;on va coder...&lt;br /&gt;
&lt;br /&gt;
Coté composants techniques, évidement SignalR pour la communication client/serveur et &lt;a href=&quot;http://www.highcharts.com/&quot;&gt;Highchart&lt;/a&gt; coté client pour dessiner le chart.&lt;br /&gt;
&lt;br /&gt;
Après avoir créé un nouveau projet WebForm ou MVC ajoutez le package SignalR via &lt;a href=&quot;http://nuget.org/&quot;&gt;nuget&lt;/a&gt;.&lt;br /&gt;
Intéressons-nous au code javascript. (&lt;i&gt;A noter que le code lié à la configuration du chart à été omis a des fins de clarté.&lt;/i&gt;)&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:js&quot;&gt;$(function () {
     var stockExchangeServer = $.connection.stockExchange;

    stockExchangeServer.drawShareValue = function (id, content) {

        if (id != this.Id) {
            return;
        }

        // set up the updating of the chart.
        var series = chart.series[0];
        var x = new Date(parseInt(content[0].Date.substr(6))).getTime(),
                y = content[0].Price;

        series.addPoint([x, y], true, true);
    };

    $.connection.hub.start(function () {
        stockExchangeServer.connect();
            .done(function (success) {
                if (success === false) {
                    console.log(&quot;:(&quot;);
                }
                console.log(&quot;connected&quot;);
            });
    });
});
&lt;/pre&gt;&lt;br /&gt;
Pour initier la communication avec le serveur, il suffit comme vous pouvez le voir d&#39;utiliser la méthode &lt;code&gt;$.connection.hub.start()&lt;/code&gt;; &lt;br /&gt;
On se contente alors de faire appel à la méthode &lt;code&gt;connect&lt;/code&gt;; nous implémenterons cette dernière côté serveur.... oui vous avez bien lu, côté serveur.&lt;br /&gt;
&lt;br /&gt;
Remarquez également la définition de la méthode &lt;code&gt;drawShareValue()&lt;/code&gt; qui se charge de dessiner un nouveau point dans le chart, nous ferons appel à elle dans le code serveur.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Côté serveur, nous allons définir un hub, la classe de base qui abstrait la communication client/serveur dans l&#39;api SignalR.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;public class StockExchange : Hub
    {
        private Timer _timer;

        private double _fowlerPrice = 10.2;

        private double VaryPrice()
        {
            Random rnd = new Random();
            _fowlerPrice = _fowlerPrice + (rnd.Next(-1, 2) * rnd.NextDouble());
            return _fowlerPrice;
        }

        public bool Connect()
        {
            // Set unique id for client.
            Caller.Id = Context.ClientId;

            _timer = new Timer { Interval = 1000 };

            _timer.Elapsed += (sender, e) =&amp;gt; Send(
                new List&amp;lt;SharePrice&amp;gt;(new[]
                                         {
                                             new SharePrice
                                                 {
                                                     Date = DateTime.Now,
                                                     Price = VaryPrice(),
                                                     Share = new Share {Name = &quot;Fowler-Corp&quot;}
                                                 }
                                         }));
            _timer.Start();

            return true;
        }

        public void Send(IEnumerable&amp;lt;SharePrice&amp;gt; sp)
        {
            Clients.drawShareValue(Context.ClientId, sp);
        }
    }
&lt;/pre&gt;&lt;br /&gt;
Avez-vous remarqué la méthode Connect()? On y a fait appel à partir du code JS.&lt;br /&gt;
Et l&#39;appel à drawShareValue(), fait bien référence à la méthode que l&#39;on à définit dans le javascript. Enorme, non?&lt;br /&gt;
&lt;br /&gt;
Tout cela est possible parce que SignalR utilise dans ses fondements le typage &lt;a href=&quot;http://en.wikipedia.org/wiki/C_Sharp_4.0#Dynamic_member_lookup&quot;&gt;dynamic&lt;/a&gt; à laquelle vient s&#39;ajouter une résolution de Propriété/Méthode &quot;simple&quot; par convention, évitant ainsi d&#39;avoir à écrire du code verbeux.&lt;br /&gt;
&lt;br /&gt;
Au final, voici ce que l&#39;on peut obtenir...&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;http://fabrice.michellonet.free.fr/MyMemoryLeaks/Posts/43/chart_crop.png&quot; alt=&quot;chart&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
Bon ok, l&#39;image ne bouge pas, il faut imaginer qu&#39;un point vient s&#39;ajouter chaque seconde dans le graph :)&lt;br /&gt;
&lt;br /&gt;
Pour ceux qui voudrait jeter un coup d’œil à la solution entière, vous pouvez la récupérer sur &lt;a href=&quot;https://github.com/fmichellonet/SignalR.Samples.MVCLiveChart&quot;&gt;Github&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Avez-vous utilisé d&#39;autres technos/framework pour faciliter les communications &quot;temps réel&quot; entre le serveur et le browser?&lt;br/&gt;&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/7833601605957993703/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/7833601605957993703' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/7833601605957993703'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/7833601605957993703'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2011/09/live-charting-avec-signalr.html' title='Live charting avec SignalR'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-3820879386763448703</id><published>2011-07-13T17:07:00.002+02:00</published><updated>2011-07-13T17:12:03.051+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="EntityFramework.Patterns"/><category scheme="http://www.blogger.com/atom/ns#" term="ORM"/><title type='text'>EntityFramework.Patterns : Repository &amp; Unit Of Work</title><content type='html'>&lt;p&gt;
Je vous propose un très rapide post pour faciliter la prise en main des Patterns Repository&lt;T&gt; et Unit Of Work disponibles dans &lt;a href=&quot;&quot;&gt;EntityFramework.Patterns&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Pour simplifier le sujet, le but du pattern Repository est de donner au développeur une passerelle de requêtage unifiée, via des opérations (le plus souvent) atomiques.
Unit Of Work, est la quant à lui pour valider transactionnellement un ensemble de modifications faites sur les données.&lt;/p&gt;
&lt;p&gt;Pour la version longue vous pourrez trouver votre bonheur sur le site de &lt;a href=&quot;http://martinfowler.com/&quot;&gt;Martin Fowler&lt;/a&gt; &lt;a href=&quot;http://martinfowler.com/eaaCatalog/repository.html&quot;&gt;ici pour le Repository&lt;/a&gt; et &lt;a href=&quot;http://martinfowler.com/eaaCatalog/unitOfWork.html&quot;&gt;ici pour Unit Of Work&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Partons d&#39;un modèle simplissime comme celui ci-dessous :
&lt;pre class=&quot;brush:csharp&quot;&gt;

public class Context : DbContext
{
    public virtual DbSet&amp;lt;Product&amp;gt; Products { get; set; }
    public virtual DbSet&amp;lt;ProductCategory&amp;gt; Categories { get; set; }

    public Context()
    {
        Database.SetInitializer(new DropCreateDatabaseAlways&amp;lt;Context&amp;gt;());
    }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int? ProductCategoryId { get; set; }
    public virtual ProductCategory ProductCategory { get; set; }
}

public class ProductCategory
{
    public int Id { get; set; }
    public string Name { get; set; }
}
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;Commençons par créer le Repository
&lt;pre class=&quot;brush:csharp&quot;&gt;
using(Context ctx = new Context())
{
    DbContextAdapter adapter = new DbContextAdapter(ctx);
    IRepository&amp;lt;Product&amp;gt; productRepo = new Repository&amp;lt;Product&amp;gt;(adp);
    ...
}
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;Interrogeons la base pour ramener l&#39;ensemble des produits :
&lt;pre class=&quot;brush:csharp&quot;&gt;
IEnumerable&amp;lt;Product&amp;gt; lst = productRepo.GetAll();
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;Ramenons le premier élément dont le nom commence par &quot;Bike&quot;&lt;/p&gt;
&lt;pre class=&quot;brush:csharp&quot;&gt;
Product prod = productRepo.First(p =&amp;gt; p.Name.StartsWith(&amp;quot;Bike&amp;quot;));
&lt;/pre&gt;
&lt;p&gt;L&#39;utilisation de la méthode Single a pour effet de ramener un seul élément de la base de données; mais lève une exception si plusieurs éléments répondent aux critères demandés.
&lt;pre class=&quot;brush:csharp&quot;&gt;
 productRepo.Single(p =&amp;gt; p.Name.StartsWith(&amp;quot;Roc&amp;quot;))
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;Find(), permet de filtrer en fonction de plusieurs critères :
&lt;pre class=&quot;brush:csharp&quot;&gt;
IEnumerable&amp;lt;Product&amp;gt; lst = productRepo.Find(
                p =&amp;gt; p.Id &amp;lt; 100 &amp;amp;&amp;amp; p.Name.Contains(&amp;quot;o&amp;quot;) &amp;amp;&amp;amp; p.Name.Length &amp;lt; 20);
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;Toutes ces méthodes acceptent optionnellement un ensemble de liens de navigation inter entités 
&lt;pre class=&quot;brush:csharp&quot;&gt;params Expression&amp;lt;Func&amp;lt;T, object&amp;gt;&amp;gt;[] includeProperties&lt;/pre&gt;
définissant les jointures à effectuer lors du requêtage.
Ainsi :
&lt;pre class=&quot;brush:csharp&quot;&gt;
productRepo.First(p =&amp;gt; p.ProductCategoryId != null , p =&amp;gt; p.ProductCategory);
&lt;/pre&gt;
charge le produit et sa catégorie associée en une seule requete SQL; Cette façon de faire nous protège du fameux problème du &lt;a href=&quot;http://stackoverflow.com/questions/97197/what-is-the-n1-selects-problem&quot;&gt;Select N+1&lt;/a&gt; lié au &lt;a href=&quot;http://en.wikipedia.org/wiki/Lazy_loading&quot;&gt;lazy loading&lt;/a&gt; utilisé par défaut avec Entity Framework.
&lt;/p&gt;
&lt;p&gt;Après l’interrogation de la base passons a la persistance de nos données. Pour cela nous allons faire appel au pattern UnitOfWork.
L&#39;insertion d&#39;un nouvel élément prend cette forme :
&lt;pre class=&quot;brush:csharp&quot;&gt;
using(...)
{
   ...
   IUnitOfWork unitOfWork = new UnitOfWork(adp);
   Product p = new Product{Name = &quot;Skateboard&quot;};
   productRepo.Insert(p);
   unitOfWork.Commit();
}
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;Vous l&#39;aurez compris la mise à jour et la suppression sont aussi simple que ca : 
&lt;pre class=&quot;brush:csharp&quot;&gt;
Product p = productRepo.First(c =&amp;gt; c.Name == &amp;quot;Bike&amp;quot;);
p.Name = &quot;New bike&quot;;
productRepo.Update(p);

Product delete = productRepo.First(p =&amp;gt; p.Name.StartsWith(&amp;quot;To be&amp;quot;)); 
productRepo.Delete(delete);

unitOfWork.Commit();
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;Dans les prochains jours je vous montrerais comment injecter Repository et Unit of work dans une couche Service par exemple avec un conteneur DI comme &lt;a href=&quot;http://ninject.org/&quot;&gt;NInject&lt;/a&gt;.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/3820879386763448703/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/3820879386763448703' title='4 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/3820879386763448703'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/3820879386763448703'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2011/07/entityframeworkpatterns-repository-unit_13.html' title='EntityFramework.Patterns : Repository &amp; Unit Of Work'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-7405101182765635229</id><published>2011-07-07T18:32:00.001+02:00</published><updated>2011-07-07T18:39:26.839+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="EntityFramework.Patterns"/><title type='text'>Release d&#39;EntityFramework.Patterns</title><content type='html'>&lt;p&gt;Bon ça y est je me suis décidé à trouver un toit pour &lt;a href=&quot;http://efpatterns.codeplex.com/&quot;&gt;EntityFramework.Patterns&lt;/a&gt;, une librairie qui s&#39;adossant à &lt;a href=&quot;http://msdn.microsoft.com/en-us/data/aa937723&quot;&gt;Entity Framework 4.1&lt;/a&gt;, propose l&#39;implémentation de patterns couramment nécessaire lorsqu&#39;on utilise un &lt;a href=&quot;http://en.wikipedia.org/wiki/Object-relational_mapping&quot;&gt;ORM&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Je n&#39;ai toujours pas cédé aux appels des sirènes de &lt;a href=&quot;https://github.com/&quot;&gt;Github&lt;/a&gt;; EntityFramework.Patterns est donc hébergé sur &lt;a href=&quot;http://www.codeplex.com/&quot;&gt;Codeplex&lt;/a&gt;.
Vous trouverez également la librairie sur &lt;a href=&quot;http://nuget.org/List/Search?packageType=Packages&amp;searchCategory=All+Categories&amp;searchTerm=EntityFramework.Patterns&amp;sortOrder=package-download-count&amp;pageSize=10&quot;&gt;nuget&lt;/a&gt;... d&#39;ailleurs elle y était présente bien avant la création du repository sur codeplex.
&lt;/p&gt;
&lt;p&gt;
Pour l&#39;installer via nuget, rien de plus simple :
&lt;pre class=&quot;brush: ps&quot;&gt;
install-package EntityFramework.Patterns
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;
A l&#39;heure actuelle, vous trouverez deux patterns d&#39;infrastructure :
&lt;ul&gt;
&lt;li&gt;Repository&lt;/li&gt;
&lt;li&gt;Unit Of work&lt;/li&gt;
&lt;/ul&gt;

&lt;a href=&quot;http://wekeroad.com/post/7102729511/a-simple-example-thats-incredibly-complex&quot;&gt;Rob Conery&lt;/a&gt; les définissaient ainsi récemment : 

&lt;blockquote&gt;
The Repository Pattern is all about encapsulating calls to your DB as methods to do a thing. These calls are (typically) atomic.
&lt;/blockquote&gt;
&lt;br/&gt;
Tout est dit! L&#39;avantage est simple, couplé avec &lt;a href=&quot;http://blog.ploeh.dk/2010/09/20/InstrumentationWithDecoratorsAndInterceptors.aspx&quot;&gt;un/des décorateurs&lt;/a&gt; il sera facile d&#39;ajouter des comportements transverses (cache, securité, log etc...)

&lt;blockquote&gt;
UnitOfWork is - well it’s a way of transactionally flushing changes to a persistence store (aka Database)
&lt;/blockquote&gt;
&lt;br/&gt;
Ce qui permet de découpler facilement la gestion d&#39;état des entités et le requêtage.
&lt;/p&gt;

&lt;p&gt;Des patterns d&#39;infrastructure pour l&#39;instant, qui seront rapidement suivit par les patterns suivants :
&lt;ul&gt;
&lt;li&gt;Repository Decorator&lt;/li&gt;
&lt;li&gt;Audit log&lt;/li&gt;
&lt;li&gt;Audit trail&lt;/li&gt;
&lt;li&gt;Archived entity&lt;/li&gt;
&lt;li&gt;Internationalized entity&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;p&gt;
Dans un tout prochain post je présenterais ces deux patterns Repostitory&amp;lt;T&amp;gt; et UnitOfWork.
&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/7405101182765635229/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/7405101182765635229' title='6 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/7405101182765635229'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/7405101182765635229'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2011/07/release-dentityframeworkpatterns.html' title='Release d&#39;EntityFramework.Patterns'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-535820351817854973</id><published>2011-07-07T16:51:00.000+02:00</published><updated>2011-07-07T16:51:38.029+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Electronique"/><category scheme="http://www.blogger.com/atom/ns#" term="Micro Framework"/><title type='text'>FEZ Domino</title><content type='html'>&lt;p&gt;Un rapide post pour vous faire partager ma joie de ce jour.&lt;/p&gt;
&lt;p&gt;J&#39;ai enfin reçu la commande que j&#39;avais passé sur &lt;a href=&quot;http://www.robotshop.com/eu/&quot;&gt;Roboshop&lt;/a&gt; il y a bientôt un mois (ils déconnent un peu chez Roboshop sur les délai...)
Bref, entre autre dans le colis :
&lt;ol&gt;
&lt;li&gt;Micro-contrôleur &lt;a href=&quot;http://www.ghielectronics.com/catalog/product/133&quot;&gt;Fez Domino&lt;/a&gt;
   &lt;ul&gt;
     &lt;li&gt;Processeur 72Mhz 32-bit ARM7 LPC2388&lt;/li&gt;
     &lt;li&gt;~148KB free Flash&lt;/li&gt;
     &lt;li&gt;~62KB free RAM&lt;/li&gt;
   &lt;/ul&gt;
   &lt;br/&gt;
   &lt;img alt=&quot;fez domino&quot; src=&quot;http://fabrice.michellonet.free.fr/MyMemoryLeaks/Posts/42/FEZ_Domino.JPG&quot;/&gt;
&lt;/li&gt;
   &lt;br/&gt;
&lt;li&gt;Un servo controlleur &lt;a href=&quot;http://www.lynxmotion.com/p-395-ssc-32-servo-controller.aspx&quot;&gt;SSC-32&lt;/a&gt;
   &lt;ul&gt;
     &lt;li&gt;Peut gérer jusqu&#39;à 32 servo moteurs.&lt;/li&gt;
   &lt;/ul&gt;
&lt;br/&gt;
   &lt;img alt=&quot;SSC-32&quot; src=&quot;http://fabrice.michellonet.free.fr/MyMemoryLeaks/Posts/42/SSC32.JPG&quot;/&gt;
&lt;/li&gt;
&lt;br/&gt;
&lt;/ol&gt;
C&#39;est vraiment petit ces trucs la, pour vous donner une idée, les voici à côté d&#39;une pile 9V.
&lt;br/&gt;&lt;br/&gt;
&lt;img alt=&quot;Domino &amp; SSC-32&quot; src=&quot;http://fabrice.michellonet.free.fr/MyMemoryLeaks/Posts/42/Domino&amp;SSC32.JPG&quot;/&gt;
&lt;/p&gt;
&lt;p&gt;Mon premier défit va être de tenter le portage d&#39;un &lt;a href=&quot;http://en.wikipedia.org/wiki/Dependency_injection&quot;&gt;conteneur DI&lt;/a&gt; sur cette plateforme. Je sens que ça va être chaud!&lt;/p&gt;
&lt;p&gt;Ensuite, je crois que je vais tenter la construction d&#39;un &lt;a href=&quot;http://fr.wikipedia.org/wiki/Robot_hexapode&quot;&gt;Hexapode&lt;/a&gt;... d’où l&#39;achat du SSC-32.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/535820351817854973/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/535820351817854973' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/535820351817854973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/535820351817854973'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2011/07/fez-domino.html' title='FEZ Domino'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-7742361934671179583</id><published>2011-06-21T23:32:00.003+02:00</published><updated>2011-07-11T15:46:40.827+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET MVC"/><category scheme="http://www.blogger.com/atom/ns#" term="Nuget"/><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio"/><title type='text'>Custom ASP.NET MVC Project Template</title><content type='html'>&lt;p&gt;Récemment, Phil Haack nous présentait dans un très bon post &lt;a href=&quot;http://haacked.com/archive/2011/06/06/creating-a-custom-asp-net-mvc-project-template.aspx&quot;&gt;comment ajouter un template MVC3 personnalisé&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Dans ce post il lève le voile sur l&#39;intégration de &lt;a href=&quot;http://nuget.org/&quot;&gt;nuget&lt;/a&gt; dans Visual Studio. On y apprend que malheureusement par manque de temps l&#39;intégration n&#39;est que minimaliste et que seul les packages présent sur la machine (%ProgramFiles%\Microsoft ASP.NET\ASP.NET MVC 3\Packages) ne peuvent être installés.&lt;/p&gt;
&lt;p&gt;Après avoir fait un peu joujou avec, voici quelques points complémentaires : 
&lt;ul&gt;
&lt;li&gt;Pour télécharger un package nuget (extension nupkg), vous pouvez utiliser &lt;a href=&quot;http://nuget.codeplex.com/releases/view/59864&quot;&gt;nuget package explorer&lt;/a&gt;&lt;/li&gt;&lt;br/&gt;
&lt;li&gt;Il n&#39;y a pas de résolution de dépendance entre package. Vous devez donc les ordonner dans la section WizardData :
&lt;pre class=&quot;brush: csharp&quot;&gt;
&amp;lt;WizardData&amp;gt;
    &amp;lt;packages&amp;gt;
        &amp;lt;package id=&amp;quot;jQuery&amp;quot; version=&amp;quot;1.5.1&amp;quot; /&amp;gt;
        &amp;lt;package id=&amp;quot;jQuery.Validation&amp;quot; version=&amp;quot;1.8.0&amp;quot; /&amp;gt;
        &amp;lt;package id=&amp;quot;jQuery.UI.Combined&amp;quot; version=&amp;quot;1.8.11&amp;quot; /&amp;gt;
    &amp;lt;/packages&amp;gt;
&amp;lt;/WizardData&amp;gt;
&lt;/pre&gt;
&lt;/li&gt;&lt;br/&gt;
&lt;li&gt;Les template de quickstart (plusieurs projets) fonctionnent dans cette configuration et peuvent tirer parti de l&#39;installation de packages via nuget.&lt;/li&gt;&lt;br/&gt;
&lt;li&gt;Il m&#39;est arrivé a plusieurs reprise de noter que la commande 
&lt;pre class=&quot;brush: ps&quot;&gt;
devenv /installvstemplates
&lt;/pre&gt; ne suffisait a rafraichir le cache de template de Visual Studio. Un reboot de la machine remet tout dans l&#39;ordre.&lt;/li&gt;&lt;br/&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;p&gt;Happy Nuget!&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/7742361934671179583/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/7742361934671179583' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/7742361934671179583'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/7742361934671179583'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2011/06/custom-aspnet-mvc-project-template.html' title='Custom ASP.NET MVC Project Template'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-4414461101769599008</id><published>2011-05-17T21:00:00.005+02:00</published><updated>2011-06-21T23:35:11.192+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Nuget"/><category scheme="http://www.blogger.com/atom/ns#" term="Obsidian"/><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio"/><title type='text'>Quickstart &amp; Nuget</title><content type='html'>&lt;p&gt;Dans mon &lt;a href=&quot;http://mymemoryleaks.blogspot.com/2011/05/project-template-quickstart-et-vsix.html&quot;&gt;précédent post&lt;/a&gt; j’effleurais le sujet des gains de productivité que pouvais procurer les templates et autres Quickstart dans vos développement de tous les jours.&lt;/p&gt;
&lt;p&gt;Prenons le cas d’un Quickstart, qui je le rappelle n’est autre qu’une solution templatisée. Imaginons que l’on souhaite utiliser 3 ou 4 librairies externes .NET bien sentie et pourquoi pas une ou deux librairies javascript s’il s’agit d’une solution Web.&lt;/p&gt;
&lt;p&gt;En m’appuyant sur &lt;a href=&quot;http://nuget.codeplex.com/&quot;&gt;Nuget&lt;/a&gt; lors de la création des templates de projet composant le Quickstart, les dépendances pourrons être facilement être mise à jour par les développeurs à posteriori toujours grâce à Nuget. Rien de magique dans tout ça, en fait chaque projet est doté de son propre fichier &#39;packages.config&#39; (repository nuget pour le projet) relatant la version des librairies référencées.&lt;/p&gt;
&lt;p&gt;Voici ce que j’aimerais mettre en place en plus : 
&lt;ul&gt;
&lt;li&gt;Mise à jour automatique de nuget avant toute autre opération.&lt;/li&gt;
&lt;li&gt;Téléchargement et installation automatisée des dépendances référencées pour chaque projet.&lt;/li&gt;
&lt;li&gt;Mise à jour automatique des dépendances lors de la première installation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Infos complémentaires :&lt;/p&gt;
&lt;p&gt;Microsoft depuis le &lt;a href=&quot;http://www.microsoft.com/downloads/en/details.aspx?FamilyID=82cbd599-d29a-43e3-b78b-0f863d22811a&amp;displaylang=en&quot;&gt;MVC3 Tool Update&lt;/a&gt; du 12 Avril 2011 propose un nouveau template de projet MVC3 basé lui aussi sur nuget. La technique utilisée est quelque peu différente de celle que je vous présente ici, mais ne permet pas la mise à jour automatique des dépendances à l’installation.&lt;/p&gt;
&lt;p&gt;Je reviendrais surement très rapidement sur cette façon de faire dans un prochain billet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pour réaliser ces différents points il nous faudra coder un &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.templatewizard.iwizard%28v=VS.100%29.aspx&quot;&gt;Wizard&lt;/a&gt; custom.&lt;/p&gt;
&lt;p&gt;La première tâche consistant à déployer nuget.exe est simplissime. Il nous suffit de l’embarquer dans les ressources de notre Wizard, puis au runtime extraire l’exécutable et le copier par exemple dans le dossier « packages » au sein de la solution. Pour info, le dossier « package » est utilisé par nuget pour y stocker les dépendances qu’il a téléchargé.&lt;/p&gt;
&lt;pre class=&quot;brush: csharp&quot;&gt;
DirectoryInfo packageDirInfo = _solutionDirInfo.CreateSubdirectory(&quot;packages&quot;);
string _nugetFilePath = Path.Combine(packageDirInfo.FullName, &quot;Nuget.exe&quot;);
File.WriteAllBytes(_nugetFilePath, Resources.NuGet);
&lt;/pre&gt;
&lt;p&gt;
Notez que le dossier package doit absolument se trouvé dans le même répertoire que votre fichier sln, si vous voulez pouvoir profiter de la mise à jour des packages. Il s’agit d’une restriction imposé par nuget lui-même
&lt;/p&gt;
&lt;p&gt;
Nuget déployé, il est possible de le mettre à jour automatiquement en exécutant la ligne de commande suivante :
&lt;/p&gt;
&lt;pre class=&quot;brush: ps&quot;&gt;nuget update&lt;/pre&gt;
&lt;p&gt;Dans notre Wizard on pourra utiliser le code suivant : &lt;/p&gt;
&lt;pre class=&quot;brush: csharp&quot;&gt;
Process nugetProc = new Process
            {
                StartInfo = new ProcessStartInfo(_nugetFilePath)
                {
                    Arguments = &quot;update&quot;,
                    RedirectStandardError = true,
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                },
            };
            nugetProc.Start();
            StreamReader output = nugetProc.StandardOutput;
            StreamReader error = nugetProc.StandardError;
            nugetProc.WaitForExit();
&lt;/pre&gt;
&lt;p&gt;
Concernant l’installation des dépendances de chaque projet se fera simplement en utilisant une fois de plus une ligne de commande ; que l’on créera en C# de la manière suivante : 
&lt;/p&gt;
&lt;pre class=&quot;brush: csharp&quot;&gt;
Process nugetProc = new Process
            {
                StartInfo = new ProcessStartInfo(_nugetFilePath)
                {
                    Arguments = string.Format(&quot;install {0}&quot;, _packageFilePath),
                    RedirectStandardError = true,
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    WorkingDirectory = new FileInfo(_nugetFilePath).DirectoryName
                 },
            };
            nugetProc.Start();
&lt;/pre&gt;
&lt;p&gt;
L’idée ici est en fait d’exécuter 1 fois pour chacun de vos projets la commande suivante : &lt;/p&gt;
&lt;pre class=&quot;brush: ps&quot;&gt;nuget install %path/to%/packages.config&lt;/pre&gt;
&lt;p&gt;
Reste encore la tache de mettre à jour toutes les dépendances. Malheureusement, pour l’instant nuget.exe ne propose pas encore de commande permettant la mise à jour des dépendances. Cependant un récent &lt;a href=&quot;#&quot;&gt;post&lt;/a&gt;, &lt;a href=&quot;http://haacked.com/&quot;&gt;Phil Haack&lt;/a&gt; annonce la disponibilité de cette option pour la version de 1.4 de nuget.
&lt;/p&gt;
&lt;p&gt;En attendant cette fonctionnalité, nous pouvons nous en sortir en installant par default le package &lt;a href=&quot;http://nuget.org/List/Packages/NuGetPackageUpdater&quot;&gt;NuGetPackageUpdater&lt;/a&gt;. Ce dernier vous offre la possibilité d’exécuter la commande &#39;Update-Package&#39; qui se chargera d’effectuer la mise à jour de toutes les dépendances de la solution.&lt;/p&gt;
&lt;p&gt;J’espère qu’en suivant ces instructions vous pourrez construire des Templates qui se mettrons à jour tout seul.&lt;/p&gt;
&lt;p&gt;Pour ceux qui souhaiteraient jeter un coup d’œil plus approfondi au code que je viens de présenter, il est disponible sur &lt;a href=&quot;http://www.codeplex.com/&quot;&gt;Codeplex&lt;/a&gt; avec l’ensemble des briques du Quikstart &lt;a href=&quot;http://obsidian.codeplex.com/&quot;&gt;Obsidian&lt;/a&gt; sur lequel je travaille actuellement.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/4414461101769599008/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/4414461101769599008' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/4414461101769599008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/4414461101769599008'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2011/05/quickstart-nuget.html' title='Quickstart &amp; Nuget'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1146316188254265608.post-7767491471490552912</id><published>2011-05-13T23:29:00.000+02:00</published><updated>2011-05-13T23:29:16.839+02:00</updated><title type='text'>Project Template, Quickstart et VSIX</title><content type='html'>&lt;p&gt;Dernièrement j’ai fait mumuse avec les template de fichiers et projets que l’on peut créer dans Visual Studio.&lt;/p&gt;
&lt;img src=&quot;http://fabrice.michellonet.free.fr/MyMemoryLeaks/Posts/41/coccinelle.png&quot; alt=&quot;coccinelle&quot;/&gt;
&lt;p&gt;Pour ceux qui ne connaissent pas, les template de fichier vous permettent de définir l’ossature d’un type de fichier que vous utilisez souvent.  Une fois créé vous retrouverez votre template dans le menu de Visual Studio « Add new Item ».&lt;/p&gt;

&lt;p&gt;Par extension les projects template vous permettent de définir la structure d’un type projet, afin de prendre en compte les conventions de votre équipe par exemple. Vous y définissez l’ensemble des fichiers présent dès la création du projet.&lt;/p&gt;

&lt;p&gt;Ce qui est très intéressant, c&#39;est que cela permet d&#39;avoir des projets prêts à l&#39;emploi dans votre environnement, avec par exemple &lt;a href=&quot;http://nlog-project.org/&quot;&gt;NLog&lt;/a&gt;&amp;nbsp;&lt;a href=&quot;http://www.blogger.com/post-create.g?blogID=1146316188254265608&quot;&gt;et votre conteneur &lt;/a&gt;&lt;a href=&quot;http://martinfowler.com/articles/injection.html&quot;&gt;DI&lt;/a&gt; &lt;a href=&quot;http://www.castleproject.org/&quot;&gt;préféré&lt;/a&gt;. Si vous êtes expérimenté cela vous évitera quelques copier-coller,  si par contre vous ne connaissez pas bien une des briques technique cela vous évitera un tas de problématique.&lt;/p&gt;

&lt;p&gt;Quoi qu&#39;il en soit voici quelques astuces sur ces templates :&lt;p/&gt;

&lt;ol&gt;&lt;br/&gt;
&lt;li&gt;Bien que le &lt;a href=&quot;http://www.microsoft.com/downloads/en/details.aspx?FamilyID=21307c23-f0ff-4ef2-a0a4-dca54ddb1e21&quot;&gt;SDK&lt;/a&gt; de Visual Studio vous propose des projets de type Item Template et Project Template, le plus simple reste d’utiliser le menu File -&amp;gt; Export Template de Viual Studio pour générer votre précieux template.&lt;/li&gt;&lt;br/&gt;
&lt;li&gt;Pour créer un quickstart, qui n’est autre qu’un template de solution (plusieurs projets), je vous conseille de : &lt;/li&gt;
&lt;ol&gt;&lt;br/&gt;
&lt;li&gt;Exporter vos différents projets template et extraire les archives zip correspondante dans un même dossier.&lt;/li&gt;&lt;br/&gt;
&lt;li&gt;Ajouter dans ce dossier de travail un fichier .vstemplate reprenant cette structure&lt;/li&gt;&lt;br/&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;VSTemplate Version=&quot;2.0.0&quot; xmlns=&quot;http://schemas.microsoft.com/developer/vstemplate/2005&quot; Type=&quot;ProjectGroup&quot;&amp;gt;
  &amp;lt;TemplateData&amp;gt;
    &amp;lt;Name&amp;gt;Ma solution&amp;lt;/Name&amp;gt;
    &amp;lt;Description&amp;gt;Ma description&amp;lt;/Description&amp;gt;
    &amp;lt;ProjectType&amp;gt;CSharp&amp;lt;/ProjectType&amp;gt;
    &amp;lt;ProjectSubType&amp;gt;&amp;lt;/ProjectSubType&amp;gt;
    &amp;lt;SortOrder&amp;gt;1000&amp;lt;/SortOrder&amp;gt;
    &amp;lt;CreateNewFolder&amp;gt;false&amp;lt;/CreateNewFolder&amp;gt;
    &amp;lt;LocationField&amp;gt;Enabled&amp;lt;/LocationField&amp;gt;
    &amp;lt;EnableLocationBrowseButton&amp;gt;true&amp;lt;/EnableLocationBrowseButton&amp;gt;
    &amp;lt;Icon&amp;gt;monicone_100x100.ico&amp;lt;/Icon&amp;gt;
  &amp;lt;/TemplateData&amp;gt;
  &amp;lt;TemplateContent&amp;gt;
    &amp;lt;ProjectCollection&amp;gt;
      &amp;lt;ProjectTemplateLink ProjectName=&quot;Web&quot;&amp;gt;
        Web\MyTemplate.vstemplate
      &amp;lt;/ProjectTemplateLink&amp;gt;
      &amp;lt;ProjectTemplateLink ProjectName=&quot;Domain&quot;&amp;gt;
        Domain\MyTemplate.vstemplate
      &amp;lt;/ProjectTemplateLink&amp;gt;
      &amp;lt;ProjectTemplateLink ProjectName=&quot;DAL&quot;&amp;gt;
        DAL\MyTemplate.vstemplate
      &amp;lt;/ProjectTemplateLink&amp;gt;
      &amp;lt;ProjectTemplateLink ProjectName=&quot;IServices&quot;&amp;gt;
        IServices\MyTemplate.vstemplate
      &amp;lt;/ProjectTemplateLink&amp;gt;
      &amp;lt;ProjectTemplateLink ProjectName=&quot;Services&quot;&amp;gt;
        Services\MyTemplate.vstemplate
      &amp;lt;/ProjectTemplateLink&amp;gt;
    &amp;lt;/ProjectCollection&amp;gt;
  &amp;lt;/TemplateContent&amp;gt;
&amp;lt;/VSTemplate&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Vous pouvez y mettre autant de référence a des projects que vous le souhaitez en ajoutant des balises ProjectTemplateLink.&lt;/p&gt;
&lt;li&gt;Créez une archive zip du dossier de travail et placez la dans le dossier %VSInstallDir%\Common7\IDE\ProjectTemplates\. Après redémarrage de Visual Studio le nouveau template sera dispo.&lt;/li&gt;&lt;br/&gt;
&lt;/ol&gt;
&lt;li&gt;Dans le fichier vstemplate de votre Quickstart, la première occurrence à un projet sera par convention le startup project.&lt;/li&gt;&lt;br/&gt;
&lt;li&gt;Pour étendre avec du code custom vos project template il vous faudra :&lt;/li&gt;&lt;br/&gt;
&lt;ol&gt;
&lt;li&gt;Créer une assembly et implémenter l’interface &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.templatewizard.iwizard%28v=VS.100%29.aspx&quot;&gt;Microsoft.VisualStudio.TemplateWizard.IWizard&lt;/a&gt;&lt;/li&gt;&lt;br/&gt;
&lt;li&gt;Ajouter la balise WizardExtension dans le fichier .vstemplate de votre project template&lt;/li&gt;&lt;br/&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;
&amp;lt;VSTemplate Version=&amp;quot;3.0.0&amp;quot; xmlns=&amp;quot;http://schemas.microsoft.com/developer/vstemplate/2005&amp;quot; Type=&amp;quot;Project&amp;quot;&amp;gt;
  …
  &amp;lt;WizardExtension&amp;gt;
    &amp;lt;Assembly&amp;gt;MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=952e5fc020f3b126&amp;lt;/Assembly&amp;gt;
    &amp;lt;FullClassName&amp;gt;MyAssembly.Wizard&amp;lt;/FullClassName&amp;gt;
  &amp;lt;/WizardExtension&amp;gt;
&amp;lt;/VSTemplate&amp;gt;
&lt;/pre&gt;
&lt;/ol&gt;
&lt;li&gt;Il est possible de faire appel à une assembly custom dans un template de type quickstart, mais attention, la plupart des appels que vous ferez sur les objects EnvDTE et plus particulièrement &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/envdte.project.aspx&quot;&gt;EnvDTE.Project&lt;/a&gt; fréquemment utilisés dans la méthode &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.templatewizard.iwizard.projectitemfinishedgenerating.aspx&quot;&gt;IWizard. ProjectFinishedGenerating&lt;/a&gt; vous renverront des valeurs nulles.&lt;/li&gt;&lt;br/&gt;
&lt;li&gt;La façon la plus simple de créer un VSIX de déploiement est d’utiliser le projet de type VSIX Project  (Visual C# -&gt; Extensibility -&gt; VSIX Project). Le &lt;a href=&quot;http://www.microsoft.com/downloads/en/details.aspx?FamilyID=21307c23-f0ff-4ef2-a0a4-dca54ddb1e21&quot;&gt;SDK&lt;/a&gt; doit être installé.&lt;/li&gt;&lt;br/&gt;
&lt;li&gt;Dans le designer de VSIX, le champ ID comporte un GUID… n’y touchez surtout pas !&lt;/li&gt;&lt;br/&gt;
&lt;li&gt;Il est possible de définir dans quelle catégorie de template se trouvera l’élément que vous déployez via votre VSIX en renseignant le champ Add to subfolder.&lt;/li&gt;&lt;br/&gt;
&lt;img src=&quot;http://fabrice.michellonet.free.fr/MyMemoryLeaks/Posts/41/subfolder.png&quot; alt=&quot;subfolder&quot;/&gt;
&lt;/ol&gt;</content><link rel='replies' type='application/atom+xml' href='http://mymemoryleaks.blogspot.com/feeds/7767491471490552912/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1146316188254265608/7767491471490552912' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/7767491471490552912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1146316188254265608/posts/default/7767491471490552912'/><link rel='alternate' type='text/html' href='http://mymemoryleaks.blogspot.com/2011/05/project-template-quickstart-et-vsix.html' title='Project Template, Quickstart et VSIX'/><author><name>Fabrice Michellonet</name><uri>http://www.blogger.com/profile/10201820062243684793</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//2.bp.blogspot.com/-QI4mwdRtAig/VzXmA7hTkLI/AAAAAAAALEY/TrLSbDUW46UyAVJc2_z4VvVua-U9ccanQCK4B/s220/avatar.png'/></author><thr:total>0</thr:total></entry></feed>