Monday, February 6, 2012

Sitecore Fetch Squad

Automated crawler fetching websites and blogs from Sitecore content

Archive for the ‘Sitecore Blogs’ Category

Sitecore Media Library Performance Optimization Checklist

Posted by admin On October - 30 - 2011
Here is a quick checklist that you can use in order to get more performance out of your Sitecore Media Library’s delivery.

media_library
1. Ensure data/item/prefetch caches are of a sufficient size.

2. Ensure client caching is properly configured (MediaResponse.XXX settings).
3. Media Library structure – make sure the tree is balanced.
4. Change MediaLinkPrefix from ~/media to something else, for example “-/media”:

- set the value of the “Media.MediaLinkPrefix” to alternative prefix:

<setting name="Media.MediaLinkPrefix" value="-/media" /> 

-add the following line to the customHandlers section:

<customHandlers>
   <handler trigger="-/media/" handler="sitecore_media.ashx" />
   <handler trigger="~/media/" handler="sitecore_api.ashx" /></customHandlers>
This really helps for high traffic websites. Apparently tilde in the path forces different way of resolving the system permissions on a resource on Windows Server.
5. Consider IIS kernel and/or output caching, but keep in mind this consideration.

6. Consider adding other edge caching options in front of the web servers.
7. Leverage CDN like AKAMAI.

Some links and food for thought:

8. Use dedicated “Sitecore media server” (e.g. replace hostname in media links to point to another Sitecore instance; would require some customization).

Some great stuff here:

Thanks to the guys from our brilliant customer service for helping me to come up with a more complete list.


Consulting and Supporting Sitecore Developer Community

Sitecore North America Technical Insider Call

Posted by admin On October - 30 - 2011
top secret folderSitecore USA will be conducting a brief 30 minute call for Sitecore Certified Developers tomorrow at 10 AM Pacific. Here is what we will be covering:
- Some quick announcements
- State of the Union on Sitecore recommended version (new stuff)
- Sneak preview of the brand new and completely awesome Data Access Training
- Update to Search Extension Shared Source Project aka AdvancedDatabaseCrawler v2

If you are interested and not yet registered, follow this link.

In order to register for all future NA Technical Insider Calls, use the following landing page:
http://www.sitecore.net/Landing/Sitecore_Insider

Consulting and Supporting Sitecore Developer Community

Changing Field Sharing Settings in Sitecore

Posted by admin On October - 30 - 2011
So I’ve been working on a C# script which job is to change field value sharing settings on a Sitecore template field from Versioned to Shared, something you can do in the Template Manager application by checking the Shared checkbox and saving.
image
One thought came to me. What will actually happen if I have two language versions of single item with two different values? Consider the following example. I have a versioned image field with two different values in en-US and es-ES:
SNAGHTML20110fe0
So what would be the end result of making the “Image” field shared? It’s actually pretty interesting what happens after you save an item that is a template field definition.

So when a field definition item is saved, DataEngine is firing “ItemSaved” event, and the TemplateEngine has a handler for it which basically checks if either “Unversioned” or “Shared” attributes of the field definition item were changed. If there were, it runs the process of updating the field sharing settings which eventually trickles down to the data provider level where the call is made to a specially designed “FieldSharingConveter” class.

If we are making a versioned field shared, the following method is called:

  • MakeSharedFromVersioned(ID fieldId)
    • MoveDataToSharedFromVersioned(ID fieldId, ID itemId)
      within here there is a SQL query that basically selects the field value from the most recently updated version of the same item.

So basically in order to minimize data loss situations, Sitecore will always use the most recent field value for new shared value. Thought it’s rather interesting.

Consulting and Supporting Sitecore Developer Community

Partial Language Fallback Module Update

Posted by admin On October - 30 - 2011
Today I pushed a small update to the Partial Language Fallback module which I introduced a while back. Check out this quick screencast below. For the full list of changes hit “read more”.
image

Included changes:

  • Instead of weird looking yellow valid bar that is meant to highlight a fallback field value is now deprecated in favor of a much better integrated label next to the field title:

