Tuesday, April 19, 2016

Sitecore and IIS URL Rewrite module

    URL Rewrite is quite popular IIS module. It is SEO tool that allows you to improve site crawling by search engines. You can do a lot of things using it:
  • Add or remove trailing slash
  • Enforce lower case URLs
  • Use canonical hostnames
  • Redirect to HTTPS
  • etc.
    But it should be used very carefully with big systems, where you are unable to control everything. As example I'll show which problems could cause thoughtless URL rewrite configuration with Sitecore. The example that is given below correspond only to configuration CM and CD on one machine, otherwise you are free to configure URL rewriting on CD, but don't do anything on CM.

    Simplest URL rewriting rule is "Remove Trailing Slash". You can add this rule by using predefined templates inside IIS embedded wizard.
  

    This rule redirect all requests from "http://yourawesomewebsite.com/page1/" to "http://yourawesomewebsite.com/page1". It helps to avoid of indexing one your page twice, wrong resolving it by analytics, etc. But URL Rewrite rules has one bad feature, while redirecting they transfer POST request to GET. Let see how it can breaks Sitecore functionality.

Sitecore 8 has List Manager Lanchpad  application. It uses MVC approach for communication client with server. And as good MVC practice controller action are marked with method attributes. Delete list, delete folder, move list and others are marked only with [HttpPost] attribute. They do not allow [HttpGet]. And unfortunately client side JavaScript code call this method with trailing slash. E.g.:

http://yourawesomewebsite.com/sitecore/api/ssc/ListManagement/Actions/%7B0264829E-6680-49EB-85B8-703EF9414BA5%7D/DeleteListById/

URL Rewrite module will remove trailing slash and translate this request from POST to GET. As result we will get error:



How this issue could be solved:
  1. Do not use URL Rewrite module with complex website which work you could not fully control. Or use only with a part of site that you fully control. It is CD part for Sitecore.
  2. Rewrite URL Rewrite rule. In our example it could be "^(((?!ListManagement).*)/$" instead of standard "(.*)/$"  
  3. Use URL Rewrite module alternatives, as example ISAPI_Rewrite

Saturday, April 16, 2016

Sitecore PageExtenders: non greedy approach

   There is great Sitecore feature: Page Extenders. It allows you to insert any HTML code to your pages. However inaccurate usage of it can harm your site.
   
    Once I installed Federated Experience Manager on Sitecore 7.2 I was unable to get it worked. For some reasons JavaScript on its pages failed. After deeper investigation I found that on any FxM request to server I got incorrect JSON. It was well formed, but at the end string
<input name="SC_ANALYTICS_PAGE" type="hidden" id="SC_ANALYTICS_PAGE" value="ecbb31a2-4c43-494d-88a1-811994213a89" /> 
was added. I figured out that this string was added by SBOS Accelerator module that was installed few days before. Reason of adding this string was greedy PageExеnder. It added this string everywhere, except few sites(shell, modules_shell). Such behavior also break some admin pages, e.g.: ShowConfig.aspx.

   After fixing this problem I can make conclusion: that in general it is much more better to specify where PageExtender should insert controls rather than specify where it should not insert controls. Even if you add a lot of exceptions, you could not cover by your exceptions everything that could appear in custom solutions. 

Wednesday, April 6, 2016

Sitecore Social Connected 2.1: Second Life

     After installation of Sitecore Social Connected 2.1 on Sitecore 7.2 following this reference (with few unusual steps for modules) I found out that I am not able to add Facebook and Twitter accounts. It was not a problem of this module. It was caused by changes in these social networks APIs. Trying to google solution I found it for Twitter. It was pretty easy, just replace one assembly with another.
   
    Error, that is appeared in log:
ERROR Value was either too large or too small for an Int32.
Exception: System.OverflowException
Message: Value was either too large or too small for an Int32.
Source: mscorlib
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Convert.ToInt32(String value)
   at TweetSharp.TwitterService.GetAccessToken(OAuthRequestToken requestToken, String verifier)
   at Sitecore.Social.Twitter.Networks.Providers.TwitterProvider.AuthGetAccessToken(AuthArgs args)
   at Sitecore.Social.Client.Connector.SocialLogin.ProcessRequest(HttpContext httpContext)

   Could be fixed in 2 steps:
  1. Downloading newer Social Connected 3.0 module
  2. Unzipping and replacing TweetSharp.dll in your Sitecore
   I tried to find some similar solution for error with Facebook API:
"Invalid Scopes: offline_access, publish_stream, read_stream. This message is only shown to developers. Users of your app will ignore these permissions if present. Please read documentation for valid permissions at https://developers.facebook.com/docs/facebook-login/permissions".
But there was no ready to use solution. Problem was inside:

private void AddPermissionsToRequest(GetAccountCredentialsRequest accountCredentialsRequest, string networkName)
{
 string a;
 if ((a = networkName.ToLowerInvariant()) != null)
 {
  if (a == "facebook")
  {
   accountCredentialsRequest.Permissions.Add("offline_access", string.Empty);
   accountCredentialsRequest.Permissions.Add("publish_stream", string.Empty);
   accountCredentialsRequest.Permissions.Add("manage_pages", string.Empty);
   accountCredentialsRequest.Permissions.Add("read_stream", string.Empty);
   return;
  }
...

Ok, it is only constants, lets change them:

  1. Open ILDASM
  2. Dump Sitecore.Social.Client, Version=2.1.0.0 to some.il file
  3. Replace "offline_access", "publish_stream", "read_stream" with "publish_pages", "user_posts", "public_profile". It is not strict correspondence, it should be deeply investigated, but these permissions will be enough to create and post social messages.
  4. Using ILASM, assemble some.il into Sitecore.Social.Client and copy it to our Sitecore bin folder
But after trying to add Facebook account we get new error message:

ERROR The given key was not present in the dictionary.
Exception: System.Collections.Generic.KeyNotFoundException
Message: The given key was not present in the dictionary.
Source: mscorlib
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at Sitecore.Social.Facebook.Networks.Providers.FacebookProvider.GetDisplayName(Account account)
   at Sitecore.Social.Facebook.Client.Wizards.AddNetworkAccount.PageControls.FacebookWaitForAuthPageControl.GetFacebookAccount(Application application, String accessTokenSecret)
   at Sitecore.Social.Facebook.Client.Wizards.AddNetworkAccount.PageControls.FacebookWaitForAuthPageControl.GetAccountDisplayName()
   at Sitecore.Social.Client.Wizards.AddNetworkAccount.PageControls.WaitForAuthPageControl.CheckAuthStatus()

   After investigation I figured out that problem is inside:

public string GetDisplayName(Account account)
{
 System.Collections.Generic.IDictionary<string, object> accountData = this.GetAccountData(account, "/me");
 if (accountData == null)
 {
  return null;
 }
 return string.Format("{0} {1}", accountData["first_name"], accountData["last_name"]);
}

   Now Facebook returns only "name" instead of "first_name" and "last_name" separately. Guess, how we will solve this problem? Following similar steps that we have for previous fix we get new version of Sitecore.Social.Facebook.dll assembly. After copying it to Sitecore bin folder we are able to add Facebook account, create and publish posts with it.

Yahoo! We gave Sitecore Social Connected 2.1 second life.

P.S. Probably it is not all problems that could appear with changes in Facebook and Twitter APIs, but described above method fixes at least part of them. Use this solution on your own risk!