Sitecore Multisite – Generating out of context links

Linking to items in other sites gives a lot of problems and strange urls.
Sitecore creates links by using the context of the current site.
There is an easy solution for creating out of context links, just switch the context!

First we need to find the site context of the item. The Sitecore.Configuration.Factory gives us access to all available sites.

var sites = Sitecore.Configuration.Factory.GetSiteInfoList();

Now we need to find the corresponding site.

SiteContext siteContext  = null;
foreach (var site in sites)
{
    var fullPath = string.Concat(site.RootPath + site.StartItem);
    if (item.Paths.FullPath.StartsWith(fullPath))
    {
        siteContext = new SiteContext(site);
        break;
    }
}

Now that we’ve got the site context, we can generate the correct url.

var urlOptions = LinkManager.GetDefaultUrlOptions();
urlOptions.Site = siteContext;
var url = LinkManager.GetItemUrl(item, urlOptions);

Automatic Bundling and Minification in .Net

One of the cool new features of .Net 4.5 is the bundling and minification feature. This can save so many requests to your server and saves you many kbs without creating a debug hell. The amount of data is getting more and more important, because of the mobile devices. People pay lots of money on data bundles for their mobile device, we better not waste it. It also decreases loading time!! Reasons enough to start using bundling and minification!

First thing you need to do is download and install the Microsoft ASP.NET Web  Optimization Framework nuget package.

The bundles are registered at application startup. This event is handled in the Application_Start method in the Global.asax. I always try to keep my Global.asax as clean as possible and split all registrations to seperate files in the App_Start folder. So I created a static BundleConfig class in the App_Start folder. This class contains one method, Register with the current Bundles as argument.

BundleConfig.RegisterBundles(BundleTable.Bundles);

BundleConfig

The BundleConfig class registers all JavaScript and Stylesheet bundles, Both Bundles can be added to the same BundleCollection, but both bundles have their own classes. JavaScript bundles are created by using the ScriptBundle class and Stylesheet Bundles are created by using the StyleBundle class.

bundles.Add(new ScriptBundle("~/bundles/jquery").Include("~/Scripts/jquery-{version}.js"));

This creates a JavaScript bundle named “~/bundles/jquery”  and includes one file, “~/Scripts/jquery-{version}.js”.  {version} is automatically resolved to the version of the jquery file in the scripts folder.

bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));

This creates a Stylesheet bundle names “~/content/css”” and contains one file “~/Content/site.css”. Adding more files is easy, just add more files to the include and separate them by a comma.

Adding bundles to a view

The only thing left to do, is adding the bundles to a view.

MVC (Razor)

@Scripts.Render("~/bundles/jquery")

WebForms

<%: Scripts.Render("~/bundles/jquery") %>

The above code renders the JavaScript bundle.

MVC (Razor)

@Styles.Render("~/Content/css")

WebForms

<%: Styles.Render("~/Content/css") %>

The above code renders the Stylesheet bundle.

All the requests to the bundles have a querystring parameter (v=CkVTG71m7lHB5jSCpyOSxbeCVJLIPag7u7NL4ykFenk1). This is to make sure that no old versions of this file are cached and retrieved.

Config files

Bundles can also be configured in config files. This allows you to make changes to your bundle without having to rebuild the project. It also allows frontend developers to easily include, remove or change files in a bundle without having to use visual studio.

An example of a bundle.config file

<?xml version="1.0" encoding="utf-8" ?>
<bundles version="1.0">
  <styleBundle path="~/Content/css">
    <include path="~/Content/Site.css" />
  </styleBundle>
</bundles>

Debugging

One of the biggest problems of minified files is debugging. It’s almost impossible to debug those files.

That’s when the best feature of this minification framework comes in place. When compilation is set to debug (in web.config), the files will not be minified, which makes it a lot easier to debug.

<system.web>
    <compilation debug="true" />
    <!-- Lines removed for clarity. -->
</system.web>

Creating custom bundle transforms

