Centre de développement Sharepoint 2010
Sharepoint 2010 - MSDN
Tutoriels Sharepoint 2010 sur areaprog
Developper Top 10 Resource Center | Sharepoint
Un petit mot pour vous inviter à un E-camp (un live meeting) que j’animerai vendredi 24 février à 13h30.
Je vous ferai une présentation dirigée d'un sample Windows Phone 7 qui utilise une authentification par Access Control Service.
Votre application proposera ainsi une connexion FB, Live, Google, … et les utilisateurs se connecteront avec un de leurs comptes existants parmi ces fournisseurs d’identité.
Les avantages sont multiples:
- Vous n’aurez pas à développer votre propre gestion de comptes et de profils - L’utilisateur n’aura pas besoin de créer un nouveau compte spécifique à votre application - Vous choisissez quels providers utiliser par simple configuration, sans modifier votre code
- Vous n’aurez pas à développer votre propre gestion de comptes et de profils
- L’utilisateur n’aura pas besoin de créer un nouveau compte spécifique à votre application
- Vous choisissez quels providers utiliser par simple configuration, sans modifier votre code
Nous installerons le package NuGet permettant d’utiliser ACS sur Windows Phone, puis nous mettrons en place les différents éléments pour passer le jeton d’authentification à un web service.
En espérant vous voir vendredi !!!
Après une journée J1 marathon mais passionnante, voici un début de contenu du parcours “De A à Z : concevoir une solution applicative”.
Merci à tous ceux qui ont suivi les sessions que j’ai animées avec grand plaisir avec des co-speakers de choc !
Désolée pour ceux qui n’ont pas eu de place. Heureusement les webcasts arrivent et en attendant je vous propose les slides.
A très bientôt !
Vous souhaitez repartir avec une vision complète du développement d’application ? Vous souhaitez comprendre quelles technologies mettre en œuvre pour un résultat moderne, sexy et interopérable ? Vous souhaitez actualiser vos compétences dans le développement ? Vous souhaitez développer une application sans partir dans le mur ? Vous souhaitez profiter des techdays pour acquérir les bons réflexes ? Vous hésitez quant aux sessions à suivre ?
Ce parcours est fait pour vous !
Pendant une journée, il vous sert de guide pour comprendre comment construire une solution applicative de bout en bout.
A partir d’un cahier des charges, nous définirons l’architecture de la solution en justifiant le choix des technologies mises en œuvre . Nous aborderons ensuite chacun des aspects du développement de la solution, depuis le back-end jusqu’aux applications clientes, en passant par l’hébergement de ce petit monde.
Au sommaire, 5 sessions:
Les sessions peuvent aussi être suivies de manière indépendante, le besoin métier (notre fil rouge) servant simplement de support aux démos.
Chaque session se déroulera en 2 phases et conviendra aussi bien au public débutant que confirmé
Des spoilers sur le contenu des sessions bientôt
Le parcours “De A à Z : Développer une solution applicative” c’est le 7 février aux TechDays 2012…
Faites passer !
Le toolkit Azure pour Windows Phone simplifie grandement l’intégration d’Azure dans les applications. Depuis peu, il a été divisé en plusieurs packages NuGet permettant de cibler l’intégration d’une fonctionnalité précise (stockage, ACS, notifications Push, …)
L’un des packages permet d’intégrer les fonctionnalités d’une authentification auprès de providers d’identités existants (Facebook, Windows Live, Google,…) grâce à Access Control Services.
Dans mon application, l’utilisateur pourra s’authentifier auprès de ces providers et le jeton d’authentification sera réinjecté dans les requêtes OData envoyées à mon WCF Data Service. Au niveau de mon service, les données ajoutées par un utilisateur authentifié seront rattachées à celui-ci et lui seul y aura accès par la suite.
Revenons à notre Toolkit Azure : notre application utilisera donc ACS et proposera une mire de connexion en fonction du provider choisi. Voici le package NuGet à installer dans votre projet WP7.
Le mode d’emploi est explicite et il est donc relativement aisé d’intégrer une authentification OAuth 2.0 dans une application WP7.
Par contre, la procédure ne détaille pas comment mettre en place le service web pour lequel pour utilisera précisément cette authentification, en réinjectant le jeton dans la requête http OData.
En fait, la solution est un mix entre le tutoriel créé pour l’ancien toolkit et le mode d’emploi installé avec le package NuGet.
Voici comment faire, en quelques étapes…
Notre application WP7 manipule des données fournies par un service OData. Mais seul un utilisateur authentifié sera autorisé récupérer ces données, et seules les données le concernant lui seront renvoyées.
Ce package mettra en place tout ce qu’il faut dans votre projet pour qu’il puisse utiliser ACS et stocker le jeton qui sera réinjecté dans les requêtes OData, par la suite.
Le mode d’emploi ([Your WP7 Project]/App_Readme/Phone.Identity.Controls.BasePage.Readme.htm) s’affiche dès l’installation du package NuGet. Il suffit de suivre les étapes pour le faire fonctionner.
Vous aurez néanmoins besoin d’un ACS, que vous pouvez configurer en suivant les étapes mentionnées ici dans la Task 2.
La page de login s’affiche dans un web browser control, il faut donc le déclarer au niveau du manifest : WMAppManifest.xml
<Capability Name="ID_CAP_WEBBROWSERCOMPONENT"/>
Ajoutez la page de login en tant que page de démarrage de votre application, comme indiqué dans le mode d’emploi.
Lorsque vous démarrez l’application, si votre jeton est encore valide vous naviguerez directement à la page d’accueil de votre application. Dans ce cas, il faut prévoir de sortir de l’application sur le bouton Back. Une manière de réaliser cette opération est de vider l’historique de navigation lorsque l’on arrive sur la page d’accueil.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo(e); while(this.NavigationService.BackStack.Any()) { NavigationService.RemoveBackEntry(); } }
A ce niveau, vous devriez être capable de vous logger en vous identifiant auprès d’un de vos providers préférés, par-exemple avec un Live Id:
Une fois que l’authentification a réussi, le jeton est stocké comme un SimpleWebTokenStore dans
Application.Current.Resources["swtStore"]
Le jeton doit être placé dans l’en-tête de la requête Http. Il faut s’abonner à l’évènement SendingRequest de votre contexte WCF Data Service et y mettre à jour l’en-tête en ajoutant l’”authorization”.
_dc = new YourDataServiceContext(new Uri("http://YourDataService.svc/")); _dc.SendingRequest += new EventHandler<SendingRequestEventArgs>(SendingRequest); void SendingRequest(object sender, SendingRequestEventArgs e) { var simpleWebTokenStore = Application.Current.Resources["swtStore"] as SimpleWebTokenStore; if (simpleWebTokenStore != null) { e.RequestHeaders["Authorization"] = "OAuth " + simpleWebTokenStore.SimpleWebToken.RawToken; } }
Attention, l’accès aux Resources ne peut se faire en dehors du thread de l’UI. Si c’est votre cas, il faut stocker le jeton ailleurs pour l’utiliser sans problème depuis l’événement SendingRequest.
Si votre service n’est pas configuré pour fonctionner avec OAuth 2.0, suivez l’étape Task 3 – Securing an OData Service with OAuth2 and Windows Identity Foundation du tutoriel mentionné précédemment.
Votre service utilisera une librairie développée par Microsoft DPE, qui étend le mécanisme de WIF pour supporter OAuth 2.0.
A ce niveau, vous devriez avoir:
L’identité de l’appelant (que l’on récupère depuis le header) va nous servir dans l’application des règles métier de notre service.
[System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)] public class YourDataService : DataService<[YourContext]> { // This method is called only once to initialize service-wide policies. public static void InitializeService(DataServiceConfiguration config) { config.SetEntitySetAccessRule("[YourEntity]", EntitySetRights.All); config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3; } string GetUserIdentity() { string userIdName = null; var claim = HttpContext.Current.User.Identity as IClaimsIdentity; if (HttpContext.Current.Request.IsAuthenticated) { userIdName = HttpContext.Current.User.Identity.Name; } return userIdName; }
Vous pouvez utiliser des QueryInterceptor et/ou ChangeInterceptor pour intercepter les requêtes, et ainsi modifier leur comportement par défaut suivant l’identité de l’appelant. Dans mon cas, je stocke l’identifiant de l’appelant dans chaque enregistrement qu’il ajoute dans la base.
[ChangeInterceptor("[YourEntity]")] public void OnChange([YourEntityType] updatedRecord, UpdateOperations operations) { if (operations == UpdateOperations.Add) { var userIdName = GetUserIdentity(); if (userIdName == null) { throw new DataServiceException(401, "Permission Denied you must be an authenticated user"); } updatedRecord.UserId = userIdName; } }
Les requêtes de sélection ne revoient que les enregistrements associés à l’identité de l’appelant. Seul le créateur des enregistrements pourra y accéder.
[QueryInterceptor("[YourEntity]")] public Expression<Func<[YourEntityType], bool>> OnQuery() { var userIdName = GetUserIdentity(); if (userIdName == null) { throw new DataServiceException(401, "Permission Denied you must be an authenticated user"); } return (b => b.UserId == userIdName); }
Placez un point d’arrêt dans le ChangeInterceptor ou le QueryInterceptor pour vérifier si tout ce petit monde fonctionne et si votre identité est récupérée correctement côté serveur dans votre service. Si ce n’est pas le cas, essayez d’utiliser IIS plutôt que le Visual Studio Development Server (merci à Benjamin Guinebertière pour l’astuce !)
Chaque requête OData effectuée depuis notre application Windows Phone inclut un jeton d’authentification, renseigné par le provider d’identité. Cette opération se fait par l’intermédiaire d’ACS. Cette identité peut être utilisée dans des règles métier au niveau du WCF Data Service. Ces règles seront appliquées quel que soit le client duquel provient la requête. Il est ainsi possible de contrôler l’accès et l’édition des données effectués depuis un client aussi simpliste qu’un navigateur web. Sans jeton d’authentification, les requêtes déclencheront un erreur de sécurité (pour ceux qui ne suivent pas : c’est parce que l’on a codé en déclenchant explicitement une exception dans le service).
Vous pourrez manipuler les données publiées en OData depuis votre application WP7 mais également depuis toute application tournant sur n’importe quelle plateforme supportant une authentification OAuth 2.0.
Elle est pas belle la vie ?
The Windows Azure Toolkit for Windows Phone is helping a lot to integrate all kind of Azure features in the device. Recently, Azure Toolkit for Windows Phone has been split in separate parts (storage, ACS, Push notification, …), so that each can be used separately in a project (via NuGet), which is a VERY good thing.
Though, it makes it easy to deal with ACS authentication and external identity providers which is what we need in our WP7 application. We want to get an authenticated user to use our app since the OData service will associate data to this user. The service will also ensure that each user will have access to his own data only.
Back to the Azure Toolkit : we are interested in the ACS part so that our WP7 application provides a log in page and an authenticated user. The NuGet package for this is here:
The How To is very explicit, though, it is very easy to handle an OAuth 2 authentication in a windows phone app.
But the procedure doesn’t explain how to set up your remote service so that it can handle the token you just received, and also doesn’t detail how to send it to the server. Actually the answer is a mix of the tutorial dedicated to the inital toolkit, and the new “How To” procedure.
Here is how to do it in a few steps…
Our WP7 application needs to access data from the OData service, but only an authenticated user will be allowed to. We also want to filter resulting information according to the user identity.
This package will install all your project needs to use ACS and store the token that will be later reinjected in the OData Http request.
The “HowTo” ([Your WP7 Project]/App_Readme/Phone.Identity.Controls.BasePage.Readme.htm) is very explicit and you just need to follow the steps to make it work. by the way, you need to have set up an ACS like explained here in Task 2.
The log in page will be provided from a web browser control, so you should make it available in the manifest file WMAppManifest.xml
Add the log in page as the welcome page in your application, as explained in the How To.
If your token is valid when you start the app, you will skip the log in page and navigate directly to your application home page. So you will have to handle the Back button from there so that you exit the application. You can do it by clearing the navigation history when you navigate to your home page:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo(e); while (this.NavigationService.BackStack.Any()) { NavigationService.RemoveBackEntry(); } }
At this point, you should be able to log into your app with any of your identity provider credentials, for example with a Live ID:
Once the log in procedure succeeds, your token is stored as a SimpleWebTokenStore in
The token will be placed in the header of the http request.You should register to the SendingRequest event of your WCF Data Service context and update the header with the authorization.
The access to the Resources is not allowed from a thread different from the IU thread, so if that may happen in your case, you should save the token in some place from a BeginInvoke so that you can reuse it safely in the SendingRequest event.
If your WCF Data Service has not been setup to handle OAuth 2, you should follow the step Task 3 – Securing an OData Service with OAuth2 and Windows Identity Foundation of the great tutorial mentioned earlier.
You will use an assembly developped by Microsoft DPE guys, that extends the WIF mechanism to handle OAuth.
At this point you should have:
You would probably check the identity on some actions made on your data.
You can use interceptors (QueryInterceptor or ChangeInterceptor) to do some identity validation and relative tasks, according to your business rules. In my case, I store the user identity name in each new record.
On queries, I return only records that are associated to the identity of the request initiator.
You can put a breakpoint on the ChangeInterceptor and QueryInterceptor to check if everything is going fine and if your identity is retrieved properly on the service side. If not, try to use IIS instead of Visual Studio Development Server (thanks to Benjamin Guinebertière for that tip !)
Each OData request made from your WP application is now including an identity token, allowed by the identity provider through ACS. You can use this identity for business rules purpose in your service, and this will be efficient wherever the request comes from. Though, you can protect your data from being accessed and updated from a simple web browser which will return a security exception.
You can still use these data from any application running on any platform that is able to send an OAuth http authorization header.
Now that we can scan a barcode from a picture thanks to ZXing lib, let’s try to improve the user experience.
It would be much better to scan a barcode in real time, just like WP7 does out of the box. I wanted to provide this kind of experience in my own application. You can do the same by downloading the following lib and use the code below.
Download the binaries and add a reference to both dlls in your own project.
Use the video scan lib by calling the static StartScan method of the BarCodeManager static class.
/// <summary> /// Starts the scan : navigates to the scan page and starts reading video stream /// Note : Scan will auto-stop if navigation occurs /// </summary> /// <param name="onBarCodeFound">Delegate Action on a barcode found</param> /// <param name="onError">Delegate Action on error</param> /// <param name="zxingReader">(optional) A specific reader format, Default will be EAN13Reader </param> public static void StartScan(Action<string> onBarCodeFound, Action<Exception> onError, BarcodeFormat barcodeFormat = null)
Parameters are:
- Action<string> onBarCodeFound : a delegate called on a background thread as soon as a barcode/QR code is detected. The parameter is the associated barcode/QR string - Action<Exception> onError : a delegate on error. The parameter is the associated exception that generated the error - BarcodeFormat barcodeFormat = null : the type of code that should be scanned (default = UPC_EAN): ALL_1D; CODE_128; CODE_39; DATAMATRIX; EAN_13; EAN_8; ITF; PDF417; QR_CODE; UPC_A; UPC_E; // Auto detect UPC_EAN;
Calling StartScan will launch the WP7 camera, and start the scanning process which consists in:
If unsuccessful, it will retry 15 times after what it will call the onError callback with a VideoScanException exception as a parameter. You can update the trial count by setting BarCodeManager.MaxTry (default is 15).
If a code was found, the onBarCodeFound callback will be called with the string code found as a parameter.
private void Button_Click(object sender, RoutedEventArgs e) { WP7.ScanBarCode.BarCodeManager.StartScan( // on success (b) => Dispatcher.BeginInvoke(() => { tbScanResultBarCode.Text = b; NavigationService.GoBack(); }), // on error (ex) => Dispatcher.BeginInvoke(() => { tbScanResultBarCode.Text = ex.Message; NavigationService.GoBack(); }) // Default : please, decode any bar-code ); }
private void Button_Click_1(object sender, RoutedEventArgs e) { WP7.ScanBarCode.BarCodeManager.StartScan( // on success (b) => Dispatcher.BeginInvoke(() => { tbScanResultQR.Text = b; NavigationService.GoBack(); }), // on error (ex) => Dispatcher.BeginInvoke(() => { tbScanResultQR.Text = ex.Message; NavigationService.GoBack(); }), // Please, decode a QR Code BarcodeFormat.QR_CODE); }
You can test the sample application ang get the whole code here.
The lib uses the video capabilities of WP7.1 SDK with the PhotoCamera class. The code is inspired from the original idea of Pierre Cauchois and includes some snippets from SLAR toolkit.
[This is an early version made for my own purpose and was not tested for production]
La communauté Silverlight qui s’est montée récemment sur Facebook (http://on.fb.me/pVH80X) organise son premier évènement dans nos locaux ce mercredi après-midi (le 26 octobre).
N’hésitez pas à venir assister aux sessions inédites :
La communauté Silverlight France se lance, venez participer à sa naissance ! - Session “Présentation de la Communauté” (15mn) Découvrez la communauté, son site web, son mode de fonctionnement et comment contribuer à celle-ci. Vous aimez Silverlight et vous souhaitez partager ? Alors venez aider et contribuer ! Vous aimez Silverlight mais vous ne savez pas par quel bout commencer ? Venez comprendre comment apprendre auprès d’experts reconnus sur le meilleur des ressources francophones. Vous ne connaissez pas encore Silverlight ? Venez découvrir et mesurer tout le potentiel de cette technologie qui a déjà fait ses preuves aujourd’hui et qui réserve bien des surprises à l’avenir. - Session “Silverlight 5 : Nouveautés et 3D” (1h20) Présenté par David Catuhe (Microsoft France), Cyril Cathala (So@t) et Nathanael Marchand (So@t) Silverlight 5 arrive et apporte son lot de nouveautés. A travers cette session, vous allez pouvoir découvrir, comprendre et analyser toutes les nouveautés de cette version qui repousse encore plus loin les limites des RIA. Au menu, fenêtres natives, intégration encore plus poussée avec Windows, capacités multimédia améliorées tout ceci en proposant des outils encore plus performants pour le développement et le débogage. Mais la plus grosse innovation de Silverlight reste l’intégration du moteur XNA: la 3D dans Silverlight. Aidés de la dernière version du Silverlight Toolkit, nous découvrirons comment profiter d’une des plateformes de référence utilisée pour les jeux vidéo (sur XBOX et Windows Phone 7) afin que vos visiteurs soient époustouflés par des visites virtuelles, des catalogues de produits animés et d’autres raffinements qu’aucune autre technologie web ne permet si simplement. - Session “Rx Framework” (40mn) Présenté par Aymeric Lagier (SUPINFO/MSP Expert Silverlight), Christophe Argento (Ineat Conseil) et Kévin Alexandre (Wygwam) Le challenge des interfaces d’aujourd’hui est de proposer toujours plus de fluidité tout en poussant la complexité tant au niveau des sources de données que du volume de données. Venez découvrir cette bibliothèque de Microsoft qui permet de simplifier le développement, gagner en fluidité tout en maitrisant les pièges de l’asynchrone. - Session “Communication en Silverlight” (40mn) Présenté par John Thiriet (MCNext) et Matthieu Mezil (Infinite Square/MVP) Communiquer efficacement en Silverlight est un challenge. Vous pourrez découvrir lors de cette session des méthodes et astuces pour que votre application soit efficace face aux scénarios les plus complexes. La nouvelle couche Low Latency de Silverlight 5, la comparaison entre la pile de communication navigateur et client, WCF pour Silverlight seront notamment les sujets abordés lors de cet après-midi. - Session “Retour d’expérience MVVM” (40mn) Animé par Stéphanie Hertrich (Microsoft France) et Jonathan Antoine (Infinite Square/MVP) Session spéciale, interactive et inédite : nous discuterons ensemble de MVVM afin de bénéficier du retour d'expérience de chacun. La session se voudra agile et sera construite d'après vos retours, en abordant de nombreux thèmes comme les difficultés rencontrées fréquemment avec ce pattern, les frameworks du marché, etc. A la suite de ces sessions, un petit cocktail sera proposé afin de partager en toute convivialité avec les acteurs de la communauté ainsi que l’équipe de développement du Silverlight 5 Toolkit présente en exclusivité pour vous.
A mercredi !
Edit 14/11/2011 : Mieux que de prendre le code en photo : Scannez un code barre/QR en live dans un flux vidéo en 1 ligne de code ! http://bit.ly/ud2rFn
Cet article complète la première maquette de l’application CaveAVins pour Windows Phone 7.5, en ajoutant une fonction d’aide à l’achat grâce au scan du code-barre de la bouteille.
L’application initiale permet d’ajouter, modifier, noter, localiser géographiquement un vin. Pour simplifier la création d’un vin et surtout obtenir une aide à l’achat d’un vin en boutique, il sera possible de prendre le code-barre de la bouteille en photo, de visualiser les notes qui lui ont été données par les autre utilisateurs et d’obtenir la fiche complète du vin. Si cette bouteille n’a pas encore été évaluée, la fiche du vin devra être créée manuellement et sera ainsi prête pour les prochains acheteurs.
Nous complèterons l’application existante, en mettant en place les éléments suivants:
Articles:
Tutoriels:
1 - Le scan de code-barre est accessible à partir de la tuile secondaire ou de la page d’ajout/édition d’un vin
2 - Le code-barre d’une bouteille est pris en photo
3 – Ce vin existe déjà dans le catalogue : sa fiche est complétée automatiquement, ou une nouvelle fiche de vin sera créée. La note moyenne donnée par les utilisateurs s’affiche au bas de la photo.
Téléchargez la librairie ZXing sur codeplex. Elle permet de scanner différents types de code-barres ainsi que des code QR dont voici la liste:
UPC-A and UPC-E EAN-8 and EAN-13 Code 39 Code 128 QR Code ITF Data Matrix (Not tested) PDF417 (Not tested)
Dans notre cas, nous utiliserons le type Code 128.
La librairie est sous licence Apache 2.0 et peut donc être utilisée sur le marketplace. Plus d’information concernant l’utilisation de librairies open-source sur le marketplace:
Pour utiliser la librairie, référencez-la dans votre application Windows Phone
Le scan de code barre est déclenché par le code ci-dessous où l’on récupère le résultat de manière asynchrone:
/// <summary> /// Button click handler to initiate scanning. This should be ted to the click event for a button in your application /// </summary> public void ScanBarCode() { try { WP7BarcodeManager.ScanMode = com.google.zxing.BarcodeFormat.UPC_EAN; WP7BarcodeManager.ScanBarcode(BarcodeResults_Finished); //Provide callback method } catch (Exception ex) { Debug.WriteLine("Error processing image.", ex); } } /// <summary> /// Callback method that processes results returned by the WP7BarcodeManager. Results are also stored at WP7BarcodeManager.LastCaptureResults. /// </summary> /// <param name="BCResults">Object that holds all the results of processing the barcode. Results are also stored at WP7BarcodeManager.LastCaptureResults.</param> public void BarcodeResults_Finished(BarcodeCaptureResult BCResults) { Deployment.Current.Dispatcher.BeginInvoke(() => { try { if (BCResults.State == CaptureState.Success) { BarCode = BCResults.BarcodeText; //Use results FindWineFromBarCode(_BarCode); } else { MessageBox.Show(BCResults.ErrorMessage); } } catch (Exception ex) { MessageBox.Show(String.Format("Barcode Processing Error: {0}", ex.Message)); } }); }
En suivant l’exemple de code plus complet fourni dans la page de documentation, vous pourrez même faire fonctionner votre application dans l’émulateur : il suffit dans ce cas de choisir une image sur votre disque plutôt que de prendre une photo.
On recherche ensuite un vin ayant le code-barre détecté et on charge sa fiche s’il existe déjà dans la base, la fiche reste vierge en dehors du code-barre et devra être remplie manuellement.
private void FindWineFromBarCode(string barCode) { // On cherche d'abord dans notre propre cave à vins var existingWine = CaveAVinsModel.Instance.Bottles.FirstOrDefault(b => b.WineInfos.BarCode == barCode); if (existingWine != null) { MessageBox.Show(Resources.Strings.Wine_AlreadyExistsInYourCave); SelectedBottle = existingWine; } else { // sinon on recherche le vin dans le catalogue complet CaveAVinsModel.Instance.FindWineFromBarCode(SelectedBottle, barCode, () => RefreshWineInfos(SelectedBottle)); } }
Pour faciliter l’ajout d’un vin, il est possible d’épingler la fonction de scan d’un code-barre directement sur la page d’accueil du téléphone.
La tuile secondaire est créée en cliquant sur le bouton visible sur la page d’édition du vin.
Voici le code utilisé pour créer la tuile :
void CreateApplicationSecondaryTile() { var appTile = ShellTile.ActiveTiles .FirstOrDefault(t => t.NavigationUri.ToString().Contains("Scan")); if (appTile == null) { StandardTileData secTileData = new StandardTileData() { BackgroundImage = new Uri("/icons/barcode.png", UriKind.Relative), Title = Strings.secTileBarCode_Title, }; ShellTile.Create(new Uri("/View/EditWineView.xaml?Scan=1", UriKind.Relative), secTileData); } }
Un paramètre “Scan” est passé à la page EditWineView pour différencier les sources d’appel : depuis la tuile ou depuis l’application. Si c’est la tuile qui a déclenché la navigation sur la page, on lance directement la fonction de scan, pour minimiser le nombre de clics. Cette opération est réalisée en surchargeant la méthode OnNavigatedTo:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { if (e.NavigationMode == System.Windows.Navigation.NavigationMode.New) { if (NavigationContext.QueryString.ContainsKey("Scan")) { App.ViewModel.EditWineViewModel.ScanBarCode(); } } else { base.OnNavigatedTo(e); } }
Il faut pouvoir différencier la note que l’on donne au vin, de la moyenne de celles données par les autres utilisateurs. C’est pourquoi l’affichage de la note moyenne du vin est ajouté au bas de la photo, sur la fiche du vin.
Pour l’instant, celle-ci est calculée en temps réel lors de l’ouverture de la fiche : on récupère toutes les fiches de caves associées à ce vin qui comportent une note et on en fait une moyenne. Mais on pourrait imaginer la stocker dans la fiche et la mettre à jour à partir de notre WCF Data Service à l’aide d’un intercepteur sur les requêtes d’ajout/modification sur l’entite MyWine. Ceci permettrait d’optimiser la communication entre l’application et la base de données. Ce principe d’intercepteurs a déjà été utilisé dans l’article précédent, pour stocker la latitude et la longitude associés à une adresse géographique et vous pouvez vous y référer pour comprendre comment cela fonctionne.
Cette fois-ci , l’application est réellement collaborative ! On retrouve une bouteille de vin déjà présente dans le catalogue, on peut voir la moyenne des notes qui lui ont été attribuées et également la noter soi-même. De là à ce qu’elle soit vraiment fonctionnelle, il n’y a qu’un pas…ou peut-être plusieurs, soit. Il manque encore plein de petits plus très pratiques comme pouvoir saisir le code-barre à la main ou retrouver une bouteille à partir de son nom. Il faudrait également pouvoir classer les vins dans des catégories et cépages.
Mais vous l’aurez compris, le principe pour réaliser ces fonctions sont du même ordre que celles qui ont déjà été réalisées et ne justifient pas l’écriture d’un tutoriel dédié. D’autres fonctions collaboratives seraient néanmoins intéressantes comme le partage sur Facebook ou la possibilité de faire partager un vin à un autre utilisateur de l’application.
D’autres plateformes peuvent aussi être très intéressantes pour ce genre d’applications avec notamment des possibilités avancées pour le partage d’information et les notifications.
A suivre !
Plus que quelques jours avant la nouvelle saison 2011 des MsDays.
J’aurai le plaisir de participer à 2 sessions très différentes.
En partant du besoin fonctionnel de départ, nous choisirons les technologies adéquates pour implémenter notre application. D'Entity Framework, à WCF Data Services, en passant par la migration dans le Cloud, SQL Azure, WP7, Bing Map. Le but étant de vous en montrer les points clés.
Une session co-présentée avec Eric Vernie, qui reprend le fil conducteur de la série d’articles sur la cave à vins.
Comment développer une application avec les technologies actuelles, en respectant l’évolution des usages. Un bon résumé de la conception de bout en bout, depuis le stockage des données jusqu’à l’application Windows Phone et à l’ouverture vers d’autres technologies clientes. Une session dense, avec du code, qui vous permettra d’avoir un bon tour d’horizon des technologies de développement.
Office 365 vient d’être lancé avec son offre de plateforme collaborative adaptée à toutes les tailles d’Entreprise, de la messagerie aux solutions synchrones, en passant par le portail collaboratif. Vous connaissez déjà les bonnes pratiques de développement sur SharePoint Online : sandbox, intégration Silverlight, Linq to SharePoint, WCF, etc. Venez découvrir dans cette session comment passer à la vitesse supérieure en industrialisant vos développements de bout en bout, des spécifications fonctionnelles au déploiement et à la maintenance applicative dans le cloud. Un témoignage exclusif de Calinda Software, une Start-up française éditrice de solution sociale autour de SharePoint, qui viendra illustrer cette vision à travers leur propre expérience sur la Marketplace Office 365 pour le portage de leur solution dans le Cloud.
Une session co-présentée avec Na-Young Kwon (responsable produit Sharepoint) et la société Calinda.
Après un rappel des différences entre Sharepoint et Sharepoint Online par Na-Young, Calinda vous parlera des principales difficultés rencontrées lors du passage sur Sharepoint Online te sur la Marketplace. J’entrerai ensuite plus dans le code en vous montrant quelques astuces pour le développement sur la version Online de Sharepoint.
Update 18/10/2011: l’url du service OData devient http://stephecaveavins.cloudapp.net/CaveAVinsDataService.svc
Cet article décrit le fonctionnement de la première maquette de l’application Cave A Vins pour Windows Phone. Il explique les points sensibles de l’application et détaille leur réalisation, sans rentrer autant dans le détail qu’un tutoriel.
Pas si basique que cela, notre application va mettre en œuvre les concepts suivants:
Nous allons également modifier le service WCF Data Services pour le rendre plus intelligent et effectuer automatiquement la transformation d’une adresse en coordonnées latitude/longitude que l’on ajoutera aux informations sur le vin.
L’application est développée pour Windows Phone 7.1. Pour découvrir les nouveautés par-rapport à la version 7.0, c’est ici. Prérequis : Windows Phone SDK 7.1 Release Candidate
Un petit aperçu du résultat:
Voilà à quoi ressemble notre application de gestion de Cave A Vins. L’application utilise un contrôle Panorama, avec un en-tête déroulant affichant autant d’images de bouteilles que vous avez de vins différents dans votre cave. Si vous avez des yeux de lynx (‘achement dur ne pas écrire Linq ou Lync ), vous remarquerez qu’elles portent le nom du vin sur leur étiquette. Bon c’est pas fait pour être lisible, juste décoratif : les bouteilles défilent quand vous passez d’un item panorama à un autre (cf vidéo).
1 2 3
1 - La première page affiche la liste des vins présents dans la cave triés par date décroissante d’achat.
2 - La seconde utilise le contrôle LongListSelector du toolkit Silverlight pour WP7 pour afficher la même liste, groupée par année. On pourrait imaginer ajouter les informations sur les cépages et proposer le même type de vue groupée ce qui serait très pratique.
3 - La troisième page utilise le contrôle Bing Maps pour afficher l’origine des vins et le nombre de bouteilles associées. Cela permet de repérer facilement ce qu’il manque à la cave pour être suffisamment variée géographiquement parlant.
4 5
4 – le menu contextuel permet de décrémenter le nombre de bouteilles du vin sélectionné, d’ajouter/éditer/supprimer un vin de sa cave.
5 – l’édition d’un vin permet de saisir les informations qui lui sont relatives ainsi que de prendre la photo de son étiquette
Rappel de l’architecture existante après la migration dans Azure:
Et l’architecture qui sera mise en place dans le contexte de cet article :
Le service proxy d’authentification “CaveAVins Blob Authentifier” est facultatif mais conseillé pour ne pas divulguer les clés d’accès au storage Azure.
A ce stade, plusieurs questions restent encore en suspens :
De mon point vue, la question est moins triviale pour une application Silverlight WP7 que pour du Silverlight classique.
Pour ma part, en Silverlight je pars toujours sur du “MVVM-like” plus ou moins strict, selon l’importance et la durée de vie de mon application. Je pars soit de mes classes de base et méthodes d’extension qui constituent ma boite à outils que j’ai créé au fil des projets, soit d’un framework ou partie de framework existant type MVVMLight, Caliburn, Prism…
En 3 mots, si vous ne savez pas ce qu’est MVVM (Model – View – ViewModel) : c’est une architecture 3-tiers avec
La bible de ce qu’est l’architecture MVVM, avec un petit exemple et le code associé qui va bien : http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
Le choix est moins immédiat sur WP7 qu’en Silverlight classique ou WPF, car beaucoup de contrôles standards “metro styled” n’intègrent pas complètement les bindings (ex : les boutons de la barres de menu). Heureusement, plusieurs variantes de frameworks MVVM ont été portées pour WP7, comme MVVMLight, Caliburn, …
Dans mon cas, je n’utiliserai pas de framework prêt à l’emploi – ce n’est pas le sujet de cet article -, mais je reste sur une architecture de type MVVM, sans être trop stricte, en conservant du code behind, notamment pour la navigation, et la gestion des boutons de la barre de menus.
La couche View est composée de vues : MainView qui contient le panorama à 3 items et EditWineView qui permet d’éditer un vin.
La couche ViewModel contient les 2 ViewModels associés aux vues : MainViewModel et EditWineViewModel.
La couche Model est composée de la classe CaveAVinsModel qui est générée automatiquement lors de l’ajout du service CaveAVins, à partir des metadata, ce qui fait gagner un temps fou. D’autant plus que ces classes proxy implémentent déjà les mécanismes de notification (INotifyPropertyChanged). Du coup, mon MainviewModel va pouvoir directement exposer ces collections à la vue, sans passer par une classe WineViewModel intermédiaire. C’est un premier raccourci par-rapport à du MVVM.strict, mais dans ce cas là, c’est nettement plus productif.
La classe métier UploadPhoto prend en charge la sauvegarde des photos dans l’Azure Blob Storage, permettant ainsi que les couches Viewmodel et View ne soient pas couplées au mécanisme des blobs. On pourrait ainsi facilement stocker les photos ailleurs sans retoucher aux couches de présentation.
La couche DAL correspond à l’accès aux données : aux blobs Azure et à notre service WCF Data Services hébergé lui aussi dans Azure.
Pour pouvoir associer des bouteilles à un propriétaire, plusieurs options s’offrent à nous et en l’occurrence, c’est la plus simple qui a été retenue.
Le téléphone stocke un numéro associé au Live Id du propriétaire (renseigné dès le téléchargement de la première application sur le MarketPlace). Nous pouvons donc utiliser cet identifiant pour rattacher un vin à son propriétaire, sans pour autant lui demander d’informations d’authentification ou de connexion. Et si vous changez de téléphone, vous ne perdez pas pour autant votre cave à vins.
Voici un exemple de code permettant d’accéder au numéro de l’utilisateur:
public string GetUserAnId() { string myId = string.Empty; string anid = UserExtendedProperties.GetValue("ANID") as string; if (anid != null) { myId = anid.Substring(2, 32); } return myId; }
Une autre solution serait d’utiliser la fédération d’identité, en utilisant Azure Access Control Services (ACS) et un compte provenant d’un fournisseur d’identité comme Hotmail, Facebook, Google,… Cela évite à l’utilisateur de créer un énième compte dédié à l’application de cave à vins et ça permet au développeur de ne pas réinventer la roue en créant un mécanisme de gestion de comptes qui lui est propre.
Le Toolkit Azure pour Windows Phone permet de simplifier cette opération en fournissant un template tout prêt pour ce genre d’applications. Benjamin a réalisé une vidéo de quelques minutes pour vous montrer comment utiliser le toolkit pour la gestion des authentifications.
Une des vues de mon panorama est une carte Bing Map matérialisant les quantités restantes de chacun des vins de ma cave. C’est une bonne aide à l’achat pour garantir une cave variée et cela me permet de vérifier rapidement si je ne manque pas de vin d’Alsace !
Le contrôle Bing Map fait cela très bien en affichant des punaises correspondant à une liste de coordonnées géographiques (latitude, longitude). Dans notre cas, la fiche d’un vin contient une adresse et il faut donc passer par une étape intermédiaire avant de pouvoir afficher la punaise : la transformation de l’adresse en latitude et longitude. Bing Map fournit un service de résolution utilisable avec un compte développeur gratuit. Pour plus d’information sur les conditions d’utilisation : http://www.microsoft.com/maps/product/licensing.aspx.
L’application Windows Phone pourrait réaliser cette résolution dynamiquement lors du lancement de l’application, mais cela signifie que je ferais autant de résolutions que de vins dans ma cave, à chaque chargement des données. Une meilleure idée serait de modifier directement la fiche du vin lors de l’ajout ou de la modification d’un vin. Mais si c’est mon application WP7 qui s’en charge, cela signifie que tout autre client potentiel qui ajouterait des vins dans la cave ne disposerait pas de la latitude et longitude. L’idéal serait que quiconque utilise le service bénéficie de cette résolution d’adresse, même un simple client http.
Nous allons donc déporter cette résolution au niveau du service WCF Data Services à l’aide d’”intercepteurs”'. Voici comment cela se met place dans notre solution, dans la classe CaveAVinsDataService :
public class CaveAVinsDataService : DataService<CaveAVins.Db.CaveAVinsContext> { // This method is called only once to initialize service-wide policies. public static void InitializeService(DataServiceConfiguration config) { config.SetEntitySetAccessRule("Wines", EntitySetRights.All); config.SetEntitySetAccessRule("Bottles", EntitySetRights.All); config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3; } // Define a change interceptor for the Products entity set. [ChangeInterceptor("Wines")] public void OnChangeProducts(Wine updatedWine, UpdateOperations operations) { CurrentDataSource.ChangeTracker.DetectChanges(); foreach (var uw in CurrentDataSource.ChangeTracker.Entries<Wine>()) { string oldValue = null; if (operations == UpdateOperations.Change) { oldValue = CurrentDataSource.ChangeTracker.Entries<Wine>().First().OriginalValues.GetValue<string>("Address"); } if (oldValue != updatedWine.Address) { // Update Latitude & longitude var geoloc = MakeGeocodeRequest(updatedWine.Address); if (geoloc != null) { uw.Entity.Latitude = geoloc.Latitude; uw.Entity.Longitude = geoloc.Longitude; } } } }
On ajoute une méthode préfixée d’un custom attribute ChangeInterceptor("Wines")qui permet d’intercepter les requêtes de modification et d’ajout sur la table Wine. Si cette opération concerne un ajout ou qu’une modification de la propriété Address a été détectée, on appelle le service BingMap qui nous renverra une latitude et une longitude à partir de l’adresse. Ces informations sont alors répercutées directement dans l’entité Wine.
C’est tout côté serveur.
Dans l’application, il suffit de binder la collection de vins au contrôle Bing Map.
<my:Map CredentialsProvider="Your credentials" Center="46.642000079154968,2.3379997909069061" ZoomLevel="5"> <my:MapItemsControl ItemsSource="{Binding Model.Bottles}"> <my:MapItemsControl.ItemTemplate> <DataTemplate> <my:Pushpin Location="{Binding Converter={StaticResource BottlesToLocationConv}}" Tap="Image_Tap" Background="DarkRed" FontWeight="Bold"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Count}"/> <my:Pushpin.Template> … </my:Pushpin.Template> </my:Pushpin> </DataTemplate> </my:MapItemsControl.ItemTemplate> </my:MapItemsControl> </my:Map>
Pour cela, j’utilise un converter qui me renvoit une instance de Geocoordinates (latitude, longitude) à partir d’une instance de Wine. Puis je personnalise le PushPin pour qu’il affiche le nombre de bouteilles, c’est à dire la propriété Count de la classe MyWine.
public class BottlesToLocationConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { MyWine wine = value as MyWine; GeoCoordinate result = null; if (wine != null) { result = new GeoCoordinate(wine.WineInfos.Latitude.GetValueOrDefault(), wine.WineInfos.Longitude.GetValueOrDefault()); } return result; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return null; } }
Le tour est joué !
Le SDK Windows Phone 7.1 fournit un client WCF Data Services (vive Linq) ainsi que la possibilité de générer les classes proxy d’un service directement dans Visual Studio : bref, c’est tout pareil qu’en Silverlight classique.
On commencer par ajouter la référence du service de cave à vins : http://stephecaveavins.cloudapp.net/CaveAVinsDataService.svc. Puis on instancie la classe de contexte qui vient d’être générée. Ensuite on construit sa requête de sélection ou on effectue les opérations CUD et on exécute tout cela de manière asynchrone.
Reste la gestion du tombstoning du contexte WCF Data Services qui permettra de retrouver un état cohérent de nos entités : How to persist the state of an OData client for Windows Phone. En effet, depuis Windows Phone 7.1, la persistence des données est facilitée par la nouvelle méthode “Serialize” au niveau du contexte WCF Data Services.
Tous les détails dans le tutoriel associé à paraitre.
Pour permettre de réaliser ces fonctionnalités, nous avons besoin d’ajouter des informations dans la base de données et donc de modifier sa structure. Rappelons que celle-ci a été créée automatiquement à partir de nos classes POCOs, grâce à Entity Framework Code First.
Il est également possible d’associer des classes POCOs à une base de données existante, et c’est ce qui a été fait dans notre cas, pour ajouter de nouvelles colonnes/propriétés. La structure de la base a été modifiée directement à partir du portail SQL Azure et les nouvelles propriétés de nos POCOS sont associées aux nouvelles colonnes de nos tables grâce à l’API Fluent pour Entity Framework Code First.
Avant :
Maintenant:
L’entité MyWine est complétée par
L’entité Wine est complétée par:
Avec Fluent, cela se fait en quelques lignes dans le contructeur du contexte, après avoir complété les POCOs par les nouvelles propriétés:
public class CaveAVinsContext : DbContext { public DbSet<MyWine> Bottles { get; set; } public DbSet<Wine> Wines { get; set; } public CaveAVinsContext() : base() { Database.SetInitializer<CaveAVinsContext>(null); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<MyWine>().Property(p => p.UserId); modelBuilder.Entity<MyWine>().Property(p => p.AddedDate); modelBuilder.Entity<Wine>().Property(p => p.BarCode); modelBuilder.Entity<Wine>().Property(p => p.Latitude); modelBuilder.Entity<Wine>().Property(p => p.Longitude); base.OnModelCreating(modelBuilder); } }
C’est très facile grâce à l’API WP7 dédiée et cela se fait en quelques lignes, du genre :
void TakeAPic() { CameraCaptureTask task = new CameraCaptureTask(); task.Completed += (sender, photoResult) => { if (photoResult.TaskResult == TaskResult.OK) { BitmapImage bmp = new BitmapImage(); bmp.SetSource(photoResult.ChosenPhoto); PhotoSource = bmp; } }; task.Show(); }
Attention de pas oublier de :
Une fois la photo prise et la fiche enregistrée, il faut :
Une fois de plus, le Toolkit Azure pour Windows Phone va nous aider en facilitant l’utilisation des blobs à partir de notre smartphone grâce à la librairie WindowsPhoneCloud.StorageClient.dll
Pour commencer simplement, vous pouvez partir d’un sample de code issu du toolkit qui ne cible que la partie storage (merci Wade). Les credentials sont placés dans les ressources de l’application et sont donc visibles par tout un chacun, ce qui n’est pas recommandé. Mais dans un premier temps, on s’en contentera pour simplifier.
Grâce à la classe CloudBlobClient fournie dans WindowsPhoneCloud.StorageClient.dll, l’upload de la photo (propriété PhotoStream de type Stream) s’effectue ainsi :
public void UploadPhoto(Action callback = null) { this.IsUploading = true; this.blobClient.Upload( this.BlobName, this.PhotoStream, r => this.dispatcher.BeginInvoke( () => { this.IsUploading = false; if (r.Exception == null) { MessageBox.Show( string.Format(CultureInfo.InvariantCulture, "Image file {0} successfully uploaded!", this.BlobName), "Upload Photo Result", MessageBoxButton.OK); if (callback != null) { callback.Invoke(); } } else { MessageBox.Show( string.Format( CultureInfo.InvariantCulture, "Error: {0}", r.Exception.Message), "Upload Photo Result", MessageBoxButton.OK); } })); } }
La version complète du toolkit vous permet de réaliser la même opération en version sécurisée, en ajoutant un service qui fait office de proxy d’authentification. C’est lui qui contiendra les credentials plutôt que votre application WP7 !
Le toolkit le plus utilisé est sans conteste le Silverlight Toolkit pour WP disponible sur codeplex.
J’ai utilisé :
J’avais également besoin d’un contrôle Rating et j’ai réutilisé celui-ci (sur codeplex) qui n’est pas prévu pour WP7, mais qui fonctionne bien du moment que l’on désactive le contrôle pendant une gesture. Un Rating control est également disponible dans le Silverlight Toolkit, mais je ne l’ai pas essayé dans le cadre d’une application WP.
Le Coding4fun Tools est également très sympa (surtout qu’un de mes propres contrôles y a été intégré ). Vous y trouverez un menu about, un colorpicker, etc, …
Faites votre marché
Avec WP7.1, il est ultra simple de rendre vos tuiles dynamiques.
Un simple appel de méthode permet de mettre à jour une ou les deux faces de la tuile associée à votre application. Pour la Cave à Vins, la 1ère face affiche le nom de l’application, un petit dessin ainsi que le nombre total de bouteilles de votre cave. La 2ème face affiche le nom de la dernière bouteille achetée. Et c’est aussi simple que :
public void CreateApplicationTile(IEnumerable<MyWine> bottles = null) { var appTile = ShellTile.ActiveTiles.First(); if (appTile != null) { var standardTile = new StandardTileData { Title = "Cave A Vins", BackgroundImage = new Uri("/icons/tileBackground2.png", UriKind.Relative), BackTitle = "Dernier achat", }; if (bottles != null) { standardTile.Count = bottles.Sum(b => b.Count); if (bottles.Any()) { standardTile.BackContent = bottles.OrderByDescending(w => w.AddedDate) .First() .WineInfos.Name; } } appTile.Update(standardTile); } }
Côté pile, un MAGNIFIQUE petit dessin ainsi que le nombre total de bouteilles de votre cave :
Côté face : la dernière bouteille achetée
Voilà, tous les points sensibles de l’application sont maintenant exposés et détaillés. Je ne ferai pas de tutoriel pas à pas pour chacun des points, mais si vous rencontrez des difficultés avec l’un d’entre eux, je peux tout à fait développer le sujet dans un autre article.
Reste à peaufiner l’application, à la localiser et à gérer le tombstoning correctement (notamment en ce qui concerne WCF Data Services).
Dans le prochain article, nous verrons comment retrouver une bouteille à partir de la photo de son code barre et profiter ainsi des bouteilles déjà saisies par la communauté des utilisateur de l’application CaveAVins.
Un petit mot pour vous présenter les deux tutoriels qui vous permettront de faire migrer la base de données ainsi que le service de publication dans Azure.
Architecture On Premises :
Après la mise en pratique des deux tutoriels:
- CaveAVins Tutoriel 3 : Migration d’une base SQL Server vers SQL Azure - CaveAVins Tutoriel 4 : Hébergement du service WCF Data Services dans Azure
On obtient l’architecture suivante:
Le service OData publiant les données de la cave à vins est maintenant en ligne : http://stephecaveavins.cloudapp.net/CaveAVinsDataService.svc
Vous pouvez l’utiliser très simplement dans un projet Visual Studio en faisant un “Add Service Reference”, ou sur d’autres plateformes clientes grâces aux différents helpers : http://www.odata.org/developers/odata-sdk.
Le prochain article sera consacré à l’application CaveAVins pour Windows Phone 7.1. : avec Mango, c’est encore plus simple d’utiliser un service OData !
Petit rappel vite fait pour vous attaquer aux nouveautés de Windows Phone 7.1 (Mango)…
Et aussi pour les apps existantes :
Après la migration des données dans SQL Azure effectuée dans le précédent tutoriel, c’est au tour du service WCF Data Services de publication des données d’être hébergé sur la plateforme Cloud. Il sera ainsi accessible facilement depuis l’extérieur, y compris par un smartphone.
Les étapes décrites dans ce tutoriel sont valables pour n’importe quelle ASP.Net Web Application.
Nous irons “de là”
à “de là”:
- CaveAVins Tutoriel 1 : L’accès aux données avec Sql Server et EF Code First - CaveAVins Tutoriel 2 : La publication des données en OData avec WCF Data Services - CaveAVins Tutoriel 3 : Migration d’une base SQL Server vers SQL Azure - CaveAVins Tutoriel 4 : Hébergement du service WCF Data Services dans Azure (vous êtes ici )
<connectionStrings> <add name="CaveAVinsContext" connectionString="Server=tcp:oy7122pvo6.database.windows.net,1433;Database=CaveAVins.Db.Azure; User ID=stephe@oy7122pvo6;Password=myPassword;Trusted_Connection=False;Encrypt=True;" providerName="System.Data.SqlClient"/> </connectionStrings>
Ouvrez la solution CaveAVins dans Visual Studio.
Modifiez les propriétés de l’application Web de manière à ce qu’elle se positionne directement sur le service OData au démarrage:
Ajoutez un nouveau projet de type Windows Azure.
Appelez-le CaveAVins.Azure et cliquez sur OK.
Visual Studio nous propose d’ajouter de nouveaux projets pour les associer à des rôles, mais comme c’est un projet Web existant que nous souhaitons héberger dans Azure, nous avons déjà ce qu’il nous faut.
Le nouveau projet Azure est ajouté à la solution. Remarquez que le répertoire “Roles” est vide. Nous allons donc associer un web role au projet web existant : CaveAVins.WebApplication.
Faites un clic droit sur “Roles” et ajoutez un nouveau web role pour un projet de la solution
Notre projet CaveAVins.WebApplication apparait, et nous le sélectionnons.
Notre web role apparait dans le projet Azure : il sera hébergé sur la plateforme lors du déploiement.
En exécutant votre application (en veillant bien à ce que le projet de démarrage soit CaveAVins.Azure), l’émulateur Azure hébergera votre service. Vous avez accès à l’instance à travers la console de l’émulateur. Vous la trouverez dans les icones en bas à droite de votre écran:
Le service apparait dans la page lors du lancement :
Maintenant que le service fonctionne dans l’émulateur, déployons le réellement dans Azure.
Avant de déployer, modifions le nombre d’instances configurés pour le service et passons-le à 2.
En effet, les caractéristiques de haute disponibilité d’Azure ne peuvent être garanties si vous ne déployez qu’une seule instance, et d’ailleurs la console d’administration vous préviendra de ce risque, comme ci-dessous :
Pour vous familiariser avec le portail Azure, je vous conseille les fiches pratiques : Premiers Pas dans l’administration de Windows Azure.
Nous modifions également la taille de la VM pour choisir le minimum correspondant à nos besoins et faire ainsi baisser le cout de mon hébergement.
Puis nous désactivons les options de diagnostique. Pour les utiliser sur Azure, il faudra modifier la valeur par défaut pour l’associer à votre compte de stockage azure.
Pour que les librairies spécifiques à notre projet soient incluses dans le package Azure, il faut activer la copie locale, dans les propriétés. Dans notre, cas il faudra l’appliquer à CaveAVins.Db et à EntityFramework.
Compilez (F6), faites un clic droit sur le projet Azure et choisissez “Publish”
Vous allez pouvoir travailler directement dans dans Visual Studio pour vos projets Azure, que ce soit pour le développement ou pour le déploiement. Mais pour cela il faut commencer par associer votre projet à votre compte Azure et environnement de travail (stockage, service host).
Pour un premier déploiement, il vous faut donc accéder au portail Azure pour créer un Storage…
…ainsi qu’un nouveau Hosted Service.
Lorsque vous créerez le hosted service qui servira à héberger votre projet, il faudra décocher l’option de publication par défaut, puisque c’est à partir de Visual Studio que nous orchestrerons tout cela:
Si vous êtes perdus, suivez les étapes qui sont plus détaillées dans la fiche pratique de création d’un nouveau service
Revenons à présent à notre déploiement depuis Visual Studio et créons les informations d’authentification nécessaires pour que l’utilisation du compte Azure puisse se faire.
Ensuite suivez les étapes 2 et 3 indiquées sur la page, à savoir copier le chemin vers le certificat qui a été créé localement sur la machine.
L’ajouter dans le portail Azure
Copier le “subscription ID” comme demandé à l’étape 3, que vous trouverez ici:
On y arrive !
Par défaut, le déploiement est proposé dans l’environnement de staging (pré-production), ce qui nous convient bien pour le moment.
Le déploiement sur Azure prendra un peu de temps, et vous pouvez évaluer l’avancement dans l’”Azure Activity Log” de Visual Studio.
Ou dans l’explorateur de serveur toujours dans Visual Studio.
Ou encore directement dans le portail Azure.
Vos efforts sont payants : la prochaine fois que vous modifierez votre service et que vous voudrez le déployer, cela se fera en un clic…(bon disons deux : ”Publish” et “Ok”).
Vous pouvez aussi utiliser Web Deploy pour le déploiement dans Azure, grâce à Windows Azure Accelerator for Web Role.
Votre service est maintenant prêt à être utilisé à l’adresse de staging : http://db4da25d018242349e92ad4b830b162b.cloudapp.net/CaveAVinsDataService.svc
Vous pouvez passer votre service en production en publiant sur l’environnement de production dans Visual Studio ou en passant le service de pré-prod en production par le portail Azure :
Une fois l’opération réalisée, le service est disponible en production, et donc disponible à travers l’URL fixe http://stephecaveavins.cloudapp.net/CaveAVinsDataService.svc
Cliquez sur http://stephecaveavins.cloudapp.net/CaveAVinsDataService.svc pour accéder au service.
Et voilà !
Notre architecture devient:
Nous pouvons maintenant accéder aux données à partir d’une application Windows Phone : c’est le sujet de nos prochains tutoriels.
Ce tutoriel montre comment migrer une base de données SQL Server existante vers SQL Azure. Il a été écrit dans le cadre d’une suite d’articles mais la procédure est exactement la même pour n’importe quelle base SQL Server et vous pouvez donc la suivre indépendamment des exemples proposés.
Dans notre projet démarré from scratch, nous sommes arrivés au stade suivant:
Pour pouvoir accéder à nos données depuis un téléphone, il nous faut les héberger sur un serveur accessible depuis l’extérieur. Dans notre cas, nous décidons d’utiliser la plateforme Azure, les motivations de ce choix sont détaillées dans l’article Architecture et découpage du projet . Nous verrons qu’il est très simple de migrer un projet existant vers Azure. Dans notre cas, nous migrerons 2 éléments différents:
Dans ce tutoriel, nous commencerons par migrer la base de données Sql Server vers Sql Azure. Si ceci est votre première expérience de la plateforme, nous créerons également le serveur Sql Azure en pas à pas. Nous modifierons la chaine de connexion du service WCF Data Services : le service fonctionnera toujours, mais en adressant cette fois Sql Azure. Nous obtiendrons l’architecture suivante à la fin de ce tutoriel:
Puis nous migrerons le service WCF Data Services vers la plateforme Azure sous la forme d’un web role dans le tutoriel suivant.
- CaveAVins Tutoriel 1 : L’accès aux données avec Sql Server et EF Code First - CaveAVins Tutoriel 2 : La publication des données en OData avec WCF Data Services - CaveAVins Tutoriel 3 : Migration d’une base SQL Server vers SQL Azure (vous êtes ici ) - CaveAVins Tutoriel 4 : Hébergement du service WCF Data Services dans Azure
Un outil de migration téléchargeable sur codeplex va vous permettre d’effectuer cette opération en quelques clics :
SQL Azure Migration Wizard
Une fois le fichier décompressé, lancez l’application.
Sélectionnez “Analyser et migrer base de données SQL”
Entrez le serveur SQL utilisé pour le stockage des données et cliquez sur “Connecter”.
Choisissez CaveAVins.Db.CaveAVinsContext. C’est le nom de la base de données qui a été générée par Entity Framework Code First.
Puis cliquez sur “Suivant”
Choisissez de scripter tous les objets : c’est le choix par défaut.
Voici un dernier rappel des éléments qui seront générés.
L’outil s’occupe de générer les scripts adéquats.
A présent, ces scripts vont être utilisés avec votre compte Azure pour générer la base de données Sql Azure correspondante.
Pour renseigner ces informations, vous aurez besoin d’un serveur Sql Azure sur lequel créer votre base de données. Si vous n’avez pas encore créé de serveur, réalisez les étapes du chapitre suivant.
Si c’est la première fois que vous utilisez Sql Azure, il vous faudra suivre les étapes suivantes.
Accédez au portail Azure et connectez-vous avec le live Id que vous avez utilisé pour créer votre compte Azure.
Sélectionnez “Base de données” ainsi que votre abonnement, puis cliquez sur “Créer”.
Sélectionnez la zone géographique la plus proche : “West Europe”.
Choisissez votre identifiant et mot de passe.
Ajoutez une règle autorisant n’importe à quelle machine – y compris Azure – à accéder à la base.
Votre serveur Sql Azure est créé et apparait maintenant dans le portail.
Vous pouvez repasser sur l’assistant de migration et compléter les champs avec les informations correspondantes apparaissant sur le portail :
Cliquez sur “Connecter”.
Puis sur “Créer la base”.
Entrez le nom de la base de données que vous souhaitez créer.
Cliquez sur “Suivant”.
La migration est terminée. Retournez sur le portail Azure, vous verrez apparaitre votre base de données.
Pour que notre service adresse la base de données SQL Azure, il suffit de modifier la chaine de connexion, que vous trouverez sur la droite du portail.
Cliquez sur “Afficher”.
Copiez la chaine de connexion ADO.Net et ajoutez-la dans une nouvelle section “connectionStrings” dans le web.config de notre service, comme ceci:
<connectionStrings> <add name="CaveAVinsContext" connectionString="Server=tcp:oy7122pvo6.database.windows.net,1433;Database=CaveAVins.Db.Azure;User ID=stephe@oy7122pvo6;Password=myPassword;Trusted_Connection=False;Encrypt=True;" providerName="System.Data.SqlClient"/> </connectionStrings>
Le nom de la chaine de connexion est important, puisqu’il doit correspondre au nom du contexte EF Code First associé à notre base de données, dans notre cas : CaveAVinsContext.
Relancez le service : il accède maintenant à notre base de données Sql Azure !
Pour le prouver, ajoutons une ligne dans la table Wines, par l’intermédiaire de l’outil d’administration en ligne de Windows Azure:
Exécutons notre service et consultons la liste des vins à l’adresse: http://localhost:5972/CaveAVinsDataService.svc/Wines
Passons maintenant à la migration du service WCF Data Services. C’est ce que nous verrons dans le tutoriel suivant.
Voici le deuxième tutoriel de la série dans lequel nous mettrons en place la publication des données dans le format OData qui est très interopérable. Pour cela, nous utiliserons WCF Data Services qui est une implémentation de OData pour .Net. Nous verrons qu’il est très simple de créer un service WCF Data Services à partir d’un projet Entity Framework.
- CaveAVins Tutoriel 1 : L’accès aux données avec Sql Server et EF Code First - CaveAVins Tutoriel 2 : La publication des données en OData avec WCF Data Services (vous êtes ici ) - CaveAVins Tutoriel 3 : Migration d’une base SQL Server vers SQL Azure - CaveAVins Tutoriel 4 : Hébergement du service WCF Data Services dans Azure
La version Code First de Entity Framework est très récente et son utilisation entraine encore quelques opérations manuelles dans la configuration du projet pour un bon fonctionnement avec WCF Data Services. Ce “tuning” manuel représente une grande partie de l’article et vous pourrez heureusement bientôt vous affranchir de ces étapes.
Pour ce tutoriel, vous aurez besoin d’installer :
- Visual Studio 2010 Express, Premium ou Ultimate (pour tester les diagrammes d’architecture, Use Case, …) - Entity Framework 4.1 - EF Power Tools (CTP 1) - WCF Data Services 4.0 étant sorti avant EF 4.1, il nous faudra télécharger et installer WCF Data Services 2011 CTP2 qui sait prendre en charge la classe DbContext de EF Code First.
- Visual Studio 2010 Express, Premium ou Ultimate (pour tester les diagrammes d’architecture, Use Case, …)
- Entity Framework 4.1
- EF Power Tools (CTP 1)
- WCF Data Services 4.0 étant sorti avant EF 4.1, il nous faudra télécharger et installer WCF Data Services 2011 CTP2 qui sait prendre en charge la classe DbContext de EF Code First.
- Nous partons du résultat de notre précédent tutoriel dont vous pouvez télécharger les sources ici:
- Ouvrez la solution CaveAVins.sln dans Visual Studio 2010
- Dans la solution, ajoutez un projet Web de type ASP.Net Empty Web Application appelé CaveAVins.WebApplication
- Ajoutez un nouvel élément Web de type WCF Data Service dans le projet CaveAVins.WebApplication.
- Le template WCF Data Service qui vient d’être utilisé n’a pas été mis à jour avec la CTP2 et ne pointe donc pas vers les dernières assemblies. Nous allons y remédier manuellement:
- Supprimez les références vers System.Data.Services et System.Data.Services.Client qui sont de version 4:
- Ajoutez manuellement les mêmes assemblies mais de version supérieure qui se trouvent dans C:\Program Files (x86)\WCF Data Services Mar 2011 CTP2\bin\.NETFramework\
- Supprimez la référence existante à l’assemblie Entity Framework 4.0 pour en ajouter une vers la version 4.1 de Entity Framework
- Ajoutez une référence vers le projet CaveAVins.Db. C’est dans ce projet que se trouve la couche ORM Entity Framework et dans lequel se trouve la classe DbContext pour notre cave à vins : CaveAVinsContext.
- Un nouveau service CaveAVinsDataServices.svc a été crée :
- Ouvrez le fichier CaveAVinsDataService.svc.cs
- Il reste à spécifier le contexte Entity Framework sur lequel s’appuyer : c’est à dire la classe définie dans le tutoriel précédent et qui aggrège nos entités Wines et Bottles sur laquelle nous autorisons des accès complets CRUD:
using System; using System.Collections.Generic; using System.Data.Services; using System.Data.Services.Common; using System.Linq; using System.ServiceModel.Web; using System.Web; namespace CaveAVins.WebApplication { public class CaveAVinsDataService : DataService<CaveAVins.Db.CaveAVinsContext> { // This method is called only once to initialize service-wide policies. public static void InitializeService(DataServiceConfiguration config) { config.SetEntitySetAccessRule("Wines", EntitySetRights.All); config.SetEntitySetAccessRule("Bottles", EntitySetRights.All); config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2; } } }
- Il faut également modifier la version de WCF Data Services supportée:
using System; using System.Collections.Generic; using System.Data.Services; using System.Data.Services.Common; using System.Linq; using System.ServiceModel.Web; using System.Web; namespace CaveAVins.WebApplication { public class CaveAVinsDataService : DataService<CaveAVins.Db.CaveAVinsContext> { // This method is called only once to initialize service-wide policies. public static void InitializeService(DataServiceConfiguration config) { config.SetEntitySetAccessRule("Wines", EntitySetRights.All); config.SetEntitySetAccessRule("Bottles", EntitySetRights.All); config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3; } } }
C’est fini !
- Définissez le projet Web comme projet de démarrage.
- Spécifiez le service CaveAVinsDataService.svc comme page de démarrage dans les propriétés Web du projet.
Par défaut, le service est hébergé dans le serveur de développement de Visual Studio.
Lancez l’application.
L’adresse “racine” du service http://localhost:5972/CaveAVinsDataService.svc nous renvoie l’index des collections disponibles.
On peut parcourir les données directement dans le browser web, à partir d’une requête OData sur notre service.
Par-exemple : http://localhost:5972/CaveAVinsDataService.svc/Wines/$count permet de compter le nombre d’élements de la liste des vins Wines :
Et pour récupérer la liste des vins et leurs propriétés : http://localhost:5972/CaveAVinsDataService.svc/Wines
Dans l’article dédié à l’authentification, nous verrons comment intercepter les requêtes grâce aux Query Interceptors pour adapter nos réponse en fonction de l’utilisateur qui émet la requête.
WCF Data Services va également nous faciliter l’utilisation de ce service côté client .Net, en nous permettant :
- d’ajouter une référence au service et en générant automatiquement les classes proxy correspondant aux types utilisés dans le service. Pour la petite histoire, c’est grâce au suffixe $metadata (http://localhost:5972/CaveAVinsDataService.svc/$metadata) que cette opération est possible. En effet, il permet d’obtenir le dictionnaire des entités et associations utilisés dans le service :
- d’utiliser Linq sur les entités, pour spécifier les requêtes qui seront transformées automatiquement en Uri OData par le provider
Vous trouverez un exemple concret de client Silverlight qui exploite un service WCF Data Services dans l’article Tutoriel : Accéder aux listes Sharepoint 2010 par OData en Silverlight. Dans cet article, les données proviennent de Sharepoint qui propose un accès OData de ses listes et bibliothèques, mais ça ne change rien en ce qui concerne l’exploitation de ce service côté client.
Un service web WCF Data Services permettant de manipuler les données a été mis en place. Grâce à lui, les données sont accessibles en OData par toute plateforme cliente qui sait communiquer en http et parser du XML : difficile de faire plus interopérable .
Il est temps à présent de faire bon usage de ces données.
Voici les sources à l’issue de ce second tutoriel:
Rendez vous après quelques vacances pour la suite !
Cet article est le troisième d’une série qui se propose d’introduire les techniques de développement actuelles, dans le cadre d’un besoin et d’un projet concret. Dans ce volet, nous nous intéressons à la publication des données sur le réseau pour les rendre accessibles à des services ou application clientes.
Notre prétexte métier est un projet de gestion de cave à vins, avec des applications pour le poste de travail et pour Windows Phone. Retrouvez la description du besoin dans le premier article de la série.
Et les tutoriels correspondants qui arriveront au fil de l’eau:
- CaveAVins Tutoriel 1 : L’accès aux données avec Sql Server et EF Code First - CaveAVins Tutoriel 2 : La publication des données en OData avec WCF Data Services (tutoriel correspondant à cet article ) - CaveAVins Tutoriel 3 : Migration d’une base SQL Server vers SQL Azure - CaveAVins Tutoriel 4 : Hébergement du service WCF Data Services dans Azure
- L’hébergement des données, des services et applications se fera dans Windows Azure et Sql Azure - La publication des données sera faite en OData avec WCF Data Services pour rester interopérable avec une grande variété de plateformes clientes - Les applications clientes seront développées en Silverlight - Nous nous efforcerons de conserver un maximum de code commun entre les 2 applications grâce à la Portable Library - Les promotions seront notifiées sur le téléphone par un service de gestion des promotions et des notifications Push
Pour faciliter la mise en pratique de la série de tutoriels, nous commencerons par mettre en place un fonctionnement On Premises (un hébergement sur des serveurs classiques), pour faire migrer la solution plus tard dans Sql Azure. Ainsi, nous obtiendrons un projet qui fonctionnera aussi bien On Premises que dans le Cloud. Cela permettra également de montrer la simplicité avec laquelle des solutions existantes peuvent évoluer vers un hébergement dans Azure.
A ce stade, nous avons réalisé le stockage et couche d’accès aux données (mapping ORM).
Pour que les données soient accessibles par des applications clientes, il faut les mettre à disposition sous la forme d’un service. Il y a différentes manières d’effectuer cette opération en fonction des plateformes clientes adressées. Dans notre cas, nos clients seront:
Chez Microsoft, les 2 principales technologies de services orientées données sont :
En résumé, cette technologie permet de masquer la communication entre le client et le serveur et de reporter automatiquement les règles métiers de validation des données côté client. C’est une technologie de haut niveau qui améliore la productivité du développement Silverlight puisque les règles métiers ne sont codées qu’une seule fois côté serveur.
Pour découvrir et comprendre RIA Services, voici quelques articles et vidéos :
WCF RIA Services est dédié à Silverlight classique uniquement, ce qui exclut son utilisation sur Windows Phone. Mais il offre également des endpoints plus limités de type SOAP, JSON, OData (en lecture seule ) pour laisser la possibilité à d’autres plateformes de consommer les données. Je vous conseille les excellents articles de David sur le sujet : Comment exposer une application WCF RIA Services à d’autres clients ?
WCF Data Service est une implémentation pour .Net de OData. Mais c’est quoi à la fin OData ? En résumé, cette technologie permet de mettre des données en ligne, de manière très interopérable c’est à dire accessibles de la même manière par toutes sortes de plateformes clientes.
On bénéficie d’un typage fort des données ainsi que du requêtage à la source.
Par-rapport à WCF RIA Services et en caricaturant, on pourrait dire que l’on troque la productivité contre l’interopérabilité.
- Sur mon client WP, je ne peux pas me permettre d’utiliser le endpoint OData de WCF RIA Services, car celui-ci propose un accès aux données en Read Only uniquement . Or j’aurai besoin d’accès en lecture/écriture sur mes données…. - Côté client : je souhaite partager un maximum de code entre les plateformes, ou au moins utiliser une seule technique pour accéder à mes données plutôt que de devoir en apprendre plusieurs. Or, avec RIA Services, mes clients utiliseront RIA Services lui-même (pour Silverlight), mais aussi les endpoints SOAP, JSON en fonction des plateformes applicatives. - Côté serveur : si tous mes clients utilisent le même point d’entrée, mon jeu de tests unitaires et fonctionnels en sera réduit d’autant
- Sur mon client WP, je ne peux pas me permettre d’utiliser le endpoint OData de WCF RIA Services, car celui-ci propose un accès aux données en Read Only uniquement . Or j’aurai besoin d’accès en lecture/écriture sur mes données….
- Côté client : je souhaite partager un maximum de code entre les plateformes, ou au moins utiliser une seule technique pour accéder à mes données plutôt que de devoir en apprendre plusieurs. Or, avec RIA Services, mes clients utiliseront RIA Services lui-même (pour Silverlight), mais aussi les endpoints SOAP, JSON en fonction des plateformes applicatives.
- Côté serveur : si tous mes clients utilisent le même point d’entrée, mon jeu de tests unitaires et fonctionnels en sera réduit d’autant
Ce choix est tout à fait discutable et les arguments sont à mettre en balance avec la productivité apportée par WCF RIA Services. Si notre application principale en Silverlight, était très complète en terme d’accès aux données et que les applications sur devices nomades reprennent simplement quelques vues de synthèse, on pourrait faire un choix différent.
Tout est une question de compromis et le choix se fait en fonction des contraintes, des priorités et des besoins d’évolutivité de votre projet.
Pour aller plus loin, je vous conseille la vidéo de la session dédiée à ce sujet que nous avons présentée aux Techdays avec David Rousset : Choisir une technologie d’accès aux données distantes qui compare WCF, WCF Data Services et WCF RIA Services.
C’est du charabia ? C’est normal, vous verrez tout cela dans le tutoriel qui vous guidera pas à pas.
Il est noter que WCF Data Services peut tout à fait publier des sources de données autres que Entity Framework comme on peut le voir sur le diagramme suivant:
Avec WCF Data Services, vous pourrez moduler les droits d’accès à vos données en fonction de vos entités (par-exemple, on pourrait imaginer une entité “producteurs” qui serait en lecture seule). Vous pouvez également aller beaucoup plus loin en définissant des méthodes d’interception des requêtes. Ce mécanisme vous permet d’adapter le résultat de la requête en fonction du contexte ou de règles métier. On pourra par-exemple faire en sorte que seul l’auteur d’une review ait le droit le la modifier, mais que tout le monde ait le droit de la consulter.
Nous aborderons ce sujet dans l’article consacré à l’authentification avec Access Control Services.
A travers SQL Azure Labs, Sql Azure fournit également une ouverture au format OData de ses données, mais :
En gros, vous perdez en souplesse, mais vous gagnez en rapidité de développement.
Voici le tutoriel associé pour mettre WCF Data Services en pratique dans le contexte de notre cave à vins.
Au final, nous obtenons un service web qui à partir d’une URI Http (REST) correspondant à une requête CRUD (Create/Read/Update/Delete), effectue l’opération demandée sur les données stockées en base. Pour une requête de sélection, le service renvoie la collection d’objets résultante sous la forme d’un flux XML (Atom ou JSON).
Nous pouvons donc utiliser un navigateur web comme un client de ce service, et requêter les données directement. Ainsi, si l’on tape l’URL du service dans le navigateur : http://localhost:33880/CaveAVinsOData.svc/ on obtient l’index des collections publiées pour notre projet de cave à vins:
Un service web WCF Data Services a été mis en place. Pour l��instant il est hébergé dans IIS (ou plutôt dans le serveur de test de Visual Studio !). Grâce à lui, les données sont accessibles en OData par toute plateforme cliente qui sait communiquer en http et parser du XML : difficile de faire plus interopérable .
Dans la version Cloud à venir, c’est Azure qui hébergera ce service sous la forme d’un web role comme nous le verrons dans l’article consacré à la migration.
En résumé, les différences de la version Cloud sont:
- Base de données Sql Azure au lieu de Sql Server - Ajout du web role qui permet de configurer l’hébergement du service dans Azure
- Base de données Sql Azure au lieu de Sql Server
- Ajout du web role qui permet de configurer l’hébergement du service dans Azure
Tout est en place pour permettre la manipulation de ces données à partir de services métiers ou d’applications clientes.
C’est ce que nous verrons un peu de vacances !
Grâce à la DropBox pour Sharepoint, Stephane Eyskens vous propose de pouvoir associer des documents directement à votre profil sous Sharepoint, par simple glisser-déplacer.
La DropBox intègre également une gestion des quotas.
Toutes les informations dans la vidéo explicative, la doc, et l’article blog associé.
Voici le premier tutoriel de la série d’articles qui introduit les technologies de développement actuelles, dans le cadre d’un projet de gestion de cave à vins.
Je ne fournirai probablement pas tout le projet en pas à pas de manière exhaustive, mais j’essaierai de le faire pour toutes les parties clés. Les tutoriels figurent à part des articles classiques pour que les étapes ne soient pas noyées dans la théorie et soient ainsi plus faciles à suivre. Je vous conseille vivement de lire l’article technique qui replace le tutoriel dans le contexte du projet avant d’attaquer l’implémentation :
- CaveAVins Tutoriel 1 : L’accès aux données avec Sql Server et EF Code First (vous êtes ici ) - CaveAVins Tutoriel 2 : La publication des données en OData avec WCF Data Services - CaveAVins Tutoriel 3 : Migration d’une base SQL Server vers SQL Azure - CaveAVins Tutoriel 4 : Hébergement du service WCF Data Services dans Azure
Dans ce tutoriel, nous utiliserons Entity Framework Code First pour décrire notre modèle objet de données par code, sous la forme d’objets simples (POCO). Entity Framework utilisera ces classes pour en déduire une structure de base de données qu’il créera automatiquement dans Sql Server.
Je montrerai volontairement une manière très basique d’utiliser Code First et Entity Framework car le but de cet article n’est pas d’approfondir cette technologie mais de présenter ce qu’elle permet de faire. Pour approfondir le sujet et aller plus loin : cliquez ici
A la fin de ce tutoriel, nous aurons réalisé une couche de données grâce à une base de données dans Sql Server et son mapping ORM.
Pour faciliter la mise en pratique de ce tutoriel, nous commencerons par mettre en place les données dans Sql Server, pour les faire migrer plus tard dans Sql Azure. Ainsi, nous obtiendrons un projet qui fonctionnera aussi bien On Premises que dans le Cloud. Cela permettra également de montrer la simplicité avec laquelle des solutions existantes peuvent évoluer vers un hébergement Cloud.
Téléchargez les sources:
- Visual Studio 2010 Express, Premium ou Ultimate (pour tester les diagrammes d’architecture, Use Case, …) - Entity Framework 4.1 - EF Power Tools (CTP 1).
- EF Power Tools (CTP 1).
Démarrez Visual Studio 2010 et créez une nouvelle solution vide que vous appellerez CaveAVins:
Ajoutez un projet de type Class Library appelé CaveAVins.Db:
Ajoutez une référence vers Entity Framework 4.1:
Avec Entity Code First, on définit directement par code les classes à partir desquelles le moteur de mapping déduira et génèrera la structure de la base de données.
Voici le diagramme des classes que nous allons créer:
Ajoutez les classes suivantes au projet:
Fichier Wine.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CaveAVins.Db { public class Wine { public int WineId { get; set; } public string Name { get; set; } public int Year { get; set; } public string PictureUrl { get; set; } public string Address { get; set; } } }
Fichier MyWine.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CaveAVins.Db { public class MyWine { public int MyWineId { get; set; } public string Review { get; set; } public int Notation { get; set; } public int Count { get; set; } public Wine WineInfos { get; set; } } }
Remarquez que les classes sont de simples POCOs et ne possèdent pas d’attributs particuliers. Nous utilisons la convention de nommage par défaut : la propriété de la classe dont le nom est suffixé par “Id” sera interprété comme la clé de la table correspondante dans la base de données. Il y a différents moyens de configurer le mapping de manière plus avancée, avec des custom attributes ou fluent.
Fichier CaveAVinsContext.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Entity; namespace CaveAVins.Db { public class CaveAVinsContext : DbContext { public DbSet<MyWine> Bottles { get; set; } public DbSet<Wine> Wines { get; set; } } }
Cette fois, nous utilisons des objets spécifiques à Entity : DbContext et DbSet pour le définition des entités. La classe CaveAVinsContext matérialise le contexte d’accès aux données. La première fois que l’on utilisera le contexte, la base de données sera créée. Pour cela, nous allons ajouter un projet de type Application Console, qui nous servira uniquement à faire un premier accès au contexte pour forcer la création de la base.
Ajoutez un projet de type Application Console:
Ajoutez une référence à Entity Framework 4.1 comme pour le projet précédent, et ajoutez également une référence au projet CaveAVins.Db:
Complétez le Main par le code suivant, qui ajoute une ligne dans la table des vins Wines.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Entity; namespace CaveAVins.Db.Setup { class Program { static void Main(string[] args) { Database.SetInitializer<CaveAVinsContext>(new DropCreateDatabaseIfModelChanges<CaveAVinsContext>()); using (var db = new CaveAVinsContext()) { if(! db.Wines.Any()) { var wine = new Wine() { Name = "Test" }; db.Wines.Add(wine); db.SaveChanges(); } } } } } Définissez le projet de type console comme projet de démarrage (clic droit sur le projet : Set as Startup Project).
Compilez et exécutez la solution.
La première ligne Database.SetInitializer<CaveAVinsContext>(new DropCreateDatabaseIfModelChanges<CaveAVinsContext>()); permet de supprimer la base de données si elle existe déjà (pour ne pas déclencher d’exception, dans le cas où vous exécuteriez plusieurs fois l’application alors que vous avez modifié la structure des données).
Si tout s’est bien déroulé, la base de données a été créée. Pour le vérifier, ajoutez une nouvelle connexion dans l’explorateur de serveurs de Visual Studio:
Entrez “.\SQLEXPRESS” pour Server Name et choisissez le nom de la base de données CaveAVins.Db.CaveAVinsContext qui devrait apparaitre dans la liste déroulante.
Et voici notre base de données ! :
Avec notre unique ligne dans la table Wines:
Pour faciliter la manipulation et la maintenance de votre mapping de type Code First, vous pouvez télécharger les EF Power Tools (CTP 1) accessibles dans l’extension Manager de Visual Studio.
Redémarrez Visual Studio et rechargez la solution.
Faites un clic droit sur le fichier CaveAVinsContext.cs, sélectionnez Entity Framework/View Entity Data Model
Le modèle objet apparait par dans l’outil de modélisation de Visual Studio .
Voici notre architecture actuelle:
La prochaine étape sera la publication des données en OData avec WCF Data Services. Les données seront ainsi accessibles par les applications clientes, ou par des services métiers de plus haut niveau qui pourront être hébergés dans Azure.
Dépassé par les technos ? Pas le temps de faire de veille ? Trop de boulot pour passer du temps à vous former sur ce qui ne vous concerne pas directement ? Un nouveau projet à démarrer ?
Et quand bien même vous décideriez de remettre le pied à l’étrier et rattraper le temps perdu, par où allez-vous commencer ? Creuser les technos une à une, sans savoir vraiment comment elles se positionnent dans le cadre d’un projet concret…avouons que c’est assez décourageant.
Cette suite d’articles se propose d’introduire les techniques de développement actuelles, dans le cadre d’un besoin et d’un projet concret. Notre prétexte métier est un projet de gestion de cave à vins, avec des applications pour le poste de travail et pour Windows Phone. Retrouvez la description du besoin dans le premier article de la série.
Pour faciliter la mise en pratique de la série de tutoriels, nous commencerons par mettre en place un fonctionnement OnPremises, pour faire migrer la solution plus tard dans Sql Azure. Ainsi, nous obtiendrons un projet qui fonctionnera aussi bien On Premises que dans le Cloud. Cela permettra également de montrer la simplicité avec laquelle des solutions existantes peuvent évoluer vers un hébergement dans Azure.
Nous commençons par nous intéresser au stockage des informations puisque c’est autour des données que va structurer notre solution.
Le stockage des données se fera dans une base de données relationnelle “cloud” de Microsoft : Sql Azure. Le choix du “cloud” et de la plateforme Azure en général est étayé dans l’article précédent, au chapitre “Hébergement des données, des services et des applications”.
Avant de partir tête baissée vers une solution Azure, il est prudent de vérifier le cout financier qu’engendre ce choix. Plusieurs outils sont à votre disposition pour vous aider à l’évaluer:
- Pricing Calculator pour déterminer le cout mensuel des éléments Azure utilisés - TCO Calculator pour une estimation du ROI
Mais avant de choisir quels éléments de la plateforme vont nous êtes utiles, il faut déterminer les types d’informations dont nous aurons besoin.
Pour ne pas alourdir les articles, nous partons sur un scénario simplissime. Un vin est défini par:
un nom
une année
une photo de la bouteille
une adresse de producteur
Une cave à vin est définie par une liste de vins avec pour chacun:
un nombre de bouteilles
une note et un commentaire
A ce stade, nous n’intégrons pas de gestion des utilisateurs dans le système et donc les notations seront anonymes. Nous pourrons envisager d’utiliser des comptes d’identité existants (Live, Google, Facebook, …) grâce à Access Control Services (ACS) disponible dans Azure AppFabric. Cela évitera à l’utilisateur de créer un énième compte qui serait spécifique à cette application, et nous libère de l’aspect gestion des comptes, stockage de mots de passe.
Toutes ces informations sont de type simple et peuvent potentiellement servir de critères de filtre…sauf une et non des moindres : la photo de la bouteille de vin ! Nous pourrions imaginer stocker les photos directement dans la base de données sous la forme d’un type binaire, mais dans la plupart des cas c’est une mauvaise idée pour différentes raisons dont:
Heureusement, Azure propose plusieurs autres mécanismes de stockage de données, dont le Blob, qui nous permettra de stocker les images comme des fichiers plats. Un autre avantage du blob pour les fichiers volumineux : l’option CDN (Content Delivery Network) qui permet d’optimiser l’accès aux données stockées dans les blobs par un mécanisme de cache réparti géographiquement. Pour finir de vous convaincre, voici la différence de tarif estimée avec Pricing Calculator entre :
- un stockage Sql Azure pur de 11 Go - un stockage Sql Azure de 1 Go pour les données et Blob de 10 Go pour les photos
- un stockage Sql Azure pur de 11 Go
- un stockage Sql Azure de 1 Go pour les données et Blob de 10 Go pour les photos
Ce qui nous donne $199.80 contre $11.49 par mois : à nous les blobs !
Nous aborderons dans un prochain post d’autres éléments qui entrent en ligne de compte dans la facturation.
A présent, définissons la structure des données que nous stockerons dans la base. Mais avant de se lancer dans du bon vieux Merise , voici une précision complémentaire:
Si une base de données est composée de tables et de relations, notre code est écrit dans un langage orienté objet où les données sont représentées par des collections d’objets. Pour permettre cette transformation qui n’est pas très naturelle, il existe des technologies dites de “mapping objet-relationnel'” (ORM pour Object Relational Mapping). Un outils ORM permet d’effectuer cette transformation dans un sens comme dans l’autre : de la base de données relationnelle vers un modèle objet et inversement.
Ben oui, comment faisait-on avant de direz-vous ? Eh bien on se fabriquait son propre mapping (voir framework de mapping) à partir d’objets d’accès aux bases de données tels que ADO.Net. En résumé, on le faisait soi-même sans le savoir ! L’inconvénient dans ce cas, c’est que le code de notre application est fortement lié à la structure de la base de données. De plus, les requêtes dont écrites en SQL qui n’est pas compilé, ce qui entraine de risques d’erreurs non contrôlées, à l’exécution.
Microsoft propose 2 technologies de type ORM pour Sql Server/Azure:
Entity Framework est plus souple et plus complet que son homogue car il permet de réaliser des mappings complexes. En effet, alors que Linq To Sql permet un mapping 1 table <-> 1 classe, Entity Framework dispose d’une couche d’abstraction intermédiaire : 1 classe <-> un modèle conceptuel <-> des tables. Cela peut sembler plus complexe, mais dans les faits, même pour des scenarios de mapping simples, la complexité de mise en oeuvre est la même pour les 2 technologies : clic clic clic dans Visual Studio . C’est pourquoi Linq To Sql tend à être de moins en moins utilisé dans les nouveaux projets, même simples : la mise en oeuvre est la même que pour Entity tout en laissant la porte ouverte à des évolutions plus complexes de votre scenario d’accès aux données.
Avec l’un comme l’autre, vous pourrez utiliser Linq pour requêter vos données à la source. En effet, c’est le provider approprié qui transformera votre requête Linq en SQL ! Pour les stressés (qui ont parfois raison de l’être ), il est possible d’être plus intrusif pour vérifier et contrôler comment cette transformation est effectuée mais ce n’est pas le sujet de cet article.
Avec Entity Framework 4.1, lorsque l’on souhaite créer une base de données, il est possible d’adopter 3 approches:
- Database First : Créer la base de données, les tables, relations, contraintes d’intégrité dans Sql Server/Azure et en déduire le modèle objet et les classes correspondantes - Model First : Créer le modèle de données (entités, propriétés de navigation, …) dans le designer Visual Studio et en déduire la structure de la base de données ainsi que les classes correspondantes - Code First : Créer les classes, propriétés par code et en déduire le modèle relationnel correspondant et la structure de la base de données.
- Database First : Créer la base de données, les tables, relations, contraintes d’intégrité dans Sql Server/Azure et en déduire le modèle objet et les classes correspondantes
- Model First : Créer le modèle de données (entités, propriétés de navigation, …) dans le designer Visual Studio et en déduire la structure de la base de données ainsi que les classes correspondantes
- Code First : Créer les classes, propriétés par code et en déduire le modèle relationnel correspondant et la structure de la base de données.
Il n’y a pas de bon ou mauvais choix. Tout dépend de la complexité de votre modèle de données, du fait que vous partez de 0 et de votre sensibilité (plutôt profil dev ou DBA ?). Dans le cas de notre cave à vins, la structure est assez simple et je n’ai pas d’existant. J’ai donc envie d’utiliser l’approche Code First, c’est à dire de créer des classes POCO (Plain Old CLR Object)…parce que j’aime bien maitriser mes classes et qu’elles aient le moins de dépendances possible, pour pouvoir éventuellement les exposer et/ou les réutiliser dans des projets qui n’utiliseraient pas Entity. Cette approche vous plaira certainement si vous avez déjà des classes existantes.
D’un point de vue plus pragmatique, la pure codeuse que je suis reste plus à l’aise et plus rapide à taper du code que de faire clic clic dans l’éditeur pourtant très convivial de Visual Studio .
Par contre, l’approche Code First est assez récente et tous les outils ne sont pas encore disponibles en version finale : si vous êtes frileux, vous pouvez tout à fait tabler sur l’une des 2 autres approches qui ont plus de vécu.
Voici le tutoriel (écrit à part pour ne pas alourdir cet article) qui vous permet de réaliser:
- la création des classes de données en utilisant la syntaxe Code First - la création automatique de la base de données grâce au mapping ORM d’Entity Framework
A partir des classes dont voici le diagramme:
Entity déduit le modèle suivant:
Et crée automatiquement les 2 tables correspondantes dans une base de données Sql Server.
Pour faciliter la mise en pratique de la série de tutoriels, nous commençons par mettre en place un fonctionnement OnPremises, pour faire migrer la solution plus tard dans Sql Azure. Ainsi, nous obtiendrons un projet qui fonctionnera aussi bien On Premises que dans le Cloud. Cela permettra également de montrer la simplicité avec laquelle des solutions existantes peuvent évoluer vers un hébergement dans Azure.
Une série de tutoriels accompagnera ces articles pour mettre en place la solution from scratch.
A ce stade, nous pouvons en tirer le schéma suivant, qui reste plus fonctionnel que technique:
Affinons quelque peu ce besoin en nous intéressant aux cas d’utilisation des applications :
La gestion de sa cave à vins (ajouter/supprimer une bouteille/choisir une bouteille dans sa cave) se fera plus naturellement à partir du téléphone, tout simplement parce qu’on l’a toujours sous la main : pas besoin de démarrer la machine, ouvrir une session, démarrer l’application…soyons honnêtes, une cave à vins sur une application PC sera rarement à jour. De plus, l’ajout d’une bouteille dans la cave se fait en prenant la bouteille en photo, donc encore une fois avec le téléphone. De la même manière, les notifications de promotions sont pertinentes sur le téléphone, puisque c’est bien lorsque l’on part faire ses courses que l’on a envie de connaitre les promotions du moment. A l’inverse, le grand écran de notre poste de travail sera très pratique pour se balader dans le catalogue complet des vins et visualiser une grande quantité de données selon des critères et des filtres que l’on aura précisé. Dans un premier temps, nous répartissons donc nos cas d’utilisations entre les 2 plateformes, de la manière suivante :
Avec Visual Studio 2010 Ultimate, vous avez la possibilité de créer des diagrammes d’architecture, bien pratiques pour la gestion et la documentation de votre projet. A ce stade, il est recommandé de faire un diagramme de Use Case (disponible aussi dans la version Premium de Visual Studio) qui reste très général. Le but est de garder une trace des fonctionnalités principales de chacune des applications, qui pourront être complétées par des use cases plus détaillés au fil de l’analyse. Cela permet également de se poser les bonnes questions ! Ici par-exemple, le vendeur de vin va pouvoir lancer des campagnes de promotions, mais…nous n’avions pas prévu de composant permettant au vendeur d’interagir avec le système… Ce genre d’oubli arrive assez fréquemment, et les diagrammes de use cases sont l’occasion de clarifier le besoin et les différents éléments du système, en accord avec le marketing ou le client. C’est d’autant plus important de ne rien oublier, que l’on doit commencer souvent bien vite (trop vite) à plancher sur un chiffrage .
Nous ajoutons donc un élément du système en charge de la gestion des promotions : Promotions Service.
Maintenant que le besoin est identifié, voyons comment architecturer notre développement.
Nous avons besoin d’évaluer les possibilités en terme de technologie pour le développement des applications. Plusieurs technologies pourraient potentiellement répondre à mon besoin:
- WPF - Silverlight - Html5
J’élimine immédiatement WPF car cette techno présente plusieurs inconvénients dans notre cas: - Je ne peux pas développer en WPF sur Windows Phone, donc cette techno serait réservée à l’application PC. - Comme notre application est publique, il vaut mieux partir sur une technologie web, c’est à dire une application qui ne nécessite pas d’installation spécifique et qui s’exécutera dans un navigateur. Ce n’est pas le cas de WPF pour lequel il faut prévoir une procédure de déploiement (jeu d’installation).
Un gros avantage d’une technologie web, est que les mises à jour successives de l’application sont transparentes pour l’utilisateur. Dans le cas d’une application lourde, il faudrait notifier les utilisateurs à chaque nouvelle version, pour qu’ils réinstallent l’application (quoique cette procédure peut être allégée si on utilise des mécanismes tels que ClickOnce). WPF reste une technologie de choix pour le développement d’applications d’entreprise, qui pourront bénéficier du maximum de fonctionnalités avec un accès complet à .Net et aux périphériques locaux.
Silverlight
Avec Silverlight 5, on atteint un bon compromis fonctionnel et technique grâce à une technologie web qui se rapproche de plus en plus de WPF : mode out of browser, accès aux API non managées par P/Invoke, mode plein écran, accès aux ressources locales de la machine et au disque dur pour les applications signées… Silverlight fonctionne dans les principaux navigateurs (IE, Safari, Firefox, Chrome) et tourne aussi sur Mac. Sur Windows Phone, Silverlight est la techno de développement la plus adaptée pour les applications et permet donc de mettre à contribution les mêmes connaissances sur les 2 plateformes. Avec Mango – la nouvelle version de Windows Phone disponible à l’automne 2011 -, c’est la version 4 de Silverlight qui sera disponible. (Elle prend mieux en charge certains éléments dont nous aurons besoin comme le client WCF Data Services pour l’accès aux données).
Html5
Html5 apporte quant à lui la facilité de déploiement sur des plateformes hétérogènes et donc une excellente portabilité. Malheureusement, cette technologie pêche encore grandement par son manque d’outillage. Ses spécifications ne sont pas encore finalisées et si les plateformes clientes sont adressées facilement, c’est bien la compatibilité de l’application avec les différents navigateurs qu’il va falloir vérifier. Cela doit être pris en charge directement dans notre code et entraine un surcout sensible de la phase de tests. En effet, l’interopérabilité d’Html5 se paie par le fait que le rendu final dépend de l’implémentation qui est faite par le navigateur…et qui serait donc potentiellement différent (ou pas !) pour chaque navigateur. Là où le plug-in Silverlight garantit un rendu identique cross-browser, Html5 nécessite d’être testé sur chaque navigateur et même sur chaque version d’un même navigateur. En fonction des résultats, il faudra prévoir des mécanisme de “fallback” dans le code, c’est à dire de mode dégradé pour les éléments Html5 mal interprétés ou non supportés. Dans tous les cas, même si je décide de partir sur Html5 pour développer une application unique disponible sur mes différents devices (PC, tablette, téléphone, …), le facteur de forme sera très différent en fonction du device et je serai certainement obligée de faire un développement spécifique pour la partie UI pour garantir une bonne expérience utilisateur. Au final, ce que l’on a vraiment intérêt à factoriser ce sont les cas d’utilisation communs, le modèle, l’accès aux données et aux services métier !!!
Choisir aujourd’hui, ne signifie pas que l’on se trompe pour demain Aujourd’hui, sans hésiter, je me tourne vers Silverlight puisque cette technologie me permet de développer pour Windows Phone ainsi que pour PC/Mac. La productivité est excellente grâce à des outils, frameworks et contrôles très évolués et les techniques de développements me sont familières (.Net, XAML, …). Les ergonomies de chacune des applications seront différentes mais les cas d’utilisation communs pourront être factorisés. Rien ne m’empêche de développer une nouvelle application par la suite, dans une technologie différente (application Html5 pour une tablette par exemple), qui saura tirer parti du code fonctionnel que j’aurai écrit côté serveur. Ainsi, on garde la notion d’interopérabilité au mieux entre les clients ayant des plateformes compatibles (assembly ou code commun), et au minimum entre le client et le serveur (services web interopérables, http REST, …).
D’où l’intérêt de bien réfléchir à la répartition du code métier entre le client et le serveur.
L’accès aux données
Nous aurons besoin de stocker les données et de faire en sorte qu’elles soient accessibles facilement par les différentes applications. Donc besoin d’une couche de stockage + une couche de publication des données sur le réseau. Cela consiste à utiliser une base de données (SQL Server par-exemple), à faire un mapping objet/relationnel de celle-ci et à mettre ces collections d’objets à disposition des services métier et des applications clientes.
On souhaite une technologie d’accès aux données interopérable : c’est bingo avec OData et WCF Data Services qui permet justement de publier des données manipulables et requêtables à la source par toutes sortes de plateformes clientes. Petite piqure de rappel : Mais c’est quoi à la fin OData ?
Toute plateforme qui sait communiquer via http et parser un flux xml sera capable de requêter et manipuler ces données. La publication des données en OData nous permet de respecter la notion d’interopérabilité entre les clients et le serveur, ce qui laisse la possibilité à de futures applications d’y accéder facilement quelle que soit la plateforme utilisée.
Plus de détails sur cette partie dans l’article qui lui est consacré.
Restent à positionner les services fonctionnels qui s’appuieront sur la couche d’accès aux données et qui seront utilisés par les différentes applications clientes. Le but sera de pouvoir réutiliser au maximum les cas d’utilisation communs dans les 2 applications pour ne pas coder, tester et maintenir n fois la même fonction dans n applications. La répartition de ces services entre le côté client et le côté serveur se fera lors de l’analyse plus poussée dans les articles suivants.
Les services développés côté serveur devront pouvoir être utilisés par les différentes plateformes clientes (services web interopérables). Pour la partie cliente, les versions de Silverlight ne sont pas les mêmes sur les différentes plateformes qui partageront du code :
- pour WP7, on utilise une version basée sur Silverlight 3 - pour Mango qui sortira cet automne, mais dont les outils de développement sont déjà disponibles en version bêta, c’est Silverlight 4 - pour le poste de travail, c’est Silverlight 4 ou Silverlight 5 en version bêta
A cet effet, le nouveau type de projet : Portable Library permet de partager du code métier entre différentes technologies (WPF, XNA, Silverlight, WP). Choisissez les plateformes cibles concernées par la librairie qui ne pourra ensuite référencer que des assemblies .Net communes à ces plateformes. En gros cela correspond aux fonctionnalités bas niveau du système en passant par la sérialisation, les ObservableCollection (top pour partager des ViewModel ), mais en excluant tout ce qui attrait à l’UI. Nous verrons ce point plus en détail lorsque nous aborderons l’architecture en couches de nos applications clientes.
Notifications des vins en promotion
Selon notre cahier des charges, les alertes promotionnelles sont destinées à l’application Windows Phone. La plupart des smartphones supportent des mécanismes de notifications asynchrones. C’est le cas pour Windows Phone avec les notifications Push. Ce mécanisme permet à une application WP de réagir en fonction d’informations provenant d’un service Microsoft de Push, lui-même prévenu par un service métier fait maison, se chargeant de déterminer et envoyer des évènements de notification. Les notifications Push à destination d’une application arrivent indépendamment du fait que celle-ci soit ou non en cours d’exécution. Ce fonctionnement permet de bénéficier d’une notion d’asynchronisme dans une application sans pour autant vider la batterie du téléphone avec un thread en tâche de fond.
J’ai besoin de serveurs, mettant à disposition mes données et services, en faisant en sorte qu’ils soient disponibles tout le temps. Tout ce petit monde se doit de se porter comme un charme, peu importe le nombre d’utilisateurs. Au démarrage, il y aura certainement peu de clients, mais comme mon concept et mes applications sont révolutionnaires , mon système doit pouvoir supporter la montée en charge. Pour le moment en tout cas, je n’ai aucune idée de la manière dont je devrais dimensionner mes serveurs. En fait, ce qui m’arrangerait, c’est de ne pas avoir de serveurs à installer, maintenir, configurer. Après tout, ce n’est pas mon métier, je préfère mon concentrer sur les applications. C’est justement ce que permet de faire Windows Azure, la plateforme Cloud de Microsoft. Qui dit plateforme, dit que toute la partie infrastructure est déjà prête à l’emploi, mettant à disposition un environnement, un framework de développement et des services. Par-rapport à un développement qui est hébergé sur un serveur au sens classique du terme, on utilisera des éléments inhérents à la plateforme Azure, en terme de stockage et de publication. Vous me direz, la belle affaire, mais pourquoi y aurait-il des différences entre mon développement classique et un développement Azure ? Eh bien justement, tout simplement pour pouvoir garantir la possibilité au système de monter en charge, de supporter les pannes matérielles, sans impacter sa disponibilité. Avec un développement classique hébergé sur un serveur, vos données sont stockées localement. Il faut prévoir au minimum des mécanismes de redondance pour supporter une panne matérielle. Si vous avez besoin de plus de ressources et décidez d’ajouter un serveur, comment allez vous répartir la charge sur ces serveurs, partager les données, sans interrompre l’accès à vos services ?
Avec Azure, le principe est de ne pas faire de stockage local sur une machine (on parle en fait d’instance), mais sur des éléments persistants fournis pas la plateforme Azure, qui seront accessibles par les différentes instances quel qu’en soit le nombre. Si une instance redémarre, le système fonctionne toujours et c’est transparent pour l’utilisateur. Finalement, on s’abstrait de la notion de machine et on se concentre sur les applications et les services ainsi que les systèmes de stockage. Les questions d’hébergement, de redondance, d’installation et de maintenance de serveurs n’existent plus en tant que tel. On a intégré ce besoin d’élasticité et de disponibilité directement au niveau de la conception des applications. Notre application et nos services sont prêts une fois pour toute à fonctionner aussi bien au ralenti qu’à pleine charge, en fonction du nombre et de la taille des instances qui leur auront été attribués. La tarification se fait en fonction des critères de volume, bande passante, nombre et taille des instances : plus d’information sur la tarification.
Autre avantage : l’environnement Azure est intégré dans Visual Studio, ce qui permet au développeur de travailler dans un seul et même outil que ce soit pour le développement ou le déploiement de ses applications. Aucun dépaysement pour le développeur en ce qui concerne le stockage de données puisque la base de données SQL Azure s’utilise exactement comme son cousin SQL Server. On peut utiliser les outils classiques de SQL Server pour administrer une base de données “dans les nuages”, simplement en précisant la chaine de connexion SQL Azure correspondante.
Pour tester gratuitement Azure et SQL Azure pendant 30 jours, profitez de l’offre Azure Pass.
Pour faciliter la mise en pratique des tutoriels qui accompagnent ces articles, nous commencerons par mettre en place les données dans Sql Server, pour les faire migrer plus tard dans Sql Azure. Ainsi, nous obtiendrons un projet qui fonctionnera aussi bien On Premises que dans le Cloud. Cela permettra également de montrer la simplicité avec laquelle des solutions existantes peuvent évoluer vers un hébergement dans Azure.
On se retrouve avec le diagramme d’architecture “grosses mailles” que voici:
Y’a plus qu’à !
Passez aux articles suivants:
Cette suite d’articles se propose d’introduire les techniques de développement actuelles, dans le cadre d’un besoin et d’un projet concret.
Un poste de développeur, de chef de projet, d’architecte, un projet, un planning, des délais trop courts, des besoins qui changent tout le temps, des tests, une maintenance perpétuelle de l’application et des mises à jour…
Effectivement, bien souvent on travaille d’arrache-pied sur un projet, la tête dans le guidon, et lorsqu’enfin on finit par la relever, des mois voir des années ont passé. Entre temps, beaucoup de choses ont évolué, aussi bien du côté des usages que du côté des technologies. Tout le monde ne peut pas se payer le luxe de faire une veille technologique de fond et/ou à large bande. D’autant plus que l’on consacre souvent notre peu de temps de veille, à creuser des sujets qui nous concernent directement et qui sont donc très ciblés.
Les techniques de développement d’aujourd’hui ne sont plus celles d’hier, même si les concepts généraux restent valables. Mais alors qu’entend-on par “le développement d’aujourd’hui” ? C’est simplement l’intégration de nos usages et contraintes actuelles à savoir :
D’un point de vue fonctionnel:
- des applications disponibles sur le poste de travail, mais aussi sur nos appareils nomade (téléphone, tablette,…)- des applications qui savent mieux exploiter leur environnement de fonctionnement (interaction avec d’autres applications connexes ou communautaires)
- de plus en plus de données en ligne, pour les partager de manière publique ou privée
- une meilleure réactivité (exploitation de nos machines multi-cores)
- une ergonomie “sexy” et pensée pour l’utilisateur
- des services disponibles depuis n’importe où et tout le temps
D’un point de vue technique:
- l’avènement des application web
- l’arrivée de plateformes et de services dans les nuages
- les applications naissent/vivent/évoluent/co-existent/meurent mais les données perdurent
- le besoin d’une architecture générique et adaptable (adaptation au développement agile)
- une meilleure lisibilité du code
- une meilleure testabilité
- une amélioration du confort de développement et de la productivité du développeur
Bref, tout un programme !
Si vous démarrez un développement aujourd’hui sans prendre en compte ces concepts devenus légion, vous risquez fort d’obtenir un résultat décevant et peu pérenne.
Comme je vous le disais, nous allons partir sur un cas concret en essayant de répondre à un besoin fonctionnel, à savoir :
CaveAVins : Une application de gestion de cave à vins et d’aide à l’achat en boutique. Bon j’en vois déjà qui lèvent les yeux au ciel : elle parle encore de vins ! Ben oui, et alors ? Déjà j’aime bien ça (quelque chose me dit que je ne suis pas la seule) et surtout cela évite d’expliquer en long en large et en travers le besoin fonctionnel que l’on comprend immédiatement, ce qui fait gagner un temps fou à tout le monde . Ce prétexte métier de cave à vins peut être remplacé par n’importe quel autre, qui s’appuierait sur un catalogue de données et fournirait des services et applications autour de celui-ci. Finalement, cela correspond à la majorité de nos applications.
Alors là je joue le rôle du client…
- Ajouter/supprimer des bouteilles dans ma cave - Filtrer, trier les bouteilles selon les cépages, les prix, les années, les mets qui s’y accordent… - Noter les bouteilles et pouvoir partager cet avis avec les autres utilisateurs
Je ne sais pas pour vous, mais quand je vais au supermarché choisir une bouteille de vins, je vis un grand moment de solitude. Quel vin vais-je choisir ? Bon j’ai mes préférences, mais si je dois choisir une bouteille de Bordeaux, comment savoir laquelle des 25 bouteilles proposées entre 4 et 6 euros sera la meilleure ? D’où l’idée de pouvoir prendre une bouteille en photo avec son téléphone et de visualiser les notes que lui ont données les autres amateurs de vins disposant de la même application que moi.
Etre notifié de promotions sur mes vins préférés, par le producteur ou le distributeur.
Voilà pour mon besoin. C’est déjà pas mal pour un début. En fonction du temps que je peux octroyer à ces articles, de l’actualité, et aussi de vos attentes, nous pourrons compléter ces besoins par d’autres scenarios.
Un petit schéma de l’idée générale à ce stade:
Passons au premier débriefing technique après avoir pris connaissance du besoin. Les idées arrivent en vrac, de manière décousue… J’utiliserai volontairement des termes techniques correspondant à des technologies mais pas de panique, inutile de savoir à quoi elles font référence à ce stade:
- Pour stocker les données (vins, caractéristiques, notes…) on va bien évidemment utiliser une base de données. A la base, il n’y a pas de catalogue de bouteilles existant, ce sont les utilisateurs qui enrichissent la base de données au fil de leurs achat et de leur notation. Les données devront donc être mutualisées et non pas être stockées localement sur leur poste de travail et/ou leur téléphone, avec un catalogue présent dans une base de données distante. Je pense à SQL Server, SQL Azure - Nous aurons besoin d’une techno qui nous permet de requêter efficacement ces données, si possible qui fonctionne depuis plusieurs plateformes clientes (doit fonctionner sur le poste de travail et sur le téléphone). Je pense à Entity Framework, Linq, OData, WCF Data Services - Les données et services doivent être hébergés et accessibles facilement Je pense à Azure et SQL Azure - Nous devrons développer 2 applications : l’une pour le PC, l’autre pour notre cher Windows Phone. Les cas d’utilisation sur le PC et sur le téléphone ont l’air assez similaires, mais certains usages se révèleront être inutiles sur les deux plateformes. En tout cas, nous essaierons de factoriser un maximum le code des deux applications Je pense à Silverlight, Portable Library, Html5 - Une manière sexy de représenter un catalogue de données sur PC, avec filtrage, tri, regroupement. Je pense à Pivot Viewer
- Pour stocker les données (vins, caractéristiques, notes…) on va bien évidemment utiliser une base de données. A la base, il n’y a pas de catalogue de bouteilles existant, ce sont les utilisateurs qui enrichissent la base de données au fil de leurs achat et de leur notation. Les données devront donc être mutualisées et non pas être stockées localement sur leur poste de travail et/ou leur téléphone, avec un catalogue présent dans une base de données distante. Je pense à SQL Server, SQL Azure
- Nous aurons besoin d’une techno qui nous permet de requêter efficacement ces données, si possible qui fonctionne depuis plusieurs plateformes clientes (doit fonctionner sur le poste de travail et sur le téléphone). Je pense à Entity Framework, Linq, OData, WCF Data Services
- Les données et services doivent être hébergés et accessibles facilement Je pense à Azure et SQL Azure
- Nous devrons développer 2 applications : l’une pour le PC, l’autre pour notre cher Windows Phone. Les cas d’utilisation sur le PC et sur le téléphone ont l’air assez similaires, mais certains usages se révèleront être inutiles sur les deux plateformes. En tout cas, nous essaierons de factoriser un maximum le code des deux applications Je pense à Silverlight, Portable Library, Html5
- Une manière sexy de représenter un catalogue de données sur PC, avec filtrage, tri, regroupement. Je pense à Pivot Viewer
- Prise de photo pour interprétation du code barre et/ou de l’étiquette de la bouteille Je pense aux services OCR (Reconnaissance optique de caractères)
- Pouvoir être notifié des bonnes affaires sur les vins que je préfère ? Je pense aux notifications Push sur Windows Phone
Les éléments techniques introduits en bleu correspondent aux premières associations d’idées. Ca ne veut pas dire que dans les faits, ils correspondront le mieux aux besoins du développeur et du client. Nous découvrirons au fil des articles, quels choix techniques seront retenus et quelles seront les solutions les plus adaptées. Je risque également de modifier la liste des besoins: soit parce que trop compliqué à mettre en œuvre dans des articles “basiques”, soit parce qu’un autre scénario auquel je n’avais pas pensé se révèlera être plus intéressant à expliquer. Vous l’aurez compris, j’écrirai cette suite d’articles en temps réel.
Voici le premier jet pour le sommaire de cette série d’articles :
…sachant que je risque de revoir la décomposition de tout cela en fonction de la longueur des articles et des notions en plus ou en moins que j’aborderai.
Tchin tchin !
13h30 : Accueil
14h00 - 18h00 : 3 sessions au choix, construisez votre agenda !
Adopter Windows Azure pour simplifier vos projets et optimiser l’impact de vos campagnes
Profitez des dernières innovations pour révolutionner vos interactions client
Discussions ouvertes, rencontrez nos spécialistes : venez avec vos questions !
Depuis mi-2010, de nouveaux thèmes bien sympathiques sont disponibles pour les applications Silverlight 4, sous la forme de dictionnaires de ressources.
Cosmopolitan (cliquez ici pour tester)
Accent (cliquez ici pour tester)
JetPack (cliquez ici pour tester)
Windows 7 (cliquez ici pour tester)
Des templates sont disponibles dans Visual Studio pour créer des applications Silverlight de type Navigation, utilisant des thèmes présentés ci-dessus. Pour les trouver et les installer, rendez-vous dans l’extension manager de Visual Studio (Tools/Extension Manager), en cherchant dans la section OnLineGallery/Templates, la chaine '”Silverlight Theme”:
Ca tombe bien puisque c’est justement le sujet de cet article. Si vous ne souhaitez pas utiliser d’application de type Navigation ou que vous souhaitez appliquer un de ces thèmes a posteriori, voici les quelques étapes à suivre:
<Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Assets/Styles.xaml"/> <ResourceDictionary Source="Assets/CoreStyles.xaml"/> <ResourceDictionary Source="Assets/SDKStyles.xaml"/> <!--<ResourceDictionary Source="Assets/ToolkitStyles.xaml"/> To extend this theme to include the toolkit controls: 1. Install the Silverlight Toolkit for Silverlight 4 2. Add a Toolkit control to your project from the toolbox. This will add references to toolkit assemblies. 3. Change the "Build Action" for ToolkitStyles.xaml to "Page" 4. Uncomment the resource dictionary include above. If you do not intend to use toolkit controls, delete this comment and the ToolkitStyles.xaml file.--> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources>
<Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Assets/Styles.xaml"/> <ResourceDictionary Source="Assets/CoreStyles.xaml"/> <ResourceDictionary Source="Assets/SDKStyles.xaml"/> <ResourceDictionary Source="Assets/ToolkitStyles.xaml"/> <!-- To extend this theme to include the toolkit controls: 1. Install the Silverlight Toolkit for Silverlight 4 2. Add a Toolkit control to your project from the toolbox. This will add references to toolkit assemblies. 3. Change the "Build Action" for ToolkitStyles.xaml to "Page" 4. Uncomment the resource dictionary include above. If you do not intend to use toolkit controls, delete this comment and the ToolkitStyles.xaml file.--> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources>
Vérifiez les propriétés du fichier ToolkitStyles.xaml. Si vous n’utilisez pas le toolkit, la propriété Build Action doit être à None, ou à Page si votre projet référence les assemblies du toolkit.
C’est tout : votre projet compile et s’exécute correctement à ce stade. Si vous êtes aussi peu doué que moi en personnalisation de l’UI, vous aurez le plaisir de constater que votre application ressemble enfin à quelque chose
Si vous ne souhaitez pas ajouter de référence supplémentaire à votre projet, il va falloir faire un peu de tuning.Au mieux ce sera le fichier app.xaml qu’il faudra retoucher. Au pire ce seront les fichiers de ressources eux-même, pour désactiver les sections qui s’appliquent à des éléments que vous n’utilisez pas dans votre projet et qui sont contenus dans des assemblies manquantes.Si vous n’utilisez pas de projet de type Navigation, vous pouvez désactiver Styles.xaml (définissez le build action en None et commentez-le dans app.xaml)Si vous n’utilisez pas le sdk de Silverlight, vous pouvez désactiver SDKStyles.xaml (définissez le build action en None et commentez-le dans app.xaml)Si vous rencontrez des erreurs, commentez les styles en question, mais cela risque de vous prendre un peu de temps. Vous pouvez vous inspirer des guidelines du fichier readme.txt inclus dans le zip des thèmes.
Attention : si vous ajoutez un nouveau contrôle par la suite, et qu’il fait partie de ceux que vous avez supprimés dans les thèmes, il faudra penser à réactiver.
Voici une petite astuce qui permet de contourner les restrictions du modèle d’exécution SandBox de Sharepoint 2010 : travailler côté client plutôt que côté serveur, en intégrant un client Silverlight dans la Web Part.
Dans notre cas, la fonctionnalité “interdite” est l’appel à un service web externe. La Web Part qui est développée dans cet exemple va intégrer une application Silverlight qui se déploiera côté client et se chargera d’effectuer l’appel au service Web. Cette application Silverlight sera uniquement chargée d’appeler ce web service et est donc ultra simpliste.
Tout cela se fait facilement et avec peu de lignes de code, comme le montre ce “Visual How To”:
Calling Public Web Services from a Sandboxed Silverlight Application in SharePoint 2010
Vous pouvez suivre ce tutoriel, voir la vidéo associée et télécharger les sources, pour comprendre comment tout cela se met en place.
The tag cloud represents items size according to the sum of their occurences in the list. This is typically the kind of control that you see on blogs, to show the post tags. When having a large list containing lots of items, the tag cloud can be used for a first filter to avoid sliding in the list for too long.
Here is an example of 2 tag clouds. You can change the background, foreground and the font family of the control. The tag cloud is compatible with both portrait and landscape mode.
The datasource used by the control is a collection of objects, and uses .ToString() for its representation.
In my case it is a collection of int for the first tag cloud and a collection of string for the second tag cloud. Bind the ItemsSource property of the tag cloud with this collection just like you would for a ListBox. The font size will be computed automatically, according to the item occurrences in the source list.
Use SelectedItem property or SelectionChanged event to get the selected tag.
In my example, I use a collection of DataSample:
public class DataSample { public string City { get; set; } public int Year { get; set; } }
The datasources of my 2 tag clouds are like follows, where dataSampleList is a collection of DataSample :
ct1.ItemsSource = dataSampleList.Select(d => d.Year); ct2.ItemsSource = dataSampleList.Select(d => d.City);
In the XAML code, the namespace should be declared like this:
xmlns:cloud="clr-namespace:Wp7TagCloud;assembly=Wp7TagCloud"
Here is the code to declare the first tag cloud:
<cloud:TagCloud x:Name="ct1" FontFamily="Georgia"/>
Here is the second one, added with a TextBlock binded on the SelectedItem of the tag cloud and also handling the SelectionChanged event:
<cloud:TagCloud x:Name="ct2" Foreground="Black" Background="DarkKhaki" SelectionChanged="ct2_SelectionChanged"/> <TextBlock Text="Selected City:"/> <TextBlock Text="{Binding ElementName=ct2, Path=SelectedItem}"/>
Here is the assembly you should download to use the tag cloud control.
The source code should be available soon in the Coding4Fun Toolkit (thanks Clint ).