[MOSS 2007] Définir les propriétés de navigation de portail dans le fichier Onet.xml

Si l'on observe le fichier Onet.xml du template de site Publishing fourni en standard, on peut noter l'activation d'une feature de scope Web déterminant les options de navigation de portail :

      <WebFeatures>

      ...

        <Feature ID="541F5F57-C847-4e16-B59A-B31E90E6F9EA">

          <Properties xmlns="http://schemas.microsoft.com/sharepoint/">

            <Property Key="InheritGlobalNavigation" Value="true"/>

            <Property Key="ShowSiblings" Value="true"/>

            <Property Key="IncludeSubSites" Value="true"/>

          </Properties>

        </Feature>

      ...

      </WebFeatures>

On voit que la feature est accompagnée de propriétés. Ce qui nous intéresse alors est de savoir quelles sont les propriétés acceptées par la feature, quelles valeurs peut-on leur donner, et quel impact cela aura sur la navigation du site.

En poussant un peu notre investigation, on retrouve cette feature dans le répertoire [12]\TEMPLATE\FEATURES\NavigationProperties. Le fichier Feature.xml qu'il contient définit la feature comme suit :

<Feature  Id="541F5F57-C847-4e16-B59A-B31E90E6F9EA"

          Title="Portal Navigation Properties"

          Description="Set per-site navigation properties."

          Version="12.0.0.0"

          Scope="Web"

          Hidden="TRUE"

          ReceiverAssembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"

          ReceiverClass="Microsoft.SharePoint.Publishing.NavigationFeatureHandler"

          xmlns="http://schemas.microsoft.com/sharepoint/">

  <ElementManifests>

    <ElementManifest Location="NavigationSiteSettings.xml"/>

  </ElementManifests>

</Feature>

Notons au passage que le fichier NavigationSiteSettings.xml déclaré en tant que ElementManifest est un fichier vide. Nous allons alors explorer la classe Microsoft.SharePoint.Publishing.NavigationFeatureHandler avec Reflector pour voir quelles informations elle traite.

 

Nous pouvons alors voir toutes les propriétes qu'accepte la feature "Portal Navigation Properties", à savoir :

  • IncludeInGlobalNavigation
  • IncludeInCurrentNavigation
  • InheritGlobalNavigation
  • InheritCurrentNavigation
  • ShowSiblings
  • IncludeSubSites
  • IncludePages
  • OrderingMethod
  • AutomaticSortingMathod (oui, Mathod et pas Method)
  • SortAscending

Ces noms évoquent sans doute quelque chose aux habitués de la plateforme de publication de MOSS 2007. En effet, on peut paramétrer ces options sur un site grâce à l'interface utilisateur dans la page "/_layouts/AreaNavigationSettings.aspx" accessible depuis le menu des actions du site

Afin de mieux se rendre compte de l'impact de chaque option sur la navigation, nous allons voir pour chacune d'entre elles les valeurs possibles ainsi que la répercussion sur cette page d'administration.

 

IncludeInGlobalNavigation et IncludeInCurrentNavigation

Ces deux options sont un peu particulières puisqu'elles définissent si le site courant doit être inclus dans la navigation actuelle ou globale du site parent. Ainsi, pour agir sur ces options avec l'interface utilisateur, il faut remonter au niveau supérieur et choisir de masquer ou non le sous-site dans les sections de navigation actuelle et globale.

Valeurs possibles :

  • true - Inclut le site dans la navigation (actuelle ou globale).
  • false - N'inclut pas le site dans la navigation (actuelle ou globale).

 

IncludeSubSites et IncludePages

Ces deux options indiquent si les pages ou les sous-sites doivent être automatiquement inclus dans la navigation. Notons que si la navigation hérite du site parent, ces options n'ont aucun sens.

Valeurs possibles :

  • true - Inclut les pages ou les sous-sites.
  • false - N'inclut pas les pages ou les sous-sites.

 