Custom transforms can be created by implementing the IBundleTransform interface.,

using System.Web.Optimization;

public class MyByndleTransform : IBundleTransform
{
   public void Process(BundleContext context, BundleResponse response)
   {
       // Process bundle tranform here
   }
}

The custom transform can now be added to the transform of a bundle

var myBundle = new Bundle("~/My/Files/To/Include");
lessBundle.Transforms.Add(new MyBundleTransform());

This bundle can now be added to the bundles collection in the BundleConfig file.

Why creating custom bundle transforms? Just think of less or coffeescript, or whatever bundle you want.

Simple CKEditor MVC EditorTemplate

I like using wysiwyg editors in my projects. It gives the user a lot of freedom in creating content.

There are a lot of wysiwyg editors, like TinyMCE, CKEditor, etc. I prefer CKEditor (formerly known as FCKEditor), because it is flexible, extendible, has a lot of plugins and creates clean (and customizable) html.

Most of my projects are MVC projects and I created a simple solution for using the CKEditor for content properties of my model.

First I mark the Properties in my model as html Properties by using the UIHint attribute.

public class Page
{
    public string Title { get; set; }

    public string SubTitle { get; set; }

    [UIHint("html")]
    public string Content { get; set; }
}

The UIHint attribute is part of the System.ComponentModel.DataAnotations namespace and can be combined with any other (MVC) attribute.

Now we need to create a view for this model:

@model MvcApplication1.Models.Page

<h2>Create new Page</h2>

<div>
    @Html.EditorForModel()
</div>

This will render an input for every property in the model. In this case, three inputs of type texy are rendered, because the type of the three properties in the Page model are strings and the application does not know how to handle the “html” value in the UIHint attribute of the Content Property.

By calling Html.EditorForModel all properties in the provided model are rendered. The attributes influence the rendering of the properties. The UIHint attribute lets you change which template is used for rendering this property. MVC searches for templates in the EditorTemplates folder. It searches in the controller folder for an EditorTemplates folder. When this folder is not found, it searches in the Shared folder for an EditorTemplates folder. When no folder is found, it will use the default template for the type of this property. When an EditorTempaltes folder is found, it will look for an html.csharp file. This is because of the value in the UIHint attribute. I want to use the html editor for every controller, so I place the html.csharp file in the Shared/EditorTemplates folder. It is also possible to override any default template, so you can make your own template for strings by creating a string.cshtml file and place it in the EditorTemplates.

When calling Html.DisplayForModel (or Html.DisplayFor), it searches in the DisplayTemplates folder. This has the same fallback scenario as described above for EditorTemplates.

My html.csharp file contains the following code:


@model String

@Html.TextArea("", Model, new { @class = "htmleditor" })

<script type="text/javascript">
    $(document).ready(function () {
        var id = "@ViewData.TemplateInfo.HtmlFieldPrefix";
        var instance = CKEDITOR.instances[id];
        if (instance) {
            delete CKEDITOR.instances[id];
        }
        $("#" + id).ckeditor();
    });
</script>

This creates a new instance of the CKEditor and deletes the old instance if exists.

Sitecore’s sublayout datasource, brilliant! Or maybe not?

One of the strengths of Sitecore is the DMS (Digital Marketing System). DMS collects user information and allows you to personalize the website based on the user’s profile.

One of the possible personalizations is changing the content of a sublayout by changing its datasource.

This sounds great, but sitecore made one big design flaw!

The items in the datasource are not stored by ID, but by the selected items path! This means that changing one of the item names in the tree of the selected item (or the selected item name itself) will break the datasource. Moving the item will also break the datasoure. Beware of that!!!

Sitecore announced to fix this in a future version.

I’m also not very happy about the way you have to retrieve the datasource item:

Item item;
string datasource = ((Sitecore.Web.UI.WebControls.Sublayout)this.Parent).DataSource;
if (!string.IsNullOrEmpty(datasource) {
    item = Sitecore.Context.Database.SelectSingleItem(datasource);
}

Reading Excel files in .Net using C#

Customers and project managers seem to have one thing in common, they both like working with Excel. Though Excel isn’t really my favorite application, there is one thing very nice about it. It is very easy to read an Excel file in .Net.

In this post, I will try to describe how you can read and parse an Excel file.

This post is based on a computer which has Office 2010 installed. If you try to read excel files on a computer or server without office installed, you first need to install this.

Interfaces

Nobody seems to care about interfaces anymore, that’s why I’m telling you that I do think it is important. It makes your application loosely coupled and unit testable! It also makes you think about generic solutions for problems.

Program to an interface, not an implementation!!

The interface I created for my reader file:


public interface IFileReader<T>
{
     T Read(string filename);
}

I created the following class which implements the IFileReader interface


public class ExcelReader : IFileReader<DataTable>
{
     public DataTable Read(string filename)
     {
      ....
     }
}

The connection string

The Excel file can be read as a database, using an OleDb  (Object Linking and Embedding, Database) connection. This is a connection designed by Microsoft for accessing a variety of sources.

I use two different connection strings for reading Excel files, one for the good old xls files and one for the xlsx files.

I check on file extension for detecting the right connection string (I know this is dirty!!!)


 string connectionString;
 var filename = filePath.Trim().ToLower();
 if (filename.EndsWith(".xlsx"))
 {
    connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0 Xml;HDR=YES;IMEX=1\";", filePath);
 }
 else if (filename.EndsWith(".xls"))
 {
    connectionString = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=1\";", filePath);
 }

Please put these connection strings in the connectionstrings section of your app.config or web.config!!

Reading sheets

Now that we have a connection string, we can create a connection.


OleDbConnection connection = new OleDbConnection(connectionString);
connection.Open();

Make sure you use try/catches for the connection.
Now that the connection is open, the next step is reading the tables. The tables in Excel are the available sheets.


DataTable tableSheets = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);

Every row in the tableSheets is a sheet


string dataTableName = tableSheets.Rows[0]["TABLE_NAME"].ToString(); 

The above code will give you the name of the first sheet. The sheet name can be used to retrieve the data of this sheet. You can also use a foreach or for loop to retrieve all sheet names if you need to collect data of all sheets.

Reading data


OleDbCommand command = new OleDbCommand(string.Format("SELECT * FROM [{0}]", dataTableName), connection);
command.CommandType = CommandType.Text;

This Command reads the data of the first sheet.
I like to use a DataTable to store the retrieved data. A DataTable is a representation of one table and contains both Columns and Rows.
The first row in a excel sheet are read as columns. The data in the Rows can be retrieved by using the name of the column as index key (like a dictionary).

So we need to fill the DataTable with the result of the Command:


var dataTable = new DataTable();
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(command);
dataAdapter.Fill(dataTable);

The OleDbDataAdapter executes the command and fills the DataTable with the resultset.

The datatable is filled and ready to use. Make sure you handle exceptions properly!

Clean up!

The only thing left to do is clean up! Close the connection and dispose all disposable objects! Why? Because you don’t want memory leaks or other strange behavior in your application! Always dispose disposable objects!  

if (connection.State == ConnectionState.Open)
connection.Close();
connection.Dispose();
command.Dispose();
dataAdapter.Dispose();

I recommend using usings instead of calling dispose!

Setting readonly variables

A lot of people don’t seem to realize that setting readonly variables is indeed possible, it can only be done from inside the constructor:

public class SomeClass
{
   private readonly ISomeService _someService;
   private readonly ISomeOtherService _someOtherService;

   public SomeClass(ISomeService someService, ISomeOtherService someOtherService)
   {
      _someService = someService;
      _someOtherService = someOtherService;
   }
}

This is perfectly fine working code and I strongly recommend it. I use this a lot with dependency injection (DI). This makes sure that the injected instances cannot be overridden, because they can only be set in the constructor.
That’s why I really don’t like the requirement of a parameterless constructor in UserControls in WebForms. There is no possibility for injection, only resolving is possible.

