28 November 2014

Configuration in SubFolder in the Include folder

I have been writing a previous post about the importance of Name for configuration files in the include folder. My usual habit was to prefix them with z. so all my custom files will be located at the last place (by alphabetical order). This means that those will be the last to be parsed which I can be sure to place any event or pipeline processor where I wanted. So my Include folder will looks like the following:


After reading a great post today from @jammykam, I wanted to share this:
You can create a folder and add all your custom files inside. From the Sitecore documentation (page 4), sitecore will first parse all the config file and then go recursively through subfolders:

When Sitecore reads the include files, it traverses the file system recursively. Sitecore first enumerates all the *.config files in the /App_Config/Include folder and then recursively enumerates all the sub-folders. You should take this order into account when you create sub-folders in the /App_Config/Include folder.
So creating a subfolder and moving the custom files inside will have the same effect than prefixing all my custom config:



27 November 2014

Sitecore 7.5 and Installing Packages through handler is broken


I was upgrading a 7.2 to 7.5 today and I noticed something unexpected that I wanted to share today.

As maybe a few of you, I am using TDS to generate my update packages for my deployments. This is awesome and We have a .ashx on our QA environment that automatically install those packages and publish items afterwards. Well, this was quite nice and working fine on Sitecore 7.2.

However, after upgrading the site to 7.5 I noticed that the solution was not compiling against the new Sitecore DLL.. And the reason was: SaveInstallationMessages() method was removed from the UpdateHelper on the Sitecore 7.5. So the following line was failing:

                    UpdateHelper.SaveInstallationMessages(entries, text);


If you compare the previous version of the Install() method from Sitecore.Update.InstallUpdatePackage

protected string Install()
{
 string result;
 using (new ShutdownGuard())
 {
  this.logEntries = new List();
  PackageInstallationInfo installationInfo = this.GetInstallationInfo();
  string text = null;
  List entries = null;
  try
  {
   this.WriteMessage(string.Format("{0} package: {1}", (installationInfo.Action == UpgradeAction.Preview) ? "Analyzing" : "Installing", installationInfo.Path), null, Level.INFO, false);
   entries = UpdateHelper.Install(installationInfo, this, out text);
  }
  catch (PostStepInstallerException ex)
  {
   entries = ex.Entries;
   text = ex.HistoryPath;
   throw ex;
  }
  finally
  {
   UpdateHelper.SaveInstallationMessages(entries, text);
  }
  result = text;
 }
 return result;
}

With the new version:

// Sitecore.Update.InstallUpdatePackage
protected string Install()
{
 string result;
 using (new ShutdownGuard())
 {
  this.logEntries = new List();
  PackageInstallationInfo installationInfo = this.GetInstallationInfo();
  string text = null;
  this.logMessages = new List();
  try
  {
   this.WriteMessage(string.Format("{0} package: {1}", (installationInfo.Action == UpgradeAction.Preview) ? "Analyzing" : "Installing", installationInfo.Path), null, Level.INFO, false);
   this.logMessages = UpdateHelper.Install(installationInfo, this, out text);
   base.InstallationHistoryRoot = text;
  }
  catch (PostStepInstallerException ex)
  {
   this.logMessages = ex.Entries;
   base.InstallationHistoryRoot = ex.HistoryPath;
   throw ex;
  }
  finally
  {
   this.SaveInstallationMessages();
  }
  result = text;
 }
 return result;
}

You can notice the SaveInstallationMessages is now defined on the control itself. This is a bit annoying as we cant re-use it in our handler anymore.
Since the UpdateHelper.Install is still outing the history path I could go around the issue by adding the SaveInstallationMessages() into our handler directly but that means duplication of methods. I would have prefered the old static method, but I could not find any other way for now...

        protected string Install(string package)
        {
            var log = LogManager.GetLogger("LogFileAppender");
            string result;
            using (new ShutdownGuard())
            {
                var installationInfo = new PackageInstallationInfo
                {
                    Action = UpgradeAction.Upgrade,
                    Mode = InstallMode.Install,
                    Path = package
                };
                string text = null;
                List entries = null;
                try
                {
                    entries = UpdateHelper.Install(installationInfo, log, out text);
                }
                catch (PostStepInstallerException ex)
                {
                    entries = ex.Entries;
                    text = ex.HistoryPath;
                    SC.Diagnostics.Log.Error("Automated Deployment error " + ex.StackTrace, "Automated deployment");
                    throw;
                }
                finally
                {
                    this.SaveInstallationMessages(entries, text);
                }

                result = text;
            }

            return result;
        }

        public string SaveInstallationMessages(System.Collections.Generic.List entries, string historyPath)
        {
            string text = System.IO.Path.Combine(historyPath, "messages.xml");
            FileUtil.EnsureFolder(text);
            using (System.IO.FileStream fileStream = System.IO.File.Create(text))
            {
                XmlEntrySerializer xmlEntrySerializer = new XmlEntrySerializer();
                xmlEntrySerializer.Serialize(entries, fileStream);
            }
            return text;
        }