OrderingMethod

Cette option permet de définir le tri de tous les éléments de navigation.

Valeurs possibles :

  • Automatic - Trie tous les types d'éléments automatiquement, et groupe les pages après tous les autres types.
  • ManualWithAutomaticPageSorting - Trie tous les types d'éléments manuellement, à l'exception des pages, qui sont groupées et triées automatiquement après les autres types.
  • Manual - Trie tous les types d'éléments manuellement.

 

AutomaticSortingMathod

Cette option, qui n'a de sens que si OrderingMethod n'a pas été défini à "Manual", permet de préciser le critère de tri automatique des éléments de navigation.

Valeurs possibles :

  • Title - Trie les éléments alphabétiquement par leur titre.
  • CreatedDate - Trie les éléments par leur date de création.
  • LastModifiedDate - Trie les éléments par leur date de dernière modification.

 

SortAscending

Cette option, qui n'a de sens que si OrderingMethod n'a pas été défini à "Manual", permet de préciser l'ordre de tri automatique des éléments de navigation.

Valeurs possibles :

  • true - Trie les éléments par ordre croissant.
  • false - Trie les éléments par ordre décroissant.

 

InheritGlobalNavigation

Cette option permet de définir l'héritage ou non de la navigation globale du site.

Valeurs possibles :

  • true - Affiche les mêmes éléments de navigation que le site parent.
  • false - Affiche les éléments de navigation sous le site actuel.

 

InheritCurrentNavigation et ShowSiblings

Il est un peu moins trivial de comprendre l'impact de ces deux options. Premièrement, il est à noter qu'elles agissent sur l'affichage de la navigation actuelle. Or, si l'on regarde l'interface utilisateur, on s'aperçoit que trois options différentes nous sont proposées :

Pour reproduire ces paramètres dans les propriétés de la feature, il va nous falloir combiner les valeurs des deux options InheritCurrentNavigation et ShowSiblings.

  • InheritCurrentNavigation = true et ShowSiblings = false donnera :

     
  • InheritCurrentNavigation = false et ShowSiblings = true donnera :


  • InheritCurrentNavigation = false et ShowSiblings = false donnera :

 

Grâce à toutes ces propriétés de la feature "Portal Navigation Properties", vous avez la possibilité de définir précisemment la navigation de vos sites de publication personnalisés directement à sa création.

Il est à noter que vous pouvez également changer toutes ces options via le modèle objet en récupérant l'objet PublishingWeb correspondant à votre site.

 

            using (SPSite site = new SPSite("http://localhost"))

            {

                using (SPWeb web = site.RootWeb)

                {

                    PublishingWeb pubWeb = PublishingWeb.GetPublishingWeb(web);

 

                    pubWeb.IncludeInGlobalNavigation = true;

                    pubWeb.IncludeInCurrentNavigation = true;

 

                    pubWeb.IncludeSubSitesInNavigation = true;

                    pubWeb.IncludePagesInNavigation = true;

 

                    pubWeb.NavigationOrderingMethod = OrderingMethod.ManualWithAutomaticPageSorting;

                    pubWeb.NavigationAutomaticSortingMethod = AutomaticSortingMethod.Title;

                    pubWeb.NavigationSortAscending = false;

 

                    pubWeb.InheritGlobalNavigation = true;

 

                    pubWeb.InheritCurrentNavigation = false;

                    pubWeb.NavigationShowSiblings = true;

                }

            }

 

Adrien

[SharePoint 2007] Développer des User Defined Functions pour Excel Services

Les Excel Services sont une nouvelle technologie fournie avec Microsoft Office SharePoint Server (MOSS) Entreprise 2007, et qui permet de simplement utiliser, partager et gérer des fichiers Microsoft Office Excel 2007 en tant que rapports interactifs sur un site d'entreprise.