image

  • Default configuration changes:
    • The “enableFallback” parameter on the “website” is now set to “true” by default
    • renderContentEditor pipeline changes for the grayed out label to work.
  • Fixed a problem with fallback values picked up from SV when fallback item had no versions (thanks Steve)
  • Misc code refactoring
  • Sitecore package for 6.4 is now included. Thanks Nick!

Enjoy!

Consulting and Supporting Sitecore Developer Community

Unapproved content gets published [Friday Case]

Posted by admin On October - 30 - 2011
Today in a Friday Case category, which features support cases causing to pull my hair out, a very interesting issue I’ve had with a customer reporting that unapproved content was going live quite unexpectedly.
After witnessing the issue with my own eyes when an item just created and not pushed via workflow was magically showing up in production after a few minutes, I decided to investigation Sitecore configuration. This revealed a PublishAgent that was enabled to run frequently, but nothing else.

<agent type="Sitecore.Tasks.PublishAgent" method="Run" interval="00:01:00">
   <param desc="source database">master</param>
    <param desc="target database">web</param>
    <param desc="mode (full or incremental)">incremental</param>
    <param desc="languages">en, da</param>
</agent>

After reproducing this on a local single server instance, I’ve narrowed it down to the “languages” parameter being the issue.
By default all PublishAgents configured with both “English” and “Danish” languages processed. What happens within the PublishAgent is pretty interesting.
1. The “languages” parameter (“en, da”) is parsed with the following code:

private static List<Language> ParseLanguages(string languages)
{
    List<Language> list = new List<Language>();
    foreach (string str in languages.Split(new char[] { ',' }))
    {
        if (str.Length > 0)
        {
            list.Add(Language.Parse(str.Trim()));
        }
    }
    return list;
}

2. Down below, the Parse() method calls Language.TryParse() which basically boils down to the following checks:

if (LanguageManager.IsValidLanguageName(name))

if (LanguageManager.LanguageRegistered(name))

if (LanguageManager.RegisterLanguage(name))

If all these checks pass, the language name is considered to be valid. What’s interesting here is that even languages that are not created/registered within Sitecore under /system/languages will be parsed successfully. In our case there is no language with ISO code “da” created/registered in Sitecore, however, as far as Language.TryParse() is concerned, this language is valid and will be passed onto the publisher.
The publisher will try and get an item in “da” language from ItemManager for further processing. Due to the nature of Sitecore to decouple items from versions, this operation will actually return an item. This item will be returned as “empty” or “naked” with no versions, but there will be an instance.
So the publisher will process this item and treat it as “approved” and publish it to the target database.
While we can speculate on whether this is expected behavior or not, there is an easy solution for this problem. Simply make sure your PublishAgent is not configured to process any languages that do not exist within Sitecore. For our example this means modifying the “languages” parameter:

<agent type="Sitecore.Tasks.PublishAgent" method="Run" interval="00:01:00">
   <param desc="source database">master</param>
    <param desc="target database">web</param>
    <param desc="mode (full or incremental)">incremental</param>
    <param desc="languages">en</param>
</agent>

Hope this helps.

Consulting and Supporting Sitecore Developer Community

Sitecore Output Caching: Kick it up a Notch

Posted by admin On October - 30 - 2011
image Ever wondered how Sitecore caches works? It is pretty cool, actually. Sitecore can cache the output of any presentation component that it is aware of (Sublayout, WebControl, XSL Rendering). Basically, this output may vary on data context (Context Item or Datasource), device, whether user is logged in or not, parameters passed to the rendering, query string and Context user:
This gives a ton of options and in most cases this is sufficient, but what if the output of your rendering depends on inner logic embedded within the control? Sometimes you could solve this with VaryByParm and by passing different parameters to the rendering, but what if that’s not the case?
This is exactly the use case I have been presented during another onsite visit with a customer.
Here is a very simple way of extending the cache variation logic for a Sublayout.
If you are Sitecore blackbelt, consider moving on to the “Solution” part below.
Consider the following example.
We have a new list control which we want to personalize by “audience”. When user is authenticated, we imagine a process that “attaches” the current user session with a particular “audience type” and saves this in a cookie. In order to simulate this, I’ve created a control called “AudienceSwitcher” which sets the current “Audience Type” explicitly for this sake of this example:
SNAGHTML155c400
Whenever “Audience Type” changes, the following method is called:

