Musielak Marek

Posted on Thursday, November 10, 2011 by Marek Musielak

Sitecore Facebook Device - Facebook Open Graph device for Sitecore

Recently I've been working on a Sitecore project for a large company that produces distilled beverages. One of the requirements was that before user can access any content within the site, they must pass age verification process. Still we needed to be able to share any of the pages on the Facebook, with the content specific for that particular page, not the data which is displayed on the age verification page.

While sharing the page on Facebook, it crawls the page and looks for the data that can be displayed for other Facebook users. The first thing which is checked is open graph data. I'm not going to explain it deeply in this post, but if you want to know more, you can learn it from here open graph protocol - facebook developers. What we need to know for the purposes of this article is that there are some meta tags that should be included within the html page header that are used by Facebook. Our goal was to display the page with those meta tags instead of the age verification page, if the site is crawled by Facebook.

Sitecore Facebook Device User Agent - 'facebookexternalhit'

For this purpose we chose the approach that uses Sitecore devices functionality. When the page is accessed by Facebook, the user agent of the facebook browser introduces itself as

facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)

We created a new device in the Sitecore that is used for the browser agent containing facebookexternalhit. Then we prepared a layout that is used for this device only and which contains all the open graph meta data required by Facebook. This allowed us to assure that all the end users will have to age verify before accessing the site, while Facebook can retrieve meaningful data.

Once you've set up the device and the layout, you can easily check whether you did it properly using the official Facebook URL Linter. The screenshot below shows an example of debug result for a page which has open graph meta data set.

Facebook Linter - Open Graph Debugger

Read More »

Posted on Thursday, July 21, 2011 by Marek Musielak

Has Google PageRank started to ignore 'www'?

Nearly year ago I became crazy about optimizing websites performance. YSlow and PageSpeed became my closest friends. One of their advices was to serve static content from cookieless domains. Unfortunately, my private web site url was http://marasm.pl (without 'www.' prefix) so I wasn't able to create any cookieless subdomain as all 'marasm.pl' cookies were used for subdomains.


That was the reason why I changed the url of my website to www.marasm.pl and redirected (with 301) all the calls from the url without 'www' to the new addresses. One month later PageRank of all pages within my site dropped to 0. I wasn't the happiest person in the world but there was nothing I could do. I left everything as it was hoping that the value of the content would earn its PageRank back.


One week ago I noticed that the PageRank of my website pages is back. More surprisingly, now it has the same values for the pages for both urls starting with 'www' and without, despite the fact that urls without 'www' are redirected. I'm sure one year ago Google didn't give any PageRank for the pages that were redirected with 301. Why did they change their minds? Is the current solution better? What would happen if I switch my domain back to the marasm.pl without 'www'?

Read More »

Posted on Friday, June 18, 2010 by Marek Musielak

How to determine who deleted the page in EPiServer

Couple of days ago a colleague of mine was looking for a way to determine who moved a page to the recycle bin in EPiServer. Much to my surprise, there is no way to find that out using EPiServer edit / admin mode.

I had been sure that when one moves the page to the recycle bin, the new version is created, but it turned out that there is no single trace who deleted the page. That's why I wrote the code below:


using System;
using System;
using EPiServer;
using EPiServer.Core;
using EPiServer.DataAccess;

namespace Web
{
public class Global : EPiServer.Global
{
protected void Application_Start(Object sender, EventArgs e)
{
DataFactory.Instance.MovedPage += SaveNewVersionIfDeleted;
}

private static void SaveNewVersionIfDeleted(object sender, PageEventArgs e)
{
if (DataFactory.Instance.IsWastebasket(e.TargetLink))
{
PageData deletedPage = DataFactory.Instance.GetPage(e.PageLink).CreateWritableClone();
SaveAction action = SaveAction.ForceNewVersion;
action |= (deletedPage.PendingPublish) ? SaveAction.Save : SaveAction.Publish;
DataFactory.Instance.Save(deletedPage, action);
}
}
}
}

The code is very short and simple. In Application_Start method of the Global.asax.cs I added a new method to the DataFactory.Instance.MovedPage handler. This method checks whether the target is recycle bin and forces a new version of the page. Now if you check the version list of any of the page in the recycle bin, the latest version shows you who and when deleted the page.


Read More »

Posted on Monday, November 30, 2009 by Marek Musielak

Custom scheduled jobs in EPiServer - advanced tips

