Business Apps Example for Silverlight 3 RTM and .NET RIA Services July Update: Part 4: SEO, Export to Excel and Out of Browser

More from my Mix09 talk “building business applications with Silverlight 3”.

You can watch the original  video of the full session 

The demo requires (all 100% free and always free):

  1. VS2008 SP1 (Which includes Sql Express 2008)
  2. Silverlight 3 RTM
  3. .NET RIA Services July '09 Preview

Also, download the full demo files and check out the running application.

Today, we will talk about Different views of our application logic. 

Different Views

Now, let’s take take a look at putting different views on this same application.  One of the key elements to supporting different views is deeplinking.   Let’s look at adding that to this application.  

image

First, we need to add a textbox to display the deeplink for each of our super employees.

 <TextBlock Text="PermaLink:"></TextBlock>
 <TextBox x:Name="PermalinkTextBox" Width="400" Height="25" TextWrapping="NoWrap" Foreground="#FFB4B4B4" />

And just wire this up in code behind..

 private void dataGrid1_SelectionChanged(object sender, SelectionChangedEventArgs e)
 {
     var emp = dataGrid1.SelectedItem as SuperEmployee;
     if (emp != null)
     {
         PermalinkTextBox.Text = Application.Current.Host.Source.ToString().Replace("ClientBin/MyApp.xap", "") +
             "#/Home?EmpId=" + emp.EmployeeID;
     }    
  
 }

image_thumb[98]

Now we need to make the page smart enough to know about this deep link..

 protected override void OnNavigatedTo(NavigationEventArgs e)
 {
     var qs = NavigationContext.QueryString;
  
     if (qs.ContainsKey("EmpId"))
     {
         dds.FilterDescriptors.Add(
             new FilterDescriptor("EmployeeID",
                 FilterOperator.IsEqualTo, qs["EmpId"]));
     }
 }

Now, run it…  cut and paste this url into a browser brings up exactly this record. 

image_thumb[100]

OK, now that we have a deeplink, what can we do with it?  Well, you can send the link around in email, IM and in blogs.