AudienceManager.SetCurrentAudience(selectedAudience);

AudienceManager is a custom class that incorporates all audience related actions, very simple:

public class AudienceManager {
 
  private const string Key = "audience";
 
  public static string CurrentAudienceName {
      get
      {
         var key = CurrentAudienceKey;
         if (ID.IsID(key)){
            var audienceItem = Sitecore.Context.Database.GetItem(key);
            if (audienceItem != null) return audienceItem.DisplayName;
         }
            return string.Empty;
         }
      }
 
      public static string CurrentAudienceKey {
         get { return WebUtil.GetCookieValue(Key) ?? AudienceTypes.Consumer; }
      }
 
      public static void SetCurrentAudience(string audience){ 
        WebUtil.SetCookieValue(Key, audience);
      }
}

This has an effect on the NewsList control, which renders only the news items that are targeted to a specific audience type:

&lt;asp:Repeater ID="NewsRepeater" runat="server"&gt;
   &lt;ItemTemplate&gt;
      &lt;li&gt;&lt;% DataBinder.Eval(Container.DataItem, "Name") %&gt;&lt;/li&gt;
   &lt;/ItemTemplate&gt;
&lt;/asp:Repeater&gt;
protected void Page_Load(object sender, EventArgs e)
{
   if(!IsPostBack)
   {
      var news = Sitecore.Context.Database.SelectItems("/sitecore/content/home/news//*[contains(@audiencetype, '{0}')]".FormatWith(AudienceManager.CurrentAudienceKey));
 
      NewsRepeater.DataSource = news;
      NewsRepeater.DataBind();
   }
}

All news items are stored under /home/news and tagged to an audience via a multilist:
image
The “Audience Types” referenced from the multilist above are stored in a separate area in the content tree:
image
After verifying that our NewsList control is working correctly and displaying different news for different audiences:
for consumer:
image
for travel agent
SNAGHTML1647516
Let’s try and cache it this rendering by checking Cacheable and VaryByData.
image
If you don’t run live mode, you would need to publish after this.
The expected result of this configuration will not be satisfactory. The same output of the NewsList control will be cached once and served up from memory every time it is rendered, no matter what the current “Audience Type” is.
Here is the solution.
1. Subclass the default Sublayout implementation:

   1: public class AudienceSublayout : Sitecore.Web.UI.WebControls.Sublayout
   2: {
   3:    public override string GetCacheKey()
   4:    {
   5:       SiteContext site = Sitecore.Context.Site;
   6:       if ((Cacheable &amp;&amp; ((site == null) || site.CacheHtml)) &amp;&amp; !SkipCaching())
   7:       {
   8:          if (VaryByParm)
   9:          {
  10:             return base.GetCacheKey() + "_#audience:" + AudienceManager.CurrentAudienceKey;
  11:          }
  12:  
  13:          return base.GetCacheKey();
  14:       }
  15:  
  16:       return string.Empty;
  17:    }
  18: }

Very basic what we do here. We override the default implementation of the GetCacheKey method which is evaluated by Sitecore’s output caching mechanism every time a control needs to get cached. The key returned by this method needs to uniquely identify the control’s output in the cache collection.
Line 10 is the most important, this is where we call our friend AudienceManager and reading the current audience key (basically a value from cookie).
2. It’s important to note that this is done only if “VaryByParm” is checked on the control definition item in Sitecore, so we need to make sure it is checked:
image
The last thing you need to do is to wire in the custom AudienceSublayout by overriding the “SublayoutRenderingType” component:
3. Compile the following class:

   1: public class SublayoutRenderingType : Sitecore.Web.UI.SublayoutRenderingType
   2: {
   3:    public override System.Web.UI.Control GetControl(NameValueCollection parameters, bool assert)
   4:    {
   5:       var sublayout = new AudienceSublayout();
   6:       foreach (string key in parameters.Keys)
   7:       {
   8:          ReflectionUtil.SetProperty(sublayout, key, parameters[key]);
   9:       }
  10:       return sublayout;
  11:    }
  12: }