If you are here, you probably know what EPiServer scheduled jobs are. If not, I suggest you to take a look at Ted Nyberg post here Ted Nyberg: scheduled jobs in EPiServer first. If you're still with me, I assume you already have basic knowledge about scheduled jobs in EPiServer.

In this post I want to talk about several things you should take into account during your work with EPiServer scheduled jobs like:
* running the scheduled job on the chosen server
* executing only one EpiServer job in the same time
* executing scheduled job as a specified user
* process within the job thread is executed



Many servers - one job only

If you have many web servers connected to the single DB server (no matter if this is your development or production environment), you should be aware of the fact, that if the job is started automatically ANY of the servers can start your scheduled job. What is more, you can not be sure that the job won't be run on many servers in the same time. In some cases this is desired behavior, while in other it can cause serious problems.

Lets consider a situation when the role of the scheduled job is to perform some CPU consuming calculations. Assume that we have 4 server: 3 of them can be accessed via Internet and the other one is used only for entering content. In this scenario I would like all those calculations to be performed on the 4th server so the users accessing the site do not encounter any performance issues.

There is simple solution - stop EPiServer Scheduler service on the servers that can be accessed via Internet and leave the service running only on the 4th server. Do not forget to set Startup Type of the service to "Manual", in other case the scheduler will start on the machine after the reboot.

Only one job executed in the same time

There are plenty of situations when we don't want to let 2 same scheduled jobs to be executed simultaneously. But when we have a scheduled job that is run very often and execution of which can take a lot of time, we can be pretty sure that such a moment will occur when scheduler will try to execute the same job despite the fact that one job is still running.

To avoid it, we can use System.Threading.Monitor class like this:

using System;

namespace Maras.ScheduledJobs
{
[EPiServer.PlugIn.ScheduledPlugIn(DisplayName = "My job",
Description = "Only one 'My job' will be executed parallelly")]
public class MyJob
{
private static readonly object MyJobLock = new object();

public static string Execute()
{
if (!System.Threading.Monitor.TryEnter(MyJobLock))
{
// other job uses the monitor
return "Job is still running";
}

try
{
// ... here comes the real code of the job
return String.Empty;
}
catch (Exception exc)
{
return string.Format("Unknown exception caught ({0} {1})",
new object[] { exc.Message, exc.StackTrace });
}
finally
{
System.Threading.Monitor.Exit(MyJobLock);
}
}
}
}

It is very important to exit the monitor in finally statement. In other case you can block your jobs until the application is restarted.

Executing EPiServer scheduled job as a specified user

If you execute your job manually from the admin mode, your job is executed with all privileges that your user has. However, when your job is run by the scheduler, it does not have you user access rights. Believe me, it's really easy to forget about it while developing new scheduled job.

Fortunately it's really easy to log with the specified user name in the EPiServer. the only thing to do is to assign new principals to the PrincipalInfo.CurrentPrincipal like this:

EPiServer.Security.PrincipalInfo.CurrentPrincipal =
EPiServer.Security.PrincipalInfo.CreatePrincipal("username");

For more information take a look at Ted Nyberg: Run a scheduled job as a specific EPiServer user.

Process within the job thread is executed

In the development phase of the scheduled job, most of the time you will start your job manually from the admin mode. In this case the job will be run within the web application process and its thread will have all privileges and rights that your user has.

However, when you set the scheduler to run the job automatically, there is a huge difference. Probably the most important is that you don't have user rights, but I already wrote about it above. The other thing that you should consider is that you don't have access to the HttpContext.Current stuff. And probably there are dozens of other things specific for your application.

Summarizing

While developing your custom scheduled job for EPiServer one has to remember that there is a big difference between jobs run manually and jobs run automatically by the scheduler. I hope that after reading this post you won't have any problems with your own scheduled jobs.

If you know about anything else that should be added to the list above, do not hesitate to comment below.

Read More »

Posted on Tuesday, July 21, 2009 by Marek Musielak

ASP.NET web site performance

I've been working on a site for a tile and wood flooring specialist store recently. That was my first own project on such a big scale. Ok, maybe not so big comparing to projects that I worked on as a Cognifide employee, but still pretty big as a single person project. It was a challenging experience for me as I set up a goal for myself - the site has to load as fast as possible.

The result can be seen here el-ART. The site is in Polish but there is no need for understanding the content so don't worry ;)