But what if you wanted the search engines to be able to find all the items in your site?  It turns out there is a standard format for this called a sitemap (https://sitemap.org).  Check out https://amazon.com/robots.txt for an example in the real world.

To add this to our application, say File\New Item in the Server Project and select the “Search Sitemap”.

image_thumb[71]

This added a robots.txt and a sitemap.aspx.   Let’s look at customizing the sitemap.aspx file.  Notice we are using a new ASP.NET datasource control… that is designed to work with the DomainService class.  This gives us server access to the same application logic from Silverlight and ASP.NET. 

 <asp:DomainDataSource runat="server" ID="SitemapDataSource" 
     DomainServiceTypeName="MyApp.Web.SuperEmployeeDomainService" 
     SelectMethod="GetSuperEmployees" />
 <url>
     <loc><%= new Uri(this.Request.Url, this.ResolveUrl("Default.aspx"))+ "?EmpId="  %><%# HttpUtility.UrlEncode(Eval("EmployeeID").ToString()) %></loc>
     <lastmod><%# (Eval("LastEdit") as DateTime?).GetValueOrDefault().ToString("yyyy-MM-dd")%></lastmod>
 </url>

One last tweak to enable the server side of the app to access the employee ID..  in default.aspx.cs add:

 protected void Page_Load(object sender, EventArgs e)
 {
     string empId = Request.QueryString["EmpId"];
     var deepLink = "/Home?EmpId=" + empId;
  
     if (empId != null)
     {
         Response.Write("<script type=text/javascript>window.location.hash='#" + deepLink + "';</script>");
     }
  
  
 }

Now run it… 

image_thumb[73]

and the sitemap…

image_thumb[104]

Cut and pasting the URL brings open that item.

image_thumb[103]

OK… that works great.  Now the search engine can find every entity in our application.  But what will the search engine find when it gets there?  Search engines are great at parsing html, but dynamic content like we are seeing in this site or in rich ajax sites are a lot harder for search engines to deal with. 

image_thumb[82]

The art of addressing this is called SEO (Search Engine Optimization).    Let’s go and apply SEO principles to our application, open up BusinessApplicationTestPage.aspx  Because we have modeled our application logic in a domain service class it is very easy to add a standards based HTML view.    Just add this code into the object tag in default.aspx.. 

 <form id="form1" runat="server" style="height:100%">
              <asp:DomainDataSource runat="server" ID="DetailsDataSource" 
                        DomainServiceTypeName="MyApp.Web.SuperEmployeeDomainService" 
                        SelectMethod="GetSuperEmployee">
               <SelectParameters>
                   <asp:QueryStringParameter  Name="employeeID" Type="Int32" Querystringfield="EmpId" />
               </SelectParameters>       
           </asp:DomainDataSource>
          <asp:ListView ID="EmployeeDetails" runat="server"  DataSourceID="DetailsDataSource" >
             <LayoutTemplate>                  
               <asp:PlaceHolder ID="itemPlaceholder" runat="server"></asp:PlaceHolder>    
             </LayoutTemplate>
             <ItemTemplate>
                <h1><a href="<%# Eval("EmployeeID")%>" > <%# Eval("Name")%> </a>  </h1>
                  <table>
                  <tr> <td><b>Name:</b> <%# Eval("Name")%> </td> </tr>
                  <tr> <td><b>Publisher:</b> <%# Eval("Publishers")%> </td></tr>
                  <tr> <td><b>Gender:</b> <%# Eval("Gender")%></td> </tr>
                  <tr> <td><b>Origin:</b> <%# Eval("Origin")%></td> </tr>
                  <tr> <td><b>Issues:</b> <%# Eval("Issues")%></td> </tr>
                  <tr> <td><b>Sites: </b><%# Eval("Sites")%></td> </tr>
               </table>
             </ItemTemplate>
          </asp:ListView>
  
  

We need add a GetSuperEmployee domain method to support this code..  so back to our SuperEmployeeDomainService and add:

  
         public SuperEmployee GetSuperEmployee(int employeeID)
         {
             return this.Context.SuperEmployeeSet
                        .Where(emp => emp.EmployeeID == employeeID)
                        .FirstOrDefault();
         }

Now run it… Disable Silverlight in the browser because hey, search engines don’t have silverlight installed. 

image

Now hit refresh on a deep link…

image

Just for kicks… let’s run this application in lynx

image

image

Pretty cool, huh?  Now the search engine (or anyone without Silverlight) can access the data. 

But does it work?  well, try these searches:

Super employee placement Alfred (Yahoo)

Super Employee Placement Alfred (some other guy)

OK, that was a server view, let’s try a different client view..  Let’s export this data to the worlds best data manipulation tool – excel! 

Add the template file to the project to the client root. 

Then add an “export to excel” button:

 <Button Content="Export to Excel" 
         Width="105" Height="28"
         Margin="5,0,0,0" HorizontalAlignment="Left"
         Click="ExportToExcel_Click" ></Button>

And write out the excel file…  Notice this is all safe access as the Silverlight runtime proxies the user selection of the location to write the file.  The developer can not get direct access to the file location. 

 private void ExportToExcel_Click(object sender, RoutedEventArgs e)
 {
     var context = dds.DomainContext as SuperEmployeeDomainContext;
     var s = Application.GetResourceStream(new Uri("excelTemplate.txt", UriKind.Relative));
     var dialog = new SaveFileDialog();
  
     dialog.DefaultExt = "*.xml";
     dialog.Filter = "Excel Xml (*.xml)|*.xml|All files (*.*)|*.*";
  
     if (dialog.ShowDialog() == false) return;
  
     using (var sw = new StreamWriter(dialog.OpenFile()))
     {
         var sr = new StreamReader(s.Stream);
         while (!sr.EndOfStream)
         {
             var line = sr.ReadLine();
             if (line == "***") break;
             sw.WriteLine(line);
         }
  
         foreach (var emp in context.SuperEmployees)
         {
             sw.WriteLine("<Row>");
             sw.WriteLine("<Cell><Data ss:Type=\"String\">{0}</Data></Cell>", emp.Name);
             sw.WriteLine("<Cell><Data ss:Type=\"String\">{0}</Data></Cell>", emp.Origin);
             sw.WriteLine("<Cell><Data ss:Type=\"String\">{0}</Data></Cell>", emp.Publishers);
             sw.WriteLine("<Cell><Data ss:Type=\"Number\">{0}</Data></Cell>", emp.Issues);
             sw.WriteLine("</Row>");
         }
         while (!sr.EndOfStream)
         {
             sw.WriteLine(sr.ReadLine());
         }
     }
 }
     }