Pour les classeurs publiés par ce moyen sur une plateforme SharePoint, Microsoft propose d'étendre la librairie de fonctions déjà disponible avec Excel grâce aux User Defined Functions (UDF). Ces dernières peuvent être exécutées depuis une feuille de calcul comme toute autre fonction Excel standard. Comme le développement des UDF s'appuie sur le Framework .Net, les possibilités d'extension sont pratiquement illimitées.

Côté technique, l'écriture d'UDF ne se distingue des développements classiques que par un attribut venant préfixer les méthodes exposées. Elles représentent, entres autres, un moyen simple de centraliser des formules jusqu'alors disponibles sous forme de macros, sans en dévoiler les règles métier. Par exemple, pour extraire le dernier mot d'une phrase dans une cellule, on pourrait écrire la formule :

Avec les UDF, on permet à l'utilisateur de simplement saisir le nom d'une nouvelle fonction :

Vous trouverez l'article complet, co-rédigé avec mon collègue et néanmoins ami Philippe Sentenac, sur le site Tech Head Brothers à cette adresse : Développer des User Defined Functions pour Excel Services.

Adrien

[SharePoint 2007] Création de Workflow avec Visual Studio 2008

Comme Philippe l'a annoncé sur son blog, et suite à la session qu'il a présentée aux TechDays 2008, nous nous sommes lancés dans la co-rédaction d'une série d'articles sur la création de Workflow pour Windows SharePoint Services 3.0 avec Visual Studio 2008.

Ainsi, nous évoquerons les sujets suivants :

  • Les avantages de Visual Studio 2008 pour le développement de Workflow SharePoint 
  • Les différences entre Workflows séquentiel et à états
  • Le design d'un Workflow à états
  • L'utilisation de correlation token
  • Des activités comme OnWorkflowActivated, Delay, ...
  • La création de formulaires ASP.Net et Infopath + Form Services
  • L'interaction entre les Workflows SharePoint et la suite Office 2007
  • La gestion de la sécurité sur les tâches et sur les documents liés au Workflow
  • La gestion d'un processus d'escalade dans les deux types de Workflow
  • La gestion des erreurs dans un Workflow
  • La création de types de contenu personnalisés pour un Workflow
  • Le packaging et le déploiement sur votre environnement

Le premier article de la série est disponible à cette adresse : Développer un Workflow « SharePoint » avec Visual Studio 2008

Bonne lecture !

Adrien


Classé sous , , ,

[MOSS 2007] Intégrer des champs de type Link et Image à ses types de contenu de page de publication

Nous allons voir aujourd'hui comment créer un type de contenu héritant de Page et intégrant des champs personnalisés de type Link et Image, ainsi que son modèle de page associé. Commençons par créer le fichier de définition du type de contenu.

CustomPage.xml :

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

  <ContentType

    ID="0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF39005AB43615533C4e09BF40969BDF9856AE"

    Name="CustomPage"

    Group="Types de contenu personnalisés"

    Description="Définit un type de contenu d'une page de publication personnalisée."

    Version="1">

    <FieldRefs>

      <FieldRef ID="{87F3E3CF-0861-4629-8386-7E87034A7A12}" Name="CustomPageLogo" />

      <FieldRef ID="{8558B229-B874-4c84-BE54-4AD6FA82B186}" Name="CustomPageContact" />

    </FieldRefs>

  </ContentType>

</Elements>

L'identifiant de notre type de contenu est constitué de l'identifiant du type de contenu Page suivi d'un séparateur "00" et d'un nouveau GUID. Cette mécanique permet de définir que CustomPage hérite de Page. Pour ceux qui ne sont pas familiarisés avec les ID des types de contenu, je conseille la lecture de cet article MSDN. Dans la partie FieldRefs, nous renseignons les références aux champs personnalisés que nous allons définir dans un deuxième fichier.