Here is the full story of my work with this site.


Many web developers think that if the site is small then they don't have to worry about the speed of the response time. Unfortunately, they are wrong. Look at the site again (el-ART). There was not much html there but there were about 15 images (including logos and css images), several css files and couple of scripts. 30 or 40 requests per every page load. Then I started optimization - there are dozens of tools which can help you with it - I prefer Page Speed Firefox addon.
Lets go step by step with several of it's clues:

Combine external CSS


There are several ways of reducing the number of requests that are sent by the browser. One of them is combining external css files. The easiest way for this is just to create a single file and copy the content of all css files into the new file. Then just replace all previous css links with the one to the new file. However, the solution is not perfect. If you have several files, you can easily keep order in them and it's easy to find what you need. With one file it becomes a challenge.

But there is an easy solution - you can create your own handler that will combine all css files for you and will return them as a single response. If your site is an ASP.NET site, you can use custom resource handler like this one. If you use other environment, you will find something similar for sure. I used my own one with gzip compression enabled, extended caching and setting header values. It not only decreases the number of the requests, but reduces the size of the response as well.

Combine external Javascript


This one is pretty similar to combining css files. However, it has to be extended if you are using Web Extensions - the site will use a lot of .axd files and it's a little bit harder to cope with them. But Damian Kulik created a solution for this which can be found here http://damikulik.blogspot.com/2009/07/script-and-styles-optimizer-for-aspnet.html. I'm not going to copy and paste from his blog here so if you want to know more about it then just stay on his blog for a couple of minutes.

Optimize the order of styles and scripts


The order of the styles and javascript files is really important. Sometimes it is enough just to move link up or down on the page to decrease the time of loading page significantly. How? It's all about the parallelization downloads. The general rule is: css files should be in the < head /> tag, while js files should be placed as far in the content as it is possible, sometimes even just before the end of the < body /> tag. More about ordering on google code.

Optimizing images


There are 2 main rules here:
- use compressed images - in many cases you can compress your images so they look exactly the same but they are smaller. Page Speed will compress the files for you and display links to compressed images so you can use them on your site.
- do not resize images in html - do not display big images that are resized - the browser will have to download the big file anyway and, what is worse, IE browsers use a pretty bad algorithm for resizing images so they look not nice.

CSS sprites


This one is huge! Probably I should mention about it on the very top of the article but never mind. The whole idea of CSS sprites is described on the css tricks site. Instead of downloading dozens of images and wasting time for requesting all of them, you can download only one image and display parts of it wherever you need them. Take a closer look at my site again (el-ART) - there are 6 links with images in the bottom part of the page. If you would check their properties you would see that all of them has the same background - gallery.jpg, just moved with background-position css property. The image is smaller than 6 separate images and browsers load it several times faster.

Compress response


One more thing that could be done is compression of the response html. When you write html then you should format it so it could be easily read and maintain, but when you send it to the user, it should be as small as possible. It really easy to apply it in ASP.NET. The only thing to do is to edit the Application_BeginRequest method in Global.asax.cs class as follows:
protected void Application_BeginRequest(object sender, EventArgs e)
{
if (Request.RawUrl.ToLower().EndsWith(".aspx"))
{
string acceptEncoding = Request.Headers["Accept-Encoding"];

if (!string.IsNullOrEmpty(acceptEncoding))
{
acceptEncoding = acceptEncoding.ToLower();

if (acceptEncoding.Contains("gzip"))
{
Response.Filter = new HtmlCompressStream(Response.Filter, CompressionMode.Compress,
HtmlCompressStream.CompressionType.GZip);
Response.AddHeader("Content-encoding", "gzip");
}

else if (acceptEncoding.Contains("deflate"))
{
Response.Filter = new HtmlCompressStream(Response.Filter, CompressionMode.Compress,
HtmlCompressStream.CompressionType.Deflate);
Response.AddHeader("Content-encoding", "deflate");
}
}
}
}



Decrease loading time - summary


All those optimization tips helped me to create the site that is displayed very fast. There are only 12 requests for the content, the size of all of them is about 210KB, and the site loads for me in less than 1 second. Just to show you the difference, BBC site uses 82 requests (556KB) and loads about 10 seconds for me.

If you have any interesting experience with increasing performance of the ASP.NET sites or want to show how you deal with optimizing issues, do not hesitate to leave your comment below.



Read More »