Opening VS 2012 Web projects in VS 2010

Have you ever met a front end developer who doesn’t mind working in Visual Studio? Well, I’m one of the lucky ones who have!
He doesn’t even own an iPhone and still his work is pretty awesome! (no, he did not pay me to write this!)

We work together on several projects. He works uses a basic version of visual studio 2010, while I work with visual studio 2012.
I created some .net 4 web projects for him to work in, and asked him to get the latest version from TFS.

He asked me if he should install WebMatrix and I answered with a simple no. This caused the projects to not being able to load.
I started checking the project references, nothing shocking. The project properties were also pretty basic, using custom webserver.

I discovered that the problem was IIS Express. This is not installed in VS 2010. Probably didn’t exists at the time of release.

So I checked the web server settings to see if IIS Express is enabled, but the project settings were set to custom webserver and the already disabled IIS Express checkbox was not checked.

I finally checked the project file, by using edit project file. This will unload the project and allows you to edit the project file, which is basically just an xml file. You should definetly check this out if you have never done that before.

And that’s where I saw the problem:

<UseIISExpress>true</UseIISExpress>

Setting this to false and reloading and committing the project file solved the problem!

Sitecore user serialization

A colleague gave me an excel file with usernames, password and profile information and asked me if I could import them in Sitecore.
After writing an import tool (read about reading excel files here), I thought to be clever and used Sitecore serialization to import all users to the test environment.
Serialization works quite well. It creates a user file for every user (in the data\serialization\security folder) and even the roles can be serialized.
I copied these files to the test environment and started the deserialization process. All sitecore users were visible in sitecore, but none of the users where able to login.
That’s when I found out that passwords are not serialized!
So remember! Serialization of users looks nice, but you do need to create new passwords!

UpdatePanels and JavaScript request events

When my journey continued in the land of UpdatePanels (read my previous post about UpdatePanels here), I was looking for a way to create a clientside success event handler. I have been working with jQuery for some years now so I’ m a bit spoiled when it goes about Ajax. Their framework makes it very easy to register success or error handlers:

$.ajax({
   url : "/someurl",
   type: "POST",
   success: function(data) {
      // your success handling here
   }
});

I was hoping to find some what the same for partial postback requests. After researching the web for a while, I took a look at the Sys.WebForms.PageRequestManager object. This singleton object holds all data relevant to async page requests and holds some useful functions for registering your functions as event handlers.

In this case, I was looking for two events, the begin and end request events. The begin request  event handler can be registered by using the add_beginRequest function and the end request handler by using the  add_endRequest function.

var requestManager = Sys.WebForms.PageRequestManager.getInstance();
requestManager.add_beginRequest(function(sender, args) {
    // begin request logic here
});
requestManager.add_endRequest(function(sender, args) {
    // end request logic here
});

The event handlers are called with two arguments: The PageRequestManager (sender in this example) and the EventArguments (args in this example). These are very important to determine which UpdatePanel or PostBack element (Button, etc) is triggering the request.

The BeginEventArguments exposes three interesting functions:

  • a get_postBackElement function for retrieving the element that caused the PostBack.
  • a get_updatePanelsToUpdate function for retrieving a list of UniqueIds of the UpdatePanels which will be updated by this request.
  • a get_request function for retrieving the event context.
   var requestManager = Sys.WebForms.PageRequestManager.getInstance();
   requestManager.add_beginRequest(function(sender, args) {
     var postBackElement = args.get_postBackElement();
     var updatePanels = args.get_updatePanelsToUpdate();
     var request = args.get_request();
   });

The EndRequestArguments exposes five functions, two are very useful for my case.

  • a get_error function for retrieving the error. This function will return null when no error has occurred.
  • a get_response function to retrieve the response.
