Installing Sitecore 9 on Mircosoft Azure Cloud as PaaS : Know your options

Installing Sitecore 9 on Microsoft Azure Cloud as PaaS has never been easier than before. There are 2 main routes that you can take:

  1. Install via Azure Market Place
  2. Install via Sitecore Azure ARM Templates

I have blogged about both options 1 and option 2 previously, but with Sitecore 9 release there are some updates. This blog is just a follow up about the changes since last release and it is based upon Sitecore 9.0 and Sitecore Azure Toolkit 2.0.

Option 1 : Install via Azure Market Place

The Azure Market Place module for Sitecore has been updated with a nice 4 step wizard. The configuration wizard will ask you to choose your Sitecore version, choose your region, add your own credentials, review legal terms and conditions, click the magic button and let Azure do its business.

I believe any non-technical person with an Azure account can do this installation without any help or bugging IT to setup servers for Sitecore 9. Bonus information, you can tick the box for Sitecore Experience Accelerator 1.5 during the installation wizard and SXA will be installed as well for you to play around with 80+ pre-built components like Carousel, Gallery and so on. The following screen shot from the Azure portal is showing different resources that were deployed successfully after I ran the Sitecore installation wizard for Single  (CM & CD combined) size.

Option 2 : Install via Azure ARM Templates

This is slightly more technical option as you will need to manually configure ARM templates (read JSON files) and use Windows Powershell. I have blogged in detail about this earlier so I will not go in details this time. I will only mention what I found was different for Sitecore 9 installation and the issues I ran into during the installation process.

There were 2 changes:

  1. You have to supply a secure certificate’s blob and it’s password within the parameters file.
  2. You have to use ArmTemplateUrl parameter instead of ArmTemplatePath  for the Start-SitecoreAzureDeployment command.

As given on the Sitecore documentation site, you need to generate the self-assigned certificate, export it and get its blob. I have combined the scripts into a single script and added additional code to get the blob so you can easily get the required secure certificate blob by running the following script:

PS C:\azure\sitecore-azure-2.0> .\self-assigned-ssl.ps1

I wanted to deploy the XP topology so I updated the azuredeploy.parameters.json file on my local machine with information as below:

Then I created a xp1install.ps1 file with parameters and raw link to the ArmTemplateUrl from the quick start templates section: (this is optional step, you can enter these values directly in PowerShell too)

From the Windows Powershell command line, navigated to the Sitecore Azure Toolkit 2.0 folder and ran this command

PS C:\azure\sitecore-azure-2.0> .\xp1install.ps1

Waited about an hour or so and the XP installation was up and running on Microsoft Azure Platform.

 

If you look closely in the screen grabs above, 19 resources were deployed during the single type of installation and 31 resources were deployed during the XP installation.

Errors during Azure ARM

I ran into 2 errors during the Azure ARM deployment:

Error 1 – InvalidTemplate Error

Initially, I was using ArmTemplatePath and was providing the full path to the template on my local machine, but it turns out, that I needed to provide ArmTemplateUrl as mentioned in this blog. Supplying the correct parameter with Github’s path resolved this error.

Error 2 – Cannot find certificate

I was supplying the path to the certificate instead of the base64 encoded string. Thanks to the Sitecore Slack community that came to the rescue and I was able to resolve this by generating the secure certificate correctly and supplying it’s blob value.

I hope it is going to help if you are doing Azure ARM deployments with Sitecore 9 in coming days!

Thanks.

Advertisements

Sitecore : Adding a Twitter Pod using LINQ To Twitter

In almost all the projects I have done in past year or so, a common requirement among the clients have been that they want the ability to add Twitter Pods on pages and also have the ability to change the account name based upon their campaign or department.

For the purpose of the post, I will be using Sitecore CMS and LINQ To Twitter library to show how simple it is to create a Twitter Pod/module.

Let suppose we only want to display top  tweet from an account/twitter handle, which is define in the Sitecore CMS

Steps:

1. Create a data template property in the CMS as ‘Twitter Account Name’ or whatever you like

