Still looking for a sponsor Max Paulousky is looking for a Silverlight/.Net job in the Commonwealth

Share to Facebook Tweet this! Share to MySpace Share to Google Share to Live   Share via AddThis

Search Engine Optimization (SEO) for Silverlight Applications. Part 2

In the first part of the article I described the way to implement the deep linking feature in MVVM-based Silverlight application.

In this post I am going to describe two other important functionalities that  should be implemented to achieve great level of search engine optimization. First on is sitemaps and second one is html content providing.

Sitemap for Silverlight applications

As soon as the application is able to work with deep links, I can start implementing support of Sitemaps. The application should be able to generate automatically links to any content within the application or to the most important content elements. I going to add these links to an XML file with special structure. It will be sitemap of the application.

All information about structure of sitemap file you can find on the official site

I am going to implement HttpHandler to be able to generate sitemap file on the fly depends on current structure and content. I will add Sitemap.ashx handler to the web project and use following code for generating sitemap xml response:

public void ProcessRequest(HttpContext context)
{
  context.Response.ContentType = "text/xml";
  string serverUrl = context.Request.Url.AbsoluteUri.Replace(
    context.Request.Url.PathAndQuery, string.Empty);
 
  VacanciesDomainService service = new VacanciesDomainService();
 
  XNamespace xnsp = "http://www.sitemaps.org/schemas/sitemap/0.9";
  XElement root = new XElement(xnsp + "urlset");
  
  //url for AllVacancies
  root.Add(GenerateUrlElement(xnsp, serverUrl + 
    RouteTable.Routes.GetVirtualPath(null, RoutingNames.AllVacancies, 
    new RouteValueDictionary()).VirtualPath));
 
  //urls for LoadVacanciesByRegion
  IEnumerable<string> regions = service.LoadAllRegions().Select(r => r.Name);
  foreach (string region in regions)
    root.Add(GenerateUrlElement(xnsp, serverUrl + 
      RouteTable.Routes.GetVirtualPath(null, RoutingNames.VacanciesByRegion, 
      new RouteValueDictionary() { { "regionName", region } }).VirtualPath));
 
  //urls for LoadVacancyById
  IEnumerable<Vacancy> vacancies = service.LoadAllVacancies();
  foreach (Vacancy vacancy in vacancies)
    root.Add(GenerateUrlElement(xnsp, serverUrl + 
      RouteTable.Routes.GetVirtualPath(null, RoutingNames.VacancyById, 
      new RouteValueDictionary() { { "id", vacancy.Id } }).VirtualPath));
 
  context.Response.Write(root.ToString());
}
 
private static XElement GenerateUrlElement(XNamespace nameSpace, string url)
{
  return new XElement(nameSpace + "url",
    new XElement(nameSpace + "loc", url),
    new XElement(nameSpace + "lastmod", DateTime.Now.Date.ToString("yyyy-MM-dd")),
    new XElement(nameSpace + "changefreq", "weekly"),
    new XElement(nameSpace + "priority", "1"));
}
 

As you can see, I generate sitemap urls for each piece of content (all vacancies, vacancy by region, vacancy details). I use GetVirtualPath() method of RouteCollection to generate a url for the particular piece of content. Also, I use the VacancyDomainService class to get enumeration of region names and set of vacancy Ids. I need it because these values will be used to build urls like “vacancies-in-Auckland” or “vacancy-8” etc.

I use generated Url to build a node in the Sitemap xml file. Function GenerateUrlElement() does it. A node url contains following subnodes:

  • loc. Contains link to particular content (post, article, web page).
  • lastmod. The date of the last modification of the content.
  • changefreq. The frequency of the content updating. Can be always, hourly, daily, weekly, monthly, yearly, never.
  • priority. Means how this content is important relatively to other content on the site. The value is between 0 to 1. Bigger value means bigger importance.

At the end, I convert XDocument to string representation of the sitemap and write it to the Context.Response. So, if I open Sitemap.ashx file in a browser, I get following result:

 Sitemap for the SilverlightJobBoardSEO.maxpaulousky.com web site

Submitting Sitemaps to search engines

Once I get sitemap, I can submit it to search engines. I have to do it as soon as I can because a web site will be crawled in one-two weeks after sitemap submitting.

Bing. Go to Webmaster tools page, register an account and submit a sitemap.

Bing.com: Webmaster tool

Google. Go to webmasters web site, register an account and submit a sitemap.

 Google.com: webmaster tools

Yahoo. Go to Yahoo, register and login and go to SiteExplorer. Then submit a web site address and a feed (Sitemap).

Yahoo.com: site explorer

Html Content Providing

Last but not least step to become successful in SEO is to provide html content depends on requested url. These data will be used by search engines to index a web site.

I proceed from the assumption that html data is not so important for end users because they will see a Silverlight application; also, search engines do not care a lot about layout and format of displaying data. So, I am going to automate generating html data.

I plan using GridView controls to display data; DomainDataSource components to read data from DomainContext and prepare them for GridView.