CustomPage.Fields.xml :

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

  <Field

    ID="{87F3E3CF-0861-4629-8386-7E87034A7A12}"

    Type="Image"

    Name="CustomPageLogo"

    DisplayName="Logo de la page personnalisée"

    StaticName="CustomPageLogo"

    Group="Custom"

    RichText="True"

    RichTextMode="FullHtml">

  </Field>

  <Field

    ID="{8558B229-B874-4c84-BE54-4AD6FA82B186}"

    Type="Link"

    Name="CustomPageContact"

    DisplayName="Contact de la page personnalisée"

    StaticName="CustomPageContact"

    Group="Custom"

    RichText="True"

    RichTextMode="FullHtml">

  </Field>

</Elements>

Pour les champs de type Link et Image, il nous faut préciser les propriétés RichText et RichTextMode respectivement à "True" et "FullHtml". Ces propriétés permettent en effet de déterminer l'affichage des champs de contenu dans les modèles de page comme nous le verrons plus loin. Nous déployons à présent ces deux fichiers grâce à une feature SharePoint.

Feature.xml :

<Feature xmlns="http://schemas.microsoft.com/sharepoint/"

    Id="FF8936BA-2BFB-48b3-B0B2-99E2F4E2E51B"

    Title="Publishing Custom Page Content Type"

    Description="Defines a simple custom publishing page content type"

    Hidden="FALSE"

    Scope="Site"

    Version="1.0.0.0">

  <ElementManifests>

    <ElementManifest Location="CustomPage.Fields.xml" />

    <ElementManifest Location="CustomPage.xml" />

  </ElementManifests>

  <ActivationDependencies>

    <!-- Publishing Feature -->

    <ActivationDependency FeatureId="AEBC918D-B20F-4a11-A1DB-9ED84D79C87E" />

  </ActivationDependencies>

</Feature>

Après le déploiement et l'activation de notre feature sur un site de publication, nous retrouvons bien notre type de contenu avec les colonnes personnalisées dans les pages de paramètres du site.

Pour pouvoir créer une page de type CustomPage, il nous faut à présent créer un modèle de page pour ce type de contenu. Grâce à SharePoint Designer, nous insérons nos deux champs de contenu dans un nouveau modèle de page.

CustomPageLayout.aspx

<%@ Page="" language="C#"  Inherits="Microsoft.SharePoint.Publishing.PublishingLayoutPage,Microsoft.SharePoint.Publishing,Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" meta:progid="SharePoint.WebPartPage.Document" %>

<%@ Register="" Tagprefix="SharePointWebControls" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Register="" Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Register="" Tagprefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Register="" Tagprefix="PublishingNavigation" Namespace="Microsoft.SharePoint.Publishing.Navigation" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<asp:Content ContentPlaceholderID="PlaceHolderPageTitle" runat="server">

  <SharePointWebControls:FieldValue id="PageTitle" FieldName="Title" runat="server"/>

</asp:Content>

<asp:Content ContentPlaceholderID="PlaceHolderMain" runat="server">

  <PublishingWebControls:RichLinkField FieldName="CustomPageContact" runat="server" />

  <PublishingWebControls:RichImageField FieldName="CustomPageLogo" runat="server" />

</asp:Content>

Voilà, nous pouvons alors créer une nouvelle page se basant sur le modèle de page CustomPageLayout. En mode édition, tout est comme nous l'attendions, et nous pouvons éditer le contenu de nos champs de type Link et Image.

 

Mais lorsque nous publions la page, on remarque alors que les champs sont rendus sous forme de texte simple, et pas comme du code HTML... In fine, le rendu est comme si nous n'avions pas précisé les deux propriétés RichText et RichTextMode dont je vous parlais plus haut.

 

Là se trouve la subtilité des champs de type Link et Image. En effet, si la propriété RichText n'est pas prise en compte, c'est parce que la valeur de cette propriété est sensible à la casse (sic !). Il s'agit alors de remplacer dans le fichier CustomPage.Field.xml de définition des champs les lignes :

    RichText="True"

par

    RichText="TRUE"