14 November 2014

Sitecore 7.5 Image resizing changes


I am sure a few people already know about this but I just wanted to put it out there in case some f us are looking for it:

From Sitecore 7.5, the Image resizing is not working the way it was.

On previous version of Sitecore you would have been familiar with the resizing, passing the parameters in the URL:

http://mywebsite/~/media/imagesample.ashx?w=150
This will output the resized version of the image with a width of 150px. The usual parameters used for resizing are:

w = Width (in pixels)
h = Height (in pixels)
mw = MaxWidth (pixels)
mh = MaxHeight (pixels)
bc = Background Color
sc = Scale (floating point)
thn = Display as thumbnail


Well, as this was still the case in 7.2, I assumed it would be the same in 7.5... and obviously it id not... My bad as I did not read the release notes for this version. Thanks to Sitecore support who pointed me to the link... Here is the abstract that relates to the issue:

Media request protection
  • The new media request protection feature restricts media URLs that contain dynamic image-scaling parameters so that only server-generated requests are processed. This ensures that the server only spends resources and disk space on valid image scaling requests.
  • Sitecore Corp. wants to give credit to Cognifide (Adam Najmanowicz and Marek Musielak, www.cognifide.com) for the discovery of this vulnerability, for their cooperation and providing the initial ImageGuard solution.
  • When the feature is enabled, Sitecore automatically signs image URLs that are rendered by the <renderField> pipeline and adds a hash value to the query string. When processing an incoming media request, image resizing/scaling is skipped if any of the relevant query string parameters in the image URL have been altered or any extra resizing parameters have been appended to the URL. In these cases, Sitecore returns the original, unaltered image. Requests for the original image (without any resizing/scaling parameters) work as usual and are not restricted.
  • If you have code in your solution that manually appends image scaling parameters to image URLs without passing the parameters to the <sc:image> control, you must rewrite the code to append a hash value using one of the helper methods or rewrite it to use the <sc:image> control. In XSLT renderings, you can use sc:SignMediaUrl(url) or sc:GetSignedMediaUrl(…). In C# code, you can use HashingUtils.ProtectAssetUrl(url) which appends a hash value to the provided URL, or you can use GetAssetUrlHash(url) to only return the hash value for the provided URL.
  • You must ensure that any static image URLs (for example, in CSS or aspx files) that contain image scaling parameters are updated to include the corresponding hash value. To make it easy to update these type of static URLs, a new /sitecore/admin/MediaHash.aspx is available, which lets you enter a media URL and, with the click of a button, generate the corresponding hash value.
  • Image URLs where resizing parameters are manipulated or added using JavaScript will no longer work because you cannot calculate the hash values from JavaScript. If you need this type of functionality, you will have to find a different approach, such as implementing a service that can calculate the correct hash value.
  • This feature is configured in the /App_Config/Include/Sitecore.Media.RequestProtection.config file.

So if like me you used to pass the width o height in the URL, then you may have to revisit a few view rendering to ensure that you are now passing the Hash value.

So if you have a Model (Glass Map) like the following
using System;
using MyProject.Common.Constants;
using MyProject.Dal.Models.Base;
using Glass.Mapper.Sc.Configuration.Attributes;
using Glass.Mapper.Sc.Fields;

namespace MyProject.Models.ImageCarousel
{
    [SitecoreType(TemplateId = TemplateIds.DataElements.CarouselImage, AutoMap = true)]
    public class CarouselImage : SitecoreBase
    {
        [SitecoreField(FieldId = FieldIds.DataElements.CarouselImage.ImageBanner)]
        public virtual Image ImageBanner { get; set; }

        [SitecoreField(FieldId = FieldIds.DataElements.CarouselImage.DestinationUrl)]
        public virtual Link DestinationUrl { get; set; }

        [SitecoreField(FieldId = FieldIds.DataElements.CarouselImage.Description)]
        public virtual string Description { get; set; }
    }
}

Then you will be able to update your cshtml view to use:
        < img src="@Sitecore.Resources.Media.HashingUtils.ProtectAssetUrl(string.Format("{0}?w=150", Model.imagebanner.src))"  />