The only think we change here is line 5. Instead of the default Sublayout we instantiate our custom AudienceSublayout.
4. Define custom SublayoutRenderingType in web.config, line 3:

   1: &lt;renderingControls&gt;
   2:  &lt;control template="method rendering" type="Sitecore.Web.UI.WebControls.Method, Sitecore.Kernel" propertyMap="AssemblyName=assembly, ClassName=class, MethodName=method"/&gt;
   3:  &lt;control template="sublayout" type="SearchDemo.SublayoutRenderingType, SearchDemo" propertyMap="Path=path" /&gt;
   4:  &lt;control template="url rendering" type="Sitecore.Web.UI.WebControls.WebPage, Sitecore.Kernel" propertyMap="Url=url"/&gt;
   5:  &lt;control template="xsl rendering" type="Sitecore.Web.UI.XslControlRenderingType, Sitecore.Kernel" propertyMap="Path=path"/&gt;
   6:  &lt;control template="webcontrol" type="Sitecore.Web.UI.WebControlRenderingType, Sitecore.Kernel" propertyMap="assembly=assembly, namespace=namespace, class=tag, properties=parameters"/&gt;
   7:  &lt;control template="xmlcontrol" type="Sitecore.Web.UI.XmlControlRenderingType, Sitecore.Kernel" propertyMap="controlName=control name, properties=parameters"/&gt;
   8: &lt;/renderingControls&gt;

That’s all you need to do. Now the output of the NewsList control will vary depending on the current “Audience Type”.
Here is where you can download all the sources for this post:
http://resources.alexshyba.com/blog/CustomVaryByCaching.zip
Obviously, this is only one way of doing it. If you have other ideas, please share in the comments below.
Have a great weekend!
Further reading:

Consulting and Supporting Sitecore Developer Community

Windows Authentication for Sitecore. Repost

Posted by admin On October - 30 - 2011
Back in 08 I posted this walkthrough on how to configure Sitecore to use Windows Authentication for SQL connection and effectively remove the username and password from the connectionStrings.config file.
Here is a quick repost of the walkthrough with a few tweaks for SQL 2008 / Windows 2008 (R2) and Sitecore 6.4.x/6.5 (some steps are not required any more):

  1. Find the application pool that your Sitecore is running under. Open Properties and set the identity to the domain user on the corresponding tab.
  2. On the SQL Server box register the domain user and grant security permissions on Sitecore databases for the domain user according to the section “4.4.1 Creating a Database Account for Sitecore CMS Databases on SQL Server 2008” of the Installation Guide.
  3. On the machine that hosts Sitecore add this domain user to the IIS_IUSRS group.
  4. Adjust the permissions for the IIS_IUSRS group according to these sections of the Installation Guide“:
    4.2.2 File System Permissions for ASP.NET Requests”
    “4.2.3 File System Permissions for System Folders”.
  5. Edit the /App_Config/ConnectionStrings.config file and replace the user id and password parameters with the trusted_connection=yes option:
    <?xml version="1.0" encoding="utf-8"?>
    <connectionStrings>
    <add name="core" connectionString="Data Source=.\sql2008;Database=Sandbox6_Core;Trusted_Connection=Yes" />
    <add name="master" connectionString="Data Source=.\sql2008;Database=Sandbox6_Master;Trusted_Connection=Yes" />
    <add name="web" connectionString="Data Source=.\sql2008;Database=Sandbox6_Web;Trusted_Connection=Yes" />
    </connectionStrings>
  6. Prepare your identity so it can be used as a service account with “aspnet_regiis.exe” and the -ga switch.
  7. Add your domain service account to the local “Performance Monitor Users” group as per this section: “4.2.5 Windows Registry Permissions”