2. Create a standard .NET User Control and lets call it ‘TwitterPod.ascx’

3. Reference LINQ to Twitter library in your project (download it from here http://linqtotwitter.codeplex.com/ and also read its documentation)

4. As per Twitter API 2.0 you need to get Consumer Key, Consumer Secret, Access Token, Access Token Secret values from http://dev.twitter.com for any applications that you are creating. Log-in there and follow the steps to get these values.

5. Add these Twitter API 2.0  values to web.config

6. Let suppose this is your .ascx control markup

<div><asp:HyperLink ID="HyperLinkFollowAccount" runat="server" Target="_blank"></asp:HyperLink></div>

<div class="twitter">
<asp:HyperLink ID="HyperLinkFirstTweet" runat="server">
<p><asp:Literal ID="LiteralFirstTweet" runat="server"></asp:Literal>
<p>Posted <asp:Literal ID="LiteralFirstPostedTime" runat="server"></asp:Literal></p>
</asp:HyperLink>
</div>

7. Add these ‘static strings’ to your User Control class

private static string ConsumerSecret

{

get { return WebConfigurationManager.AppSettings["ConsumerSecret"]; }

}

private static string ConsumerKey

{

get { return WebConfigurationManager.AppSettings["ConsumerKey"]; }

}

private static string AccessToken

{

get { return WebConfigurationManager.AppSettings["AccessToken"]; }

}

private static string AccessTokenSecret

{

get { return WebConfigurationManager.AppSettings["AccessTokenSecret"]; }

}

8.  Twitter API 2.0 requires OAuth Authentication, to get that add this to Page_Load of your User Control

protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
try
{
var auth = new SingleUserAuthorizer
{
Credentials = new InMemoryCredentials
{
ConsumerKey = ConsumerKey,
ConsumerSecret = ConsumerSecret,
OAuthToken = AccessToken,
AccessToken = AccessTokenSecret
}
};

using (var twitterCtx = new TwitterContext(auth))
{
LoadTwitterFeeds(twitterCtx);
}
}
catch(Exception ex)
{
Sitecore.Diagnostics.Log.Error(ex.Message, this);
}
}
}

9.  LoadTwitterFeeds(twitterCtx) is your custom function where you can add your logic of getting tweets via Twitter API 2.0 and displaying them

10.