En redéployant notre type de contenu, le rendu de la page est tel que nous le souhaitions ! 

Adrien

[Silverlight] Créer une application modulaire (Partie 2)

Dans le précédent billet, nous avons vu comment créer un module en Silverlight qui dispense un objet Control, ainsi qu'un WebService qui permet de donner une liste de tous les modules disponibles côté serveur. Nous allons voir aujourd'hui comment, à partir de la liste des modules récupérée depuis le WebService, nous allons pouvoir les télécharger au chargement de la page, puis incorporer les Control que ces derniers dispensent dans le Canvas principal.

J'ai écrit une classe Modman qui s'occupe de la première partie. Il appelle le WebService pour récupérer les URI relatives, télécharge la DLL grâce au Downloader puis créé une instance de la classe qui implémente l'interface IModule avec Activator.CreateInstance. Toutes les instances des modules sont alors stockées dans une liste accessible en lecture.

    public class Modman

    {

        private List<IModule> _modules = new List<IModule>();

        private ModmanWS.Modman _ws = new ModmanWS.Modman();

        private List<ModuleAssembly> _modAssemblyList = new List<ModuleAssembly>();

 

        public event EventHandler OnAllModulesLoaded;

        public event EventHandler OnModuleDownloadFailed;

        public event EventHandler<ModuleErrorEventArgs> OnModuleLoadError;

 

        public List<IModule> ModulesInstances

        {

            get { return _modules; }

        }

 

        public void DownloadAndLoadAllModules()

        {

            string[][] modList = _ws.GetModulesList();

 

            foreach (var mod in modList)

            {

                ModuleAssembly assembly = new ModuleAssembly(mod[0], mod[1], new Uri(mod[2], UriKind.Relative));

                _modAssemblyList.Add(assembly);

 

                Downloader loader = new Downloader();

                loader.Completed += new EventHandler(onDownloadComplete);

                loader.DownloadFailed += new ErrorEventHandler(onDownloadFailed);

 

                loader.Open("GET", assembly.Url);

                loader.Send();

            }

        }

 

        private void onDownloadComplete(object sender, EventArgs e)

        {

            ModuleAssembly assemblyInfo = retrieveAssemblyDownloaded(sender as Downloader);

 

            if (assemblyInfo != null)

            {

                loadModule(assemblyInfo);

                _modAssemblyList.Remove(assemblyInfo);

                if (_modAssemblyList.Count == 0 && this.OnAllModulesLoaded != null)

                    this.OnAllModulesLoaded(this, new EventArgs());

            }

        }

 

        private void onDownloadFailed(object sender, EventArgs e)

        {

            if (this.OnModuleDownloadFailed != null)

                this.OnModuleDownloadFailed(this, new EventArgs());

        }

 

        private ModuleAssembly retrieveAssemblyDownloaded(Downloader loader)

        {

            ModuleAssembly assemblyInfo = null;

            foreach (ModuleAssembly assembly in _modAssemblyList)

            {

                if (assembly.Url == loader.Uri)

                {

                    assemblyInfo = assembly;

                    break;

                }

            }

            return assemblyInfo;

        }

 

        private void loadModule(ModuleAssembly assemblyInfo)

        {

            try

            {

                Assembly assembly = Assembly.Load(assemblyInfo.AssemblyName);

                foreach (Type type in assembly.GetTypes())

                {

                    if (type.GetInterface(typeof(IModule).FullName, false) != null)

                    {

                        IModule instance = (IModule)Activator.CreateInstance(type);

                        _modules.Add(instance);

                    }

                }

            }

            catch (Exception ex)

            {

                if (OnModuleLoadError != null)

                    OnModuleLoadError(this, new ModuleErrorEventArgs(ex));

            }

        }

    }

Notez que j'utilise un objet ModuleAssembly, qui ne me sert en fait qu'à stocker les informations d'un module que retourne le WebService.