Run it…

image_thumb[83]

image

This creates an excel file on the user selected location.

image

Opening it and doing a bit of formatting…

image

And the final view… out of browser. 

Select properties on the client application

image_thumb[85]

Edit the settings.. 

image_thumb[86]

Run the application, right click and select “Install….”

image_thumb[88]

image_thumb[89]

Put a link on the desktop.. 

image

and run it!

image_thumb[90]

Comments

  • Anonymous
    July 14, 2009
    Hi, I downloaded the project and tried it out.  It failed because NORTHWIND.MDF version 655 cannot be opened since this server only supports version 612 and earlier.  I think I have the latest version of Sql Server 2008 Express installed?  I installed visual studio 2008 SP1. Thanks Rich

  • Anonymous
    July 14, 2009
    Just FYI: All the images except the first diagram a linked to local files. e.g. (file:///C:/Users/brada/AppData/Local/Temp/WindowsLiveWriter-429641856/supfilesD1D2F6D/image[198].png) ~Lee

  • Anonymous
    July 14, 2009
    Brad, I'm building a site using Silverlight 3 with an equivalent HTML edition of the public parts of the site. Therefore the things you're talking about regarding the SEO type features are quite important. One of the problems that I've discovered is the necessity in Internet Explorer to put height=100 on virtually every HTML element (not required in Firefox). This causes problems for Internet Explorer (8 at least) when you have normal content within the object tag. When you try and scroll a page in this situation rather than a smooth scrolling experience you get several repaints as it tries to scroll up and down. Will Microsoft be providing some complete examples of sites with a full fidelity HTML experience as well as Silverlight? The Silverlight store experience you have previously referred to doesn't have this problem, because it has surrounding HTML content around the Silverlight plug-in. ...Stefan

  • Anonymous
    July 15, 2009
    The comment has been removed

  • Anonymous
    July 15, 2009
    Hi Brad and thanks for your really interesting posts of new silverlight 3 features that we talk about for developping a new website on the enterprise where i work and please excuse my bad english on some words maybe ^^ I got an important question about SEO : I think not but is it needed to have a full silverlight website to use SEO functionnality or is a silverlight control included inside a asp.net website (using css) can use it as the same ? I have to make a product simulation website (looking like this one : http://www.spreadshirt.net/fr/FR/Creer-t-shirt/Personnaliser-59/ ) and i would like customers using that simulation program be able to save and get by physical web adress their composition and that search engines be able to get it too (i would like use database table to store Product ID /  icons ID / x;y position / size / for example and make a deep 'long' link with all that data to get back product customization on a web adress). U think it's possible ? Thank u. Regards. Thierry.

  • Anonymous
    July 31, 2009
    Hi Brad, I'm totally new to Silverlight and worried quite a long time how I can handle SEO and Depp Links with Silverlight. Thanks to you for your explanation here - will follow your blog updates.

  • Anonymous
    August 30, 2009
    Brad, I'm keen to understand what aspects of the Out-of-Browser experience you think can enhance a LOB application. Are you suggesting it is useful when  temporary disconnected when combined with Isolated Storage? Thanks Richie  

  • Anonymous
    September 02, 2009
    The comment has been removed