Module – Forcer la mise à jour


Dans un projet, il n’est pas rare d’utiliser une feature de provisioning (une feature permettant le déploiement en masse de pages layouts, images, javascript, css, etc..).

Une fois ces fichiers déployés sur votre environnement, ils sont accessibles via votre code pour vous permettre de faire votre propre design. De plus, une fois les fichiers présents, ils sont toujours “vivants”, rien ne vous empêche par exemple, d’aller récupérer votre fichier css dans la bibliothèque adéquate pour faire des modifications à la volée et changer le rendu de votre site. Jusque-là, pas de soucis.

Mais que se passe-t-il lorsque vous déployez une mise à jour de votre wsp après avoir modifié votre fichier css via l’interface ?

Là, on se rend compte que les css, pages et autres documents que nous avons modifiés ne sont pas mis à jour par la feature ! La raison est simple, lors du déploiement de votre premier wsp, les éléments sont présents dans votre site (là où votre feature deprovisioning les a placé) et dans le dossier 12. De plus, ces éléments sont ghostés.
Quand un élément est ghostéSharePoint fait le lien directement avec ceux présents dans le 12 et non ceux présents dans les listes sur le site. Mais une fois que vous avez modifié votre css via l’interface, le lien est changé et SharePoint pointe maintenant vers le fichier présent dans le site. Fichier qui n’est pas mis à jour lors de l’update de votre wsp vu que c’est celui sur le disque qui est mis à jour.

Cette situation a ses bons côtés comme ses mauvais, mais si vous voulez forcer la mise à jour des documents, il suffit d’ajouter le bout de code suivant en feature receiver.

Lors de l’activation de la feature, le code va récupérer l’ensemble des données du fichier elements associé qui sont de type module (le type utilisé pour uploader des fichiers. Voir le tuto de sébastien a ce sujet) pour les uploader “manuellement”.

Tout d’abord, vérifiez la présence des 2 using suivants

 
using System.Xml; 
using System.Xml.Linq; 

Contenu du feature receiver :

 
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
    try
    {
         
        if (properties != null)
        {
            using (SPSite currentSite = (SPSite) properties.Feature.Parent)
            {
                using (var web = currentSite.OpenWeb())
                {
                    var ElementDefinitions =
                        properties.Definition.GetElementDefinitions(CultureInfo.CurrentCulture);

                    foreach (SPElementDefinition ElementDefinition in ElementDefinitions)
                    {
                        if (ElementDefinition.ElementType == "Module")
                        {
                            Helper.UpdateFilesInModule(ElementDefinition, web);
                        }
                    }
                }

            }
        }

                
    }
    catch
    { 
        //catcher et logger l'erreur
    }
}

Classes à ajouter

 
internal static class Helper
{
    internal static void UpdateFilesInModule(SPElementDefinition elementDefinition, SPWeb web)
    {
        XElement xml = elementDefinition.XmlDefinition.ToXElement();
        XNamespace xmlns = "http://schemas.microsoft.com/sharepoint/";
        string featureDir = elementDefinition.FeatureDefinition.RootDirectory;
        Module module = (from m in xml.DescendantsAndSelf()
                            select new Module
                            {
                                //récupère les données du module courant a partir des données récupérée dans la définition
                                ProvisioningUrl = m.Attribute("Url").Value,
                                PhysicalPath = Path.Combine(featureDir, m.Attribute("Path").Value),
                                Files = (from f in m.Elements(xmlns.GetName("File"))
                                        select new Module.File
                                        {
                                            //recupère les données de chaque fichier présent dans le module
                                            Name = f.Attribute("Url").Value,
                                            Properties = (from p in f.Elements(xmlns.GetName("Property"))
                                                        select p).ToDictionary(
                                                            n => n.Attribute("Name").Value,
                                                            v => v.Attribute("Value").Value)
                                        }).ToArray()
                            }).FirstOrDefault();

        if (module == null)
        {
            return;
        }

        foreach (Module.File file in module.Files)
        {
            string physicalPath = Path.Combine(module.PhysicalPath, file.Name);
            string virtualPath = string.Concat(web.Url, "/", module.ProvisioningUrl, "/", file.Name);

            //verifie si le lien fourni pointe bien vers un fichier présent dans la deature
            if (File.Exists(physicalPath))
            {
                using (StreamReader sreader = new StreamReader(physicalPath))
                {
                    //met le fichier présent sur le site en checkout si ce n'est pas déja le cas
                    if (web.GetFile(virtualPath).CheckOutStatus == SPFile.SPCheckOutStatus.None) web.GetFile(virtualPath).CheckOut();
                    //upload du fichier
                    SPFile spFile = web.Files.Add(virtualPath, sreader.BaseStream, new Hashtable(file.Properties), true);
                    //checkin du fichier (avec "Updated" comme commentaire)
                    spFile.CheckIn("Updated", SPCheckinType.MajorCheckIn);

                    //approuve le fichier (avec "Updated" comme commentaire) si requis
                    if (spFile.Item.ParentList.EnableModeration) spFile.Approve("Updated");

                    spFile.Update();
                }
            }
        }
    }

    public static XElement ToXElement(this XmlNode node)
    {
        XDocument xDoc = new XDocument();

        using (XmlWriter xmlWriter = xDoc.CreateWriter())

            node.WriteTo(xmlWriter);

        return xDoc.Root;

    }
}

public class Module
{
    public string ProvisioningUrl { get; set; }
    public string PhysicalPath { get; set; }
    public File[] Files { get; set; }

    public class File
    {
        public string Name { get; set; }
        public Dictionary Properties { get; set; }
    }
}

Maintenant vos fichiers seront correctement mis à jour.

Christopher.

Article initialement posté le 19/05/2011 sur Areaprog

Cet article, publié dans SharePoint 2007, est tagué , , . Ajoutez ce permalien à vos favoris.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s