On y est presque ! Dans le code de ma page principale Silverlight, je m'abonne aux évènements de Modman, pour pouvoir afficher l'état du chargement des modules dans mon Canvas, et lorsque tous les modules ont été chargés, je récupère la liste des instances de modules, et j'ajoute pour chacun d'entre eux le MainControl au Canvas.

    public partial class Page : Canvas

    {

        public void Page_Loaded(object o, EventArgs e)

        {

            InitializeComponent();

            Modman mm = new Modman();

 

            mm.OnAllModulesLoaded += new EventHandler(ModMan_OnAllModulesLoaded);

            mm.OnModuleDownloadFailed += new EventHandler(ModMan_OnModuleDownloadFailed);

            mm.OnModuleLoadError += new EventHandler<ModuleErrorEventArgs>(ModMan_OnModuleLoadError);

 

            mm.DownloadAndLoadAllModules();

        }

 

        void ModMan_OnModuleLoadError(object sender, ModuleErrorEventArgs e)

        {

            this.statusText.Text += e.Exception.Message;

        }

 

        void ModMan_OnModuleDownloadFailed(object sender, EventArgs e)

        {

            this.statusText.Text += "Cannot download module";

        }

 

        void ModMan_OnAllModulesLoaded(object sender, EventArgs e)

        {

            try

            {

                Modman moduleManager = sender as Modman;

                foreach (IModule module in moduleManager.ModulesInstances)

                {

                    Control ctrl = module.MainControl;

 

                    ctrl.SetValue<double>(Canvas.LeftProperty, 50);

                    ctrl.SetValue<double>(Canvas.TopProperty, 50);

                    ctrl.Visibility = Visibility.Visible;

 

                    this.Children.Add(ctrl);

                }

            }

            catch (Exception ex)

            {

                this.statusText.Text += ex.Message;

            }

        }

    }

Et voilà, nous avons une application Silverlight complètement modulaire ! Les modules sont libres de personnaliser le contrôle qu'ils veulent mettre à disposition, tandis que l'application centrale garde la main sur la disposition de ces derniers dans la Canvas principal. De plus, il suffit de modifier le WebService en filtrant la liste des modules qu'il retourne pour apporter une logique métier aux modules activés (selon l'utilisateur par exemple).

Adrien


Classé sous

[Silverlight] Créer une application modulaire (Partie 1)

Lorsque l'on souhaite écrire une application modulaire en Silverlight, deux questions essentielles se posent :

  • Comment charger dynamiquement les DLL des modules ?
  • Comment récupérer le contrôle XAML correspondant ?

Nous allons voir dans ce billet une solution qui répond à ces deux questions.
La première chose à faire est de définir l'interface dont héritera tous nos modules :

    public interface IModule

    {

        string Name { get; }

        string Description { get; }

        string Version { get; }

        string Author { get; }

        System.Windows.Controls.Control MainControl { get; }

    }

Jusque là, rien de bien méchant, on a quatre propriétés pour les informations générales, et une cinquième qui va nous retourner un objet Control. Ce dernier hérite indirectement de Visual, et peut donc être directement ajouté aux enfants d'un objet Canvas. De plus, il a l'avantage d'implémenter une méthode InitializeFromXaml qui prend en paramètre une chaine de caractères correspondant au XAML et qui retourne un objet FrameworkElement.

Voyons à présent l'implémentation d'un tel module. In fine, un module est constitué d'une classe implémentant l'interface IModule définie ci-dessus, et d'un Control. Ainsi, nous allons ajouter à notre projet un fichier XAML et son fichier source associé, et fixer l'action de génération pour le XAML comme ressource incorporée.

Cela va permettre de récupérer le contenu du fichier XAML dans le code pour générer l'objet FrameworkElement associé au Control grâce à la méthode InitializeFromXaml dont je vous parlais plus haut.

MainControl.xaml :

