Gael's profileGael Duhamel - SharePoin...PhotosBlogListsMore ![]() | Help |
|
June 25 [SharePoint] Filtrer et récupérer des éléments d’une liste de configuration grâce à Linq et les méthodes d’extensions - UPDATE 25-06-2008-- UPDATE -- J'ai changé ma méthode pour récupérer directement une valeur dans ma liste de configuration. Je faisais un query qui me retournais une collection que je filtrais ensuite pour récupérer ma valeur. Alors qu'il suffisait simplement de le faire directement dans mon query -- UPDATE -- Dans mes applications SharePoint, j’utilise très souvent une liste ou je stocke l’ensemble de mes éléments de configuration comme par exemple :
Le gros avantage est que le webmaster du site peut facilement (à ses risques et périls tout de même La structure de ma liste est toute simple :
J’avais donc implémenté une classe qui me permettait de récupérer ces valeurs via un CAML query sur ma liste. Mais suite à un article posté par Philippe Sentenac sur les méthodes d’extensions, j’ai décidé de refaire cette classe en utilisant ces extensions et les nombreuses autres classes generics du framework .Net. Pour commencer, j’ai étendu l’objet SPWeb pour accéder à notre Liste de configuration (dans mon cas, j’ai aussi besoin d’un paramètre « Category » pour me retourner l’ensemble des valeurs car je ne souhaite pas faire une requête pour chaque entrée). Cette méthode, me retourne une interface générique de type ILookup < TKey, TElement>. Cette interface, va me permettre ensuite de récupérer très facilement une entrée de ma configuration : public static ILookup<String, String> ConfigurationList(this SPWeb spWeb, String Category) { SPList spListConfiguration; ILookup<String, String> configurationEntries = null; // La liste n'est pas accessible aux end users. // On doit donc s'y connecter sur le compte admin pour y accéder // Optionnel, si vous avez décidé de mettre la liste en lecture pour tout vos utilisateurs SPSecurity.RunWithElevatedPrivileges(delegate() { using (SPSite mySite = new SPSite(spWeb.Site.ID)) { using (SPWeb myWeb = mySite.OpenWeb(spWeb.ID)) { Je récupère ma liste « Configuration » grâce à la méthode d’extension TryGet de Philippe : if (myWeb.Lists.TryGet("Configuration", out spListConfiguration)) { J’exécute ensuite mon query pour récupérer mes éléments : SPQuery spQuery = new SPQuery(); spQuery.Query = String.Format(<Where><Eq><FieldRef Name='Category' /><Value Type='Choice'>{0}</Value></Eq></Where>", Category); Et je stock les résultats dans un document XML Linq (XDocument) : XDocument xml = XDocument.Parse(spListConfiguration.GetItems(spQuery).Xml); Je définie mon namespace pour me simplifier la lecture du code : XNamespace z = "#RowsetSchema";Je renvoie tout ce flux dans mon interface générique en lui spécifiant :
configurationEntries = (from xmlItems in xml.Descendants(z + "row").ToArray() select new ConfigurationEntry { Key = (String)xmlItems.Attribute("ows_Title"), Value = (String)xmlItems.Attribute("ows_Value") }) .ToLookup(key => key.Key, element => element.Value, EqualityComparer<String>.Default); }); } onfigurationEntries; } J’utile cette classe pour stocker ma clé ainsi que la valeur associée dans mon query Linq : public class ConfigurationEntry { public String Key; public String Value; } Ensuite, il ne me reste plus qu’a écrire la classe qui va me rechercher mon élément dans ma collection (on peut ici choisir de lui donner un objet SPWeb ou d’utiliser le context) public sealed class Configuration { private ILookup<String, String> configurationValues; public Configuration(SPWeb spWeb, String category) { if (spWeb == null) throw new ArgumentNullException("A SPWeb object cannot be null"); if (String.IsNullOrEmpty(category)) throw new ArgumentNullException("A category cannot be empty"); configurationValues = spWeb.ConfigurationList(category); } public Configuration(String category) { if (SPContext.Current == null) throw new ArgumentNullException("SPContext cannot be null. Please ensure that you're running a SharePoint application"); if (String.IsNullOrEmpty(category)) throw new ArgumentNullException("A category cannot be empty"); configurationValues = SPContext.Current.Web.ConfigurationList(category); } public String GetEntry(String key) { return Convert.ToString(configurationValues[key].FirstOrDefault()); } } Notez l’utilisation du générique FirstOrDefault, qui nous permet ici de nous retourner un String.Empty s’il n’y a pas de valeur à retourner. Ensuite, pour l’appel, c’est très simple. Instanciez un objet Configuration et utilisez la méthode GetEntry pour récupérer vos valeurs: Configuration configValues = new Configuration(spWeb,"SSRS"); Console.WriteLine("SSRS URL:" + configValues.GetEntry("SSRSUrl")); Console.WriteLine("SSRS Path:" + configValues.GetEntry("SSRSPath")); Console.WriteLine("SSRS WebPartPage:" + configValues.GetEntry("SSRSWebPartPage")); On peut aussi ajouter une variante à notre méthode d’extension ConfigurationList pour récupérer directement la valeur d’une clé dans notre liste :
La récupération de votre valeur se faisant comme ceci: Console.WriteLine("SSRS Url:" + spWeb.ConfigurationList("SSRS", "SSRSURL")); Comme promis, voici ici un exemple de classe qui vous permet de comparer 2 Strings sans distinction de la casse : public class StringNoCaseSensitive : IEqualityComparer<String> { public Boolean Equals(String val1, String val2) { return (val1.ToLower() == val2.ToLower()); } public int GetHashCode(string obj) { return obj.ToLower().GetHashCode(); } } Dans l’appel du ILookup,remplacer EqualityComparer<String>.Default par new StringNoCaseSensitive() et le tour est joué... Tags: June 10 [Telerik] Petit bug sur le control RadHtmlFieldDans le cadre d’un de mes projets de publication web sous MOSS, j’utilise très souvent le RAD editor pour SharePoint de Telerik. Il est vraiment très performant et d’une grande facilité d’utilisation. Mais j’ai détecté un petit bug dans son utilisation lorsque vous souhaitez valider vos pages pour éviter les attaques par script injection (XSS) via l’attribut validateRequest=True. <pages enableSessionState="true" enableViewState="true" enableViewStateMac="true" validateRequest="true" pageParserFilterType="Microsoft.SharePoint.ApplicationRuntime.SPPageParserFilter, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" asyncTimeout="7"> Il y a apparemment un bug sur certaines valeurs attribuées aux Id de ce control. Dans mon cas, j’avais ce control sur ma page : <Telerik:RadHtmlField ID="Request" FieldName="Request" runat="server"/> Ce qui provoquait une erreur de type: Un rapide coup d’œil dans l’event viewer me donne un message d’erreur un peu plus explicite : Ce message d’erreur est très explicite, il nous indique que le framework n’a pu trouver la methode validateInput et donc valider l’intégrité d’un control (du au fait du validateRequest à vrai). En effet, dès que je mettais mon attribut validateRequest à faux, ma page s’affichait correctement. Intrigué et surpris par le fait qu’un control ne puisse satisfaire à cette règle élémentaire du framework, j’ai tente de trouver sur le net (et en particulier le forum de telerik) quelques réponses. Mais absolument rien à ce sujet. N’étant pas le seul au monde à utiliser ce control et n’ayant rien trouvé dans mes investigations googleienne, je me suis dit que ca devait venir forcement d’une petite bricole sur ma page. J’ai donc vérifié l’appel à l’assembly dans mes attributs de pages (version, publickeytoken,…) ainsi que quelques propriétés du control (IsValid par exemple). Mais toujours rien… Et en relisant bien mon control, j’ai vu que la valeur de mon id était « Request ». Dans le doute et sans autres solutions, j’ai supprimé cet id en étant sur que ca n’avait aucun impact… et bien si. Détrompez-vous ! Je ne sais pas pour quelle raison, mais chez Telerik si votre id à pour valeur Request et que vous configuré votre application web pour éviter les XSS et bien ca plante… Ce n’est pas un gros problème en soit car il suffit juste de changer la valeur, mais c’est quand même surprenant… Tags: June 06 [SharePoint] Mettre à jour son web.config par l'intermediaire d'un fichier XML de configuration - UPDATED ON 06-JUNE-2008MISE A JOUR DU 06 JUIN 2008 <add path="configuration/system.web" id="{45C74BC1-DBA5-489f-A6E9-6932C25F1D97}"> <xhtmlConformance mode="Strict" /> </add> Ceci évitant la recréation multiple de vos actions. Grand merci à Gaetan Bouveret pour cet éclaircissement. Comme quoi la communauté SharePoint est plus forte que le SDK ------------------------------- Je reprend ici un post de Gaetan Bouveret, au sujet de la mise à jour du fichier web.config sans ligne de code. Je ne connaissais pas ce système de mise à jour via un flux xml. J'utilisais pour ce genre de déploiement le modèle objet et son SPWebConfigModification. Intéressé par son post, j'ai donc essayé de le mettre en place sur un de mes projets. J'ai donc ajouté dans un fichier xml (déployé par ma feature dans le répertoire config du 12) cette ligne: <add path="configuration/system.web"> <xhtmlConformance mode="Strict" /> </add> Pour déployer ce fichier dans votre web.config, il vous faut exécuter la commande : stsadm -o copyappbincontent Lors de la toute première commande tout marche parfaitement bien, mon noeud est bien ajouté là ou je le voulais. <system.web> .... <xhtmlConformance mode="Strict" /> </system.web> Le problème de cette commande add est qu'elle ne vérifie pas la présence du noeud à ajouter. Ce qui fais que si vous exécutez une nouvelle fois la commande stsadm -o copyappbincontent, ce noeud est ajouté une deuxième fois. Et dans le cas précis de cet exemple, cela fais planter mon application web car le noeud xhtmlConformance doit être unique. Pour remédier à cela, j'ai simplement ajouté une commande remove juste avant la commande add: <remove path="configuration/system.web/xhtmlConformance" /> Pour info, la valeur de path est une fonction xpath, vous pouvez donc allez chercher l'élément à supprimer même si les noeuds fils ont le même nom. <remove path="configuration/system.web/httpModules/add[@name='Session']" /> <add path="configuration/system.web/httpModules"> <add name="Session" type="System.Web.SessionState.SessionStateModule"/> </add> ps: Attention pour les fermes, le SDK stipule bien que cette commande doit être exécutée sur chaque serveur de la ferme. Tags: |
|
|