Html content should be displayed only if a user does not have a Silverlight plug-in installed. So, I put Grids and DataSources into hidden div. Once page is loaded, I check availability of the Silverlight plug-in and display div with grids if it is not installed:

<div id="AlternativeContent" style="display: none;">
  <h1>
    Alternative content for the Silverlight Job Board</h1>
  <asp:GridView ID="RegionsGridView" runat="server" AllowPaging="false" AllowSorting="false"
    AutoGenerateColumns="true" AutoGenerateDeleteButton="false" AutoGenerateEditButton="false"
    CellPadding="4" DataSourceID="RegionsDDS" ForeColor="#333333" GridLines="None"
    Visible="false">
    <AlternatingRowStyle BackColor="White" />
    <EditRowStyle BackColor="#2461BF" />
    <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
    <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
    <PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
    <RowStyle BackColor="#EFF3FB" />
    <SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
    <SortedAscendingCellStyle BackColor="#F5F7FB">
............
............
</div>
 
<script type="text/javascript">
  if (!isSilverlightInstalled()) {
    var obj = document.getElementById('AlternativeContent');
    obj.style.display = "";
  }
</script>

I use following JavaScript code to detect the Silverlight plug-in availability.

function isSilverlightInstalled() {
    var isSilverlightInstalled = false;
    try {
        //check on IE
        try {
            var slControl = new ActiveXObject('AgControl.AgControl');
            isSilverlightInstalled = true;
        }
        catch (e) {
            //either not installed or not IE. Check Firefox
            if (navigator.plugins["Silverlight Plug-In"]) {
                isSilverlightInstalled = true;
            }
        }
    }
    catch (e) {
        //we don't want to leak exceptions. However, you may 
        //to add exception tracking code here
    }
    return isSilverlightInstalled;
}
 

In the code behind I analyze Route Url of the current request, set particular QueryName and query parameters. These characteristics are used to load data from DataContext:

switch(((Route)RouteData.Route).Url)
{
  case RoutingNames.AllVacancies:
  default:
    VacanciesDDS.QueryName = "LoadAllVacancies";
    VacanciesDDS.QueryParameters.Clear();
    VacancyGridView.Visible = false;
    VacanciesGridView.Visible = true;
    RegionsGridView.Visible = true;
    return;
 
  case RoutingNames.VacanciesByRegion:
    VacanciesDDS.QueryName = "LoadVacanciesByRegion";
    VacanciesDDS.QueryParameters.Add(RouteData.Values.First().Key, 
      RouteData.Values.First().Value.ToString());
 
    VacancyGridView.Visible = false;
    VacanciesGridView.Visible = true;
    RegionsGridView.Visible = true;
    return;
 
  case RoutingNames.VacancyById:
    VacancyGridView.Visible = true;
    RegionsGridView.Visible = false; 
    VacanciesGridView.Visible = false;
 
    VacancyDDS.QueryName = "LoadVacancyById";
 
    VacancyDDS.QueryParameters.Add(RouteData.Values.First().Key, 
      RouteData.Values.First().Value.ToString());
    return;
}

Here is the web site with turned off Silverlight plug-in. The request is “Vacancies in Auckland”.

Alternative html content of the Silverlight application for search engines.

Here is the same request with turned on Silverlight plug-in:

How does Silverlight application looks (Vacancies in Auckland request)

Silverlight application in the search index.

As I had built demo application, I added the sitemap to search engines. By now, the application is indexed and I can show several top-search queries. For example, my demo application is #1 in Google by the “silverlight vacancies in Auckland”, “silverlight vacancies moscow” etc queries:

The demo silverlight job board in #1 in google

Source codes and demo application

I have prepared and uploaded both binaries and sources, also I you can browse and try the demo application.

Related links

Here is the list of links that can help to build a search engine optimized silverlight web site:

Hope, this helps!

This work is licensed under a Creative Commons Attribution By license.

Leave a Comment [ RSS ]

  • re: Search Engine Optimization (SEO) for Silverlight Applications. Part 2

    I would like to appreciate the efforts you have made in writing this article and i am hoping the same good work from you in the future as well.

    Thank

  • SEO Services india

    Wow, it is a great program! It is great if it receives reports from the cards. I believe it will help to control and reduce my expenditures

  • re: Search Engine Optimization (SEO) for Silverlight Applications. Part 2

    Requesting Gravatar... Joofer says:

    Max!
    thanks for all your effort on SEO and Silverlight.
    I'm going to work on your code samples now and see if I can use them for my project.
    Keep up the good work :)

  • re: Search Engine Optimization (SEO) for Silverlight Applications. Part 2

    Requesting Gravatar... SEO RESELLER says:

    Thanks also for the enlightenment regarding Silverlight applications in terms of the SEO perspective. I plan on using Silverlight media such as animation and video showings as a complementary content to my pages.

  • re: Search Engine Optimization (SEO) for Silverlight Applications. Part 2

    I used Silverlight application in my website and its very good for general deployment of specific user interfaces.

  • re: Search Engine Optimization (SEO) for Silverlight Applications. Part 2

    Nice application. Thanks for sharing this comprehensive review.

Comments have been closed on this topic.