Friday, May 18, 2012

Sitecore Fetch Squad

Automated crawler fetching websites and blogs from Sitecore content

Archive for October, 2011

Upcoming Sitecore Users’ Virtual Group

Posted by admin On October - 30 - 2011

Exciting news! I was invited to present at the upcoming Sitecore Users’ Virtual Group which will be held next week on Wednesday (Oct 19th) at Noon Pacific, 3:00 PM Eastern, 8:00 PM UK. Thanks guys!
So the topic would be quite random, “Latest cool prototypes from Sitecore US lab”. Since I am not in product development, rather “on-the-field” kind of Sitecorian, don’t expect any of the new MVC, Sitecore 7, but expect the demos of the following components produced for the customer needs I witness during my consulting engagements with partners and customers:
- Updates on the following two hottest modules produced. Both contain some major enhancements based on your feedback (thank you)!

Sitecore.Search extension aka AdvancedDatabaseCrawler
Partial Language Fallback

- Other prototypes and super experimental stuff like ContentSilo, NameValueEx field, WorkflowBundle and more (if we have time)!
If this sounds interesting, see this event page for more details and click here to register. Space is limited.
Hope it will be informative and fun! See you soon.

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

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

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

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

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

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

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

Old Search is deprecated in Sitecore 6.5

Posted by admin On October - 30 - 2011
I’ve blogged about this before, now it’s official. If you have not seen this before, you can find the following in the Release Notes for 6.5:
The Sitecore.Data.Indexing namespace has been deprecated and will be removed in a future version of the CMS in favor of the more powerful and flexible Sitecore.Search classes and corresponding index definitions.


Now it’s a good time to revisit the functionality build on top of “old” search and re-implement it with Sitecore.Search namespace.
Related documentation:
http://sdn.sitecore.net/upload/sitecore6/sitecore_search_and_indexing-a4.pdf

Consulting and Supporting Sitecore Developer Community