Important note:
This walkthrough describes basic Sitecore configuration with no modules or OMS/DMS installed. Additional security permissions are required for the modules and other components that carry their own databases.
HTH.

Consulting and Supporting Sitecore Developer Community

Sitecore Developer Network Search just got a bit better

Posted by admin On October - 30 - 2011

We just pushed an update to the SDN search, which included greatly enhanced search within Sitecore Community Blogs, and integrated SDN Forum. Now you should be able to search against any Sitecore resource from one place!

image

Among other enhancements, we’ve improved search relevancy by tweaking a few settings and ignoring landing pages.

Hope you see the difference.

Feel free to provide feedback, especially if your own blog is not getting indexed by us.

Enjoy!

Consulting and Supporting Sitecore Developer Community

Web Forms File Upload: 2 Exceptions [Common Errors]

Posted by admin On October - 30 - 2011
If you are having trouble with the File Upload field within the Web Forms for Marketers module, specifically the form submission fails with a generic error, check your Sitecore log file. If you see either of the following two exceptions, there is a solution! Read on.

First exception:

4624 11:31:12 WARN  Object reference not set to an instance of an object.
Exception: System.NullReferenceException
Message: Object reference not set to an instance of an object.
Source: Sitecore.Forms.Custom
at Sitecore.Form.UI.Adapters.FileUploadAdapter.AdaptResult(Object value)
at Sitecore.Form.Core.Utility.FieldReflectionUtil.GetAdaptedResult(ID fieldID, Object value)
at Sitecore.Form.Core.Controls.Data.AdaptedControlResult..ctor(ControlResult result, Boolean simpleAdapt)
at Sitecore.Form.Core.Submit.SubmitActionManager.AdaptResult(IEnumerable`1 list, Boolean simpleAdapt)
at Sitecore.Form.Core.Submit.SubmitActionManager.ExecuteSaving(ID formID, ControlResult[] list, ActionDefinition[] actions, Boolean simpleAdapt, ID sessionID)
at Sitecore.Form.Core.FormDataHandler.ProcessData(SimpleForm form, ControlResult[] fields, ActionDefinition[] actions)

4624 11:31:12 WARN  Web Forms for Marketers: an exception: Object reference not set to an instance of an object. has occured while trying to execute an action.

This is most likely happening because you have two server configuration (separated CD from CM) and master database removed as per the Scaling Guide. The error happens in case if you did not configure the remote WFM service as per section 2.11 “Multiple Sitecore Instances” within the reference doc: http://sdn.sitecore.net/upload/sdn5/products/web_forms2/web%20forms%20for%20marketers%20v2_2%20reference-a4.pdf
Simply add the connection string to the web service and make sure that the following setting on CD instance(s) is set to “web”. This setting is defined within /App_Config/Include/forms.config file.

<!-- Sets the name of the master database  -->
<setting name="WFM.MasterDatabase" value="web"/>

Second exception:

2780 14:55:48 ERROR Could not save posted file: Desert.jpg
Exception: System.InvalidOperationException
Message: An instance of Sitecore.Data.Items.Item was null. Additional information: Could not create media folder: ‘D/Sitecores/WFFM 21/Website/sitecore/media library’.
Source: Sitecore.Kernel
   at Sitecore.Diagnostics.Assert.IsNotNull(Object value, Type type, String format, Object[] args)
   at Sitecore.Resources.Media.MediaCreator.CreateFolder(String itemPath, MediaCreatorOptions options)
   at Sitecore.Resources.Media.MediaCreator.CreateItem(String itemPath, String filePath, MediaCreatorOptions options)
   at Sitecore.Resources.Media.MediaCreator.CreateFromStream(Stream stream, String filePath, Boolean setStreamIfEmpty, MediaCreatorOptions options)
   at Sitecore.Resources.Media.MediaCreator.CreateFromStream(Stream stream, String filePath, MediaCreatorOptions options)
   at Sitecore.Form.Core.Media.MediaUploaderEx.UploadToDatabase(ICollection`1 list)
   at Sitecore.Form.Core.Media.MediaUploaderEx.Upload()
   at Sitecore.Form.Core.Pipelines.FormUploadFile.Save.Process(FormUploadFileArgs args)