var requestManager = Sys.WebForms.PageRequestManager.getInstance();
requestManager.add_endRequest(function(sender, args) {
    var error = args.get_error();
    var response = args.get_response();
    if (error) {
       // handle error
    }
});

The PageRequestManager contains a lot more useful functions and properties for hooking up to the webforms ajax system.
Some I like are abortPostBack, get_isInAsyncPostBackremove_beginRequest and remove_endRequest.

UpdatePanels and JavaScript triggers

Sometimes, you don’t get to choose between WebForms and MVC (for instance when you’re doing some rework on an old project).
So I got stuck on a WebForms project and I’m more a MVC kinda guy.
Some reasons why I like MVC over WebForms:

  • Flexibility
  • Unit testable
  • Stateless
  • Clean html output

Some people say that you have to write more html with MVC, but I don’t really agree. When you make good use of the HtmlExtensions, DisplayTemplates and EditorTemplates, it is just the same and even more flexible.
But that’s not what this post is about.
When I was working on this WebForms project, I was creating a page with multiple UpdatePanels and that’s when the trouble started.
I wanted to update the UpdatePanel form outside the UpdatePanel, so there was no use in defining triggers. The trigger was coming from a JavaScript function.
After doing some research, I read about the __doPostBack function. This function allows you to update an UpdatePanel and takes two arguments. The first argument is the ClientID of the UpdatePanel:

<asp:UpdatePanel runat="server" ID="upDemo">
  <ContentTemplate>
    <h1>Inside the UpdatePanel</h1>
  </ContentTemplate>
</asp:UpdatePanel>

The following JavaScript code will trigger an update of the UpdatePanel in the demo above:

__doPostBack("<%= upDemo.ClientID %>", "some argument");

The second argument of the __doPostBack function is the event argument. This is a very nice feature, because this allows you to send an ID or some extra data. You can even send a json object if you want.

But now we need to intercept the data in the code behind. The __doPostBack causes a PostBack so all events of the page cycle will occur.  In the page load we can intercept the ajax event.

First of all, there is the ScriptManager. This manager handles the Ajax requests and provides useful data.

protected void Page_Load(object sender, EventArgs e)
{
  var scriptmanager = ScriptManager.GetCurrent(this);
  var isAjaxRequest - scriptmanager.IsInAsyncPostBack;
}

This code example shows how the ScriptManager exposes the IsInAsyncPostBack property. This property helps to determine if the request is an ajax request (Similar to Request.IsAjaxRequest in MVC). But what if you have more than one UpdatePanel? Which panel is causing the ajax request?
I found two ways to determine this, The first one is again the ScriptManager:

protected void Page_Load(object sender, EventArgs e)
{
  var scriptmanager = ScriptManager.GetCurrent(this);
  if (scriptmanager.IsInAsyncPostBack
   && scriptmanager.AsyncPostBackSourceElementID == upDemo.ClientID)
  {
    // we now know that the postback is caused by the upDemo UpdatePanel
  }
}

The AsyncPostBackSourceElementID holds the ClientID of the UpdatePanel which caused the PostBack.
The second way is by using  the Form values from the Request:

protected void Page_Load(object sender, EventArgs e)
{
  var target = this.Request.Form["__EVENTTARGET"];
  var scriptmanager = ScriptManager.GetCurrent(this);
  if (scriptmanager.IsInAsyncPostBack && target == upDemo.ClientID)
  {
    // we now know that the postback is caused by the upDemo UpdatePanel
    var argument = this.Request.Form["__EVENTARGUMENT"];
    // argument is the second argument of the __doPostBack function.
  }
}

The Form key __EVENTTARGET holds the ClientID of the UpdatePanel, similar to the AsyncPostBackSourceElementID

The Form key __EVENTARGUMENT holds the second argument of the __doPostBack function. When the __doPostBack function is called with only one argument, the value in __EVENTARGUMENT can be something like “undefined”. This depends on the browser. I recommend to send an empty string as second argument when no data is required for the request.

Check my follow up post here