private void LoadTwitterFeeds(TwitterContext service)
{
try
{

string accountName = Sitecore.Context.Item["Twitter Account Name"] as string;

var tweets = (from tweet in service.Status

where tweet.ScreenName == accountName &&
tweet.Count == 1 &&
tweet.ExcludeReplies == true &&
tweet.IncludeRetweets == true &&
tweet.Type == StatusType.User
select tweet).FirstOrDefault();

if (tweets != null)
{

HyperLinkFollowAccount.NavigateUrl = "http://twitter.com/" + accountName.Replace("@", "");
HyperLinkFollowAccount.Text = "Follow " + accountName + " on Twitter";

LiteralFirstTweet.Text = tweets.Text;
LiteralFirstPostedTime.Text = tweets.CreatedAt.ToString();
HyperLinkFirstTweet.NavigateUrl = "https://twitter.com/" + tweets.User.Identifier.ScreenName + "/status/" + tweets.StatusID.ToString();}

catch (Exception ex)
{
Sitecore.Diagnostics.Log.Error(ex.Message, this);
}
}

11. Create a Sublayout for this User Control and add it to the Sitecore Layouts.

Note: You can also pass in the ‘Twitter Account Name’ as a parameter of the SubLayout
Note++: Umbraco and Episerver CMS can also use the same code with different CMS based API.

Thanks

Sitecore : Getting image field in code behind

This is just a quick post to show how to get image URL via code behind.

This is mostly useful when you are binding children items to a repeater or returning image URL in a JSON webservice

public static string GetImageURL(Item currentItem)
{
          string imageURL = string.Empty;
          Sitecore.Data.Fields.ImageField imageField = currentItem.Fields["Image"];
          if (imageField != null && imageField.MediaItem != null)
          {
            Sitecore.Data.Items.MediaItem image = new Sitecore.Data.Items.MediaItem(imageField.MediaItem);
            imageURL = Sitecore.StringUtil.EnsurePrefix('/', Sitecore.Resources.Media.MediaManager.GetMediaUrl(image));
          }
return imageURL;
}

Cheers

Sitecore vs Umbraco – A developer’s view

One Friday afternoon, I was sitting at my desk and fixing bugs (as usual), a member of sales team came up to me and said

“Hey Naveed, we have this interesting new client and they are not sure about which CMS to go for, they have finalised Sitecore and Umbraco as the last two, can you help”

I replied: “Sure, why not, what are their business requirements ?”

Sales person: “They are medium to large size organisation and have usual requirements like news, events, forums, blogs, video content etc, they want a simple to use CMS with multiple authors and security levels”
I replied: “Ok, Sitecore and Umbraco are both equally powerful in content generation and management, they both are based on .NET stack (.NET,C#,SQL) and both are highly customisable, so far they both can be their potential CMS, do you have more specific requirements ?”

Sales person: “Yes, in future, they would like to integrate with Sharepoint and their back-end CRM system”

I replied :”Sitecore comes with a sharepoint connector out-of-box whereas for Umbraco we have to custom build one. As long as their back end CRM exposes API, we can integrate any of the CMS system with their back end, this will be custom build in both cases, do you have any other requirements ?”

Sales person: “It is not a requirement but in their wish list to have personalised content for different regions or profile history”

I replied: “Sitecore comes with Customer Engagement Platform (CEP) and Online Marketing Suite (OMS) which can make their life easy in future, however, Umbraco lacks these customised modules. So it looks like Sitecore can be their potential candidate for CMS, also do you have any idea about their budget for the website?”

Sales person: “Yes, it’s a five figure sum, not sure what exactly their budget is”

I replied: “If they are tight on budget and can compromise on add-ons then Umbraco would be good to start off with but will have high maintenance cost if they go down the route implementing customised modules. However, paying for Sitecore licenses up front will give them added benefit to use some of the modules out of the box and will have low maintenance cost, I guess best would be to give them a demo of both CMS systems to the client and let them make informed decision”

Sales person: “Sounds like a plan, ok I will let them know, cheers”

Conclusion:

No CMS is right or wrong for your business out of the box, you have evaluate them against your own business requirements for the website. Open source may be cheaper to start off with but will have maintenance costs down the line.

Disclaimer: I have worked with both CMS systems and hold them up in same respect for what they do, I am not a sales person or work for either of the CMS systems, this is just my opinion as a third party developer

Sitecore : Extending OnItemSave Handler

In a recent project, I have to update certain fields of sitecore item when the item is saved in sitecore.

The solution I went for involved extending item:saved event and adding my own handler to do certain actions based upon template type

If you are in a similar situation, here are the steps to do

1. Create you custom class with a public method to perform your logic
2. In web.config under <events> find , <event name=”item:saved”> and append your handler at the end.

Here is basic class code

public class ItemSaveEventHandler
{
//master database name
public static readonly string Master = "master";
//sample template id
public static readonly string TemplateIdItem = "{67B44133-70CD-405C-BDAF-B93E5AEA2682}";

public void OnItemSaved(object sender, EventArgs args)
{

Item temp = Event.ExtractParameter(args, 0) as Item;
//make sure you are in edit mode and not in publish mode
if (temp != null && temp.Database.Name.ToLower() == Master)
{
//check if the template is what you are looking for
if (temp.TemplateID.ToString() == TemplateIdItem )
{
//do your stuff with the item, this is just a sample
temp.Editing.BeginEdit();
temp.Fields["Title"] = "new item saved title";
temp.Editing.EndEdit();
temp.Editing.AcceptChanges();

}

}

}

Complie and debug code, when you are ready change the web.config

<event name="item:saved">
<handler type="Sitecore.Links.ItemEventHandler, Sitecore.Kernel" method="OnItemSaved"/>
<handler type="Sitecore.Globalization.ItemEventHandler, Sitecore.Kernel" method="OnItemSaved"/>
<handler type="Sitecore.Rules.ItemEventHandler, Sitecore.Kernel" method="OnItemSaved"/>
<!-- add the namespace name and assembly dll name as per your site -->
<handler type="<MyWebsite.Handlers.ItemSaveEventHandler>, <MyWebsite.Hanlders>" method="OnItemSaved"/>
</event>

Thats it, if everything is correct the event handler will be called when someone saves an item in sitecore

Cheers

Sitecore : Adding schedule jobs via agents

This is a really short and sweet post. Sometimes you have to add scheduled jobs to query sitecore items at regular intervals and perform some custom logic.

The easiest way to do it is by adding your code as an agent to the web.config and setting up the interval

First, create your custom class, this could either be within the main website or a separate class library project something like

namespace  Website.AgentsNamespace
{
public class MyAgentClass
{
   public static void Run()
   {
     //add your custom logic here
     //call sitecore, services, database whatever
     //its up to you

   }
}
}

Compile and make sure there are no bugs.

Navigate to web.config and find

<scheduling>

node. Add your class as an agent and set the time interval like

<agent type="[name.of.your.class.including.namespace], [name.of.dll.where.the.class.is.compiled]" method="Run" interval="00:05:00" />

Thats it, job done.

Check the logs, and see when sitecor adds the job to scheduler.

Sitecore : Programmatically add and publish Sitecore items through Workflow

In this post, I will show how to auto publish an Item in Sitecore. This is handy as sometimes you have to create items from external XML feeds or databases.

The code snippet also includes adding item to workflow and auto executing it to the final stage

Steps to follow

1. We need to switch from the current site context to shell (if your code is running from within the site)
2. Then use SecurityDisabler() to switch into admin mode
3. Get the master database
4. Get the template
5. Get the path where Item has to be placed
6. Check if the item path does not exists, if it doesnt then create a new item
7. Create and Edit your item
8. Move to workflow (if required)
9. Do an incremental publish

Here is the code snippet (some values are hard coded, but again you can get them from config/settings)

//step 1-Switch context
string currentSiteName = Sitecore.Context.Site.Name;
Sitecore.Context.SetActiveSite("shell");
//step 2-Switch to admin mode
using (new Sitecore.SecurityModel.SecurityDisabler())
{
//step 3-Get master database
Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master");

Item newItem = null;
//step 4 - Get data template
TemplateItem templateItem = master.GetTemplate("User Defined/My Template");
//step 5 - Define static path
string path = "/sitecore/content/Home/My Template Items/";
//myItemPath might change with in a for loop or by passing variables
string myItemPath = "My new Item";
//define complete path
myItemPath = path + myItemPath
//step 6 - check if it exists
if (master.GetItem(myItemPath ) == null)
{
//step 7 - create and edit
newItem = master.CreateItemPath(myItemPath, templateItem);
newItem.Editing.BeginEdit();
newItem.Fields["Title"].Value = "My Item Title"; //programattically update the field
//amend more fields if required
newItem.Editing.EndEdit();
newItem.Editing.AcceptChagnes();

//step 8 - add to workflow if requried and place it in start state and then execute the final stage
Sitecore.Workflows.IWorkflow workflow = master.WorkflowProvider.GetWorkflow(newItem);
workflow.Start(newItem);
workflow.Execute(Config.AutoPublishCommandID, newItem, "auto approved", false);

//step 9 - publish to pre-defined targets and langugaes
Database[] targetDBs = new Database[] { Sitecore.Configuration.Factory.GetDatabase("web") };
Language[] languages = new Language[] { LanguageManager.GetLanguage("en") };
Sitecore.Publishing.PublishManager.PublishIncremental(master, targetDBs, languages);


}

}

//switch back to current site
Sitecore.Context.SetActiveSite(currentSiteName);

Cheers