2780 14:55:48 WARN  An instance of Sitecore.Data.Items.Item was null. Additional information: Could not create media folder: ‘D/Sitecores/WFFM 21/Website/sitecore/media library’.
Exception: System.InvalidOperationException
Message: An instance of Sitecore.Data.Items.Item was null. Additional information: Could not create media folder: ‘D/Sitecores/WFFM 21/Website/sitecore/media library’.
Source: Sitecore.Kernel
   at Sitecore.Diagnostics.Assert.IsNotNull(Object value, Type type, String format, Object[] args)
   at Sitecore.Resources.Media.MediaCreator.CreateFolder(String itemPath, MediaCreatorOptions options)
   at Sitecore.Resources.Media.MediaCreator.CreateItem(String itemPath, String filePath, MediaCreatorOptions options)
   at Sitecore.Resources.Media.MediaCreator.CreateFromStream(Stream stream, String filePath, Boolean setStreamIfEmpty, MediaCreatorOptions options)
   at Sitecore.Resources.Media.MediaCreator.CreateFromStream(Stream stream, String filePath, MediaCreatorOptions options)
   at Sitecore.Form.Core.Media.MediaUploaderEx.UploadToDatabase(ICollection`1 list)
   at Sitecore.Form.Core.Media.MediaUploaderEx.Upload()
   at Sitecore.Form.Core.Pipelines.FormUploadFile.Save.Process(FormUploadFileArgs args)
   at (Object , Object[] )
   at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
   at Sitecore.Form.UI.Adapters.FileUploadAdapter.AdaptResult(Object value)
   at Sitecore.Form.Core.Utility.FieldReflectionUtil.GetAdaptedResult(ID fieldID, Object value)
   at Sitecore.Form.Core.Controls.Data.AdaptedControlResult..ctor(ControlResult result, Boolean simpleAdapt)
   at Sitecore.Form.Core.Submit.SubmitActionManager.AdaptResult(IEnumerable`1 list, Boolean simpleAdapt)
   at Sitecore.Form.Core.Submit.SubmitActionManager.ExecuteSaving(ID formID, ControlResult[] list, ActionDefinition[] actions, Boolean simpleAdapt, ID sessionID)
   at Sitecore.Form.Core.FormDataHandler.ProcessData(SimpleForm form, ControlResult[] fields, ActionDefinition[] actions)

2780 14:55:48 WARN  Web Forms for Marketers: an exception: An instance of Sitecore.Data.Items.Item was null. Additional information: Could not create media folder: ‘D/Sitecores/WFFM 21/Website/sitecore/media library’. has occured while trying to execute an action.


This error may happen if:

  • You are running WFM earlier than 2.2.0 rev. 110303
  • “Media.UploadAsFiles” setting is set to “true”

As you may have guessed, this issue was fixed in 2.2.0 rev. 110303.
Hope this helps.

Consulting and Supporting Sitecore Developer Community

Sitecore Users Virtual Group

Posted by admin On October - 30 - 2011

If you guys have not seen this initiative, check it out: http://www.sitecoreug.org

The Sitecore Users’ Virtual Group is dedicated to supporting the Sitecore community wherever they exist across the globe. There are some great speakers lined up for our first sessions and all sessions are free of charge and conducted over the web. Here is the schedule.

The first presentation will take place next Wednesday, May 18, at 9:00 AM Pacific, Noon Eastern, or 5:00 PM UK time. John West, CTO of Sitecore North America, will discuss the state of Sitecore and the CMS marketplace. John has graciously agreed to answer your questions.

If you would like to attend, please register here.

Consulting and Supporting Sitecore Developer Community