Force module update


In one project, it is not uncommon to use a provisioning feature (a feature allowing mass deployment page layouts, images, javascript, css, etc. ..).

Once these files are deployed in your environment, they are accessible via your code so you can make your own design. Moreover, once the files are uploaded, they are still “alive”, nothing prevents you, for example, to go get your css file in the proper library to make changes on the fly and change the rendering of your site. Until then, no worries.

But what does it happend when you deploy an upgrade of your wsp after changing your css file via the interface?

Here, we realize that the css, pages and other documents that we have changed are not updated by the feature! The reason is simple, when you deploy your wsp first, the elements are present in your site (where you put the provisioning feature) and in the 12 hive. Moreover, these elements are ghosted.
When an element is ghosted, SharePoint make the link directly with those in the 12 and not those included in the lists on the site. But once you have changed your css via the interface, the link is changed and now points to the SharePoint file in the site. File is not updated during the update of your wsp since it is the one on the 12 hive which is updated.

This has its good sides as its bad, but if you want to force the update of documents, just add the following snippet in feature receiver.

Upon activation of the feature, the code will retrieve all the data file associated with Elements which are module type (the type used to upload files. See on this subject Sebastien’s tutorial) for upload “manually “.

First, check the presence of 2 using the following



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

Feature receiver content :



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
    }
}


Add a class



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; }
    }
}


Now your files will be updated

Christopher.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s