<Canvas x:Name="parentCanvas"

        xmlns="http://schemas.microsoft.com/client/2007"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Width="250"

        Height="20"

        Background="White"

        >

  <TextBlock x:Name="Label" Text="Hello World !"></TextBlock>

</Canvas>

MainControl.xaml.cs :

    public class MainControl : Control

    {

        private FrameworkElement _actualControl;

 

        public MainControl()

        {

            System.IO.Stream s = this.GetType().Assembly.GetManifestResourceStream("ModuleSample.MainControl.xaml");

            _actualControl = this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd());

 

            _actualControl.Cursor = Cursors.Hand;

 

            TextBlock btnLabel = _actualControl.FindName("Label") as TextBlock;

            btnLabel.Text = "Control from Module Sample";

        }

    }

 ModuleSample.cs :

    public class ModuleSample : IModule

    {

        #region IModule Membres

 

        string IModule.Name

        {

            get { return "Module Sample"; }

        }

 

        string IModule.Description

        {

            get { return "This is just a sample of a module implementation."; }

        }

 

        string IModule.Version

        {

            get { return "1.0.0.0"; }

        }

 

        string IModule.Author

        {

            get { return "Adrien Siffermann"; }

        }

 

        Control IModule.MainControl

        {

            get { return new MainControl(); }

        }

 

        #endregion

    }

Voilà pour notre petit module. Il va s'agir maintenant de récupérer tout cela dans notre application principale Silverlight et d'ajouter le Control créé dans notre Canvas principal.

En fait, nous allons ajouter notre DLL du module dans le répertoire ClientBin de la Web Application hôte, et publier depuis cette dernière un WebService qui retourne une liste de tous les modules disponibles. En l'occurence, j'ai juste créer une liste de listes de chaines de caractères que je remplis en dur pour l'exemple, mais on peut très bien imaginer que cette méthode scanne le répertoire ClientBin, ou aille chercher en base de données une liste des modules enregistrés... On a donc pour chaque module l'information de son nom ainsi que du nom complet et de l'URI relative de son assembly.

    [WebService(Namespace = "http://tempuri.org/")]

    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

    [ToolboxItem(false)]

    [ScriptService]

    public class Modman : WebService

    {

        [WebMethod]

        [ScriptMethod]

        public List<List<string>> GetModulesList()

        {

            List<List<string>> resultList = new List<List<string>>();

 

            List<string> list = new List<string>();

            list.Add("Sample");

            list.Add("ModuleSample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");

            list.Add("ClientBin/ModuleSample.dll");

            resultList.Add(list);

 

            return resultList;

        }

    }

Dans le prochain billet, nous verrons comment, à partir de la liste des modules récupérée depuis le WebService, nous allons pouvoir les télécharger au chargement de la page, puis incorporer les Control que ces derniers dispensent dans le Canvas principal.

Adrien 


Classé sous

[Présentation] Visual Studio 2008 et le framework 3.5

Une fois n'est pas coutume, ce billet ne sera pas technique... En effet, je voulais vous annoncer que nous organisons une présentation sur Visual Studio 2008 et le framework 3.5 avec mes collègues David Verrière et Arnaud Auroux.

Au programme :

  • Introduction à Visual Studio 2008
  • Les nouveautés du C# 3.0
  • Focus sur Linq
  • Introduction à Windows Presentation Foundation
  • Introduction à Silverlight

Cette présentation, destinée aux personnes qui souhaitent découvrir ces nouvelles technologies, aura lieu Jeudi 07 Février à partir de 18h à 20h dans les locaux d'Epitech, 24 rue Pasteur - 94270 Le Kremlin Bicêtre.

J'espère vous y voir nombreux !

Adrien

SPListItem.Update() jette une Exception "L'opération n'est pas valide en raison de l'état actuel de l'objet"

J'ai été confronté aujourd'hui à une exception jetée sur un bout de code pourtant bien anodin et commun : l'ajout d'un nouvel élément à une liste.
Pour être plus précis, c'est la mise à jour des champs de cet élément à l'intérieur d'un bloc SPSecurity.RunWithElevatedPrivileges qui provoquait cette exception.

Après quelques essais infructueux et quelques recherches, il s'avère que sortir la création et la mise à jour des champs de mon élément en dehors du bloc résout le problème. Ainsi, on ne fait que l'instanciation du SPSite et du SPWeb dans le bloc SPSecurity.RunWithElevatedPrivileges, comme dans l'exemple de code ci-dessous :

        public string CreateNewListItem()

        {

            string result = "";

            SPWeb rootWeb = null;

 

            SPSecurity.RunWithElevatedPrivileges(delegate()

            {

                using (SPSite site = new SPSite("http://localhost"))

                    rootWeb = site.RootWeb;

            });

 

            SPList list = rootWeb.Lists["Sample List"];

            if (list != null)

            {

                try

                {

                    rootWeb.AllowUnsafeUpdates = true;

 

                    SPListItem item = list.Items.Add();

                    item["Title"] = "Update OK";

                    item.Update();

 

                    rootWeb.AllowUnsafeUpdates = false;

                }

                catch (Exception ex)

                {

                    result = "ListItem cannot be created (" + ex.Message + ") !";

                }

            }

            else

                result = "List 'Sample List' cannot be found !";

 

            rootWeb.Dispose();

            return result;

        }

A vrai dire, je n'arrive pas à comprendre pourquoi faire la création et la mise à jour de l'élément dans le bloc SPSecurity.RunWithElevatedPrivileges ne fonctionne pas, et je trouvais ce "tourne-autour" assez particulier pour être publié...

Adrien

Un petit nouveau...

Pour mon premier post sur mon premier blog, il est de rigueur que je vous serve une rapide présentation de qui je suis, et de ce que je compte poster sur ce blog...

Je m'appelle Adrien Siffermann et j'ai 23 ans. Je suis actuellement étudiant en 4ème année à Epitech, et je travaille en alternance à Winwise dans le pôle collaboratif.
Ainsi, même si ma formation est assez hétéroclite en matière de technologies, mon intérêt se porte plus particulièrement sur SharePoint et l'Office System. Dans le cadre de mes études, je mène également un projet de WebOS en Silverlight.

Vous l'aurez donc compris, sur ce blog je vous parlerai essentiellement de Windows SharePoint Service 3.0, de Microsoft Office SharePoint Server 2007, mais aussi de Silverlight et de .Net en général...

Je remercie au passage Philippe et Florent qui m'ont orienté vers Codes Sources pour mon blog, et Cyril qui m'a permit de l'ouvrir.


Les 10 derniers blogs postés

- Un outil pour réaliser des animations WPF basées sur des équations de Bézier par Perspective le il y a 3 heures et 20 minutes

- Sandcastle et CodePlex : le verdict par CoqBlog le il y a 4 heures et 11 minutes

- Webcasts sur le Parallel Framework disponibles par Matthieu MEZIL le il y a 7 heures et 39 minutes

- [Silverlight] - Comprendre et Débuter avec Silverlight par Danuz le il y a 12 heures et 24 minutes

- SharePoint : Nouvel article sur l'exportation et Importation de sites SharePoint par Blog Technique de Romelard Fabrice le 07-04-2008, 01:00

- ImagineCup 2008 Final in Paris: Day 1 par Richard Clark le 07-03-2008, 22:48

- PowerShell : Comment utiliser un ENUM .NET dans un script PowerShell par Blog Technique de Romelard Fabrice le 07-03-2008, 18:09

- OU SONT LES VISITEURS DE MON SITE ? par Nix's Blog le 07-03-2008, 15:07

- PowerShell : Quelques outils de développement adaptés par Blog Technique de Romelard Fabrice le 07-03-2008, 14:50

- [DevWeb] "FireFox est lent quand je developpe en local ?" par The diary of EBArtSoft le 07-03-2008, 14:47