Cookies and Avalon ClickOnce applications

ClickOnce supports command line parameters and this is one of the easiest way to get the command line parameters. There are lot of articles about how to pass command line/ URL parameters to ClickOnce application in general. Here is one of those articles. Needless to say that the same technique will work for Avalon Window based applications or Browser based applications (XBap).

To run Avalon applications, users will need to have .Net 3.0 runtime installed. For Vista, it is much easier because all the prerequisites are already there and X does not have to think about over head of getting user’s machine setup with runtime etc in most of the cases. The reason why I say most of the cases because there is possibility that Vista has been deployed and option component for .net 3.0 has been turned off. For detecting the presence of run time on user’s machine, .net 3.0 publishes its presence in user agent string as well as in mime type headers. Developer can use these to sniff the presence on user machine and direct user accordingly to either Microsoft website or to boostrapper setup package that can make sure the run time component are installed. VS has nice support for this kind of boostrapper where it also kicks of Installation of actual ClickOnce app at the end of the setup.

Since so many smart people have already talked about it, I wont get into more details here. I wanted to write something the customer specifically asked and we could/did not answer it off the top of our head so I thought it would be interesting to write it down for the posterity.

So here is the scenario…

Customer X is building a Avalon based full trust rich client. They want to deploy this client on all Avalon supported OSs and different languages. They want to download client language depending on the site through which user chose to install their application. For Example…if user navigates to German version of the site they want to install German version of the UI. They obviously take advantage of on demand download functionality that ClickOnce provides. For the cases where they don’t have to install Runtime before the application starts, it was all very simple because they can take advantage of URL parameter functionality mentioned about and pass the local to the application and then Application uses that information to set the culture and download the right culture specific UI DLL. But things get tricky when they have to direct user to boostrapper exe that installs runtime and then launches the ClickOnce installation. Now since the boostrapper.exe does not either accept or pass along these parameter, chain was broken. They want to know how the problem can be solved and here is the solution that I came up with.

  1. User hits domain1 to get to the page where the options are presented to him about downloads
  2. User chooses the option, since this domain knows its own locale, it will redirect user to Domain 2 for actual download and also passing in other options data along with local on URL parameter list
  3. Domain 2 parses URL parameters and servers up the page that actually contains the link for downloading setup.exe.
  4. This page also writes cookies that contain same information passed to domain2 from domain1
  5. When pages is served, cookies are written to disk and user clicks on setup.exe
  6. setup.exe finishes and launches ClickOnce installation
  7. ClickOnce installation finishes and then launches EXE
  8. EXE uses Application.GetCookie() API to read the cookies written.

PS: It is important the at you have domain that serves actual bits write the cookie if application that you are serving is supposed to run in Internet zone sandbox. In this condition reading cookie from some other domain would fail because you need webpermission to the domain you are trying to read cookies for. For full trust it is not a problem so theoretically for this case, domain  1 could have written the cookie and exe could have still read it.

Here some simple code snippets…

NOTE: Code is really just meant to prove point. I did not take any effort at all to do the right thing. I think Cookie reading can be improved a lot 🙂

Domain 1 Page that servers options

Options.aspx

<%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”Options.aspx.cs” Inherits=”_Default” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”
http://www.w3.org/1999/xhtml”>
<head runat=”server”>
<title>Untitled Page</title>
</head>
<body>
<form id=”form1″ runat=”server” action=”
http://bombayboy1/asp/Download.aspx”>
<div>
<asp:CheckBox ID=”chkOptionalComponent” runat=”server” Text=”Download Optional Components” /><br />
Choose your Locale:
<asp:DropDownList ID=”drpdwnLocale” runat=”server”>
<asp:ListItem>English</asp:ListItem>
<asp:ListItem>German</asp:ListItem>
<asp:ListItem>Japanese</asp:ListItem>
</asp:DropDownList><br />
<br />
 <asp:Button ID=”btnSubmit” runat=”server” Text=”Submit (ASP)” OnClick=”btnSubmit_Click1″ /></div>
</form>
</body>
</html>

Options.aspx.cs

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnSubmit_Click1(object sender, EventArgs e)
{
Response.Redirect(“Download.aspx?Locale=” + this.drpdwnLocale.Text + “&OptionalDownload=” + this.chkOptionalComponent.Checked);
}
}

Download.aspx

<%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”Download.aspx.cs” Inherits=”Download” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>

<html xmlns=”http://www.w3.org/1999/xhtml” >
<head runat=”server”>
<title>Untitled Page</title>
</head>
<body>
</body>
</html>

Download.aspx.cs

public partial class Download : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
NameValueCollection param = HttpUtility.ParseQueryString(this.ClientQueryString);
HttpCookie myCookie = new HttpCookie(“UserSettings”);
myCookie[“Locale”] = param[“Locale”];
myCookie[“OptionalDownload”] = param[“OptionalDownload”];
myCookie.Expires = DateTime.Now.AddHours(1);
Response.Cookies.Add(myCookie);
Response.Write(“<a href=\”
http://bombayboy1/Applications/CookieReader.application\”>Install </a> </br>”);
Response.Write(“<a href=\”
http://bombayboy1/Applications/Setup.exe\”>Install Runtime </a>”);
}
}

Application.xaml

<Application x:Class=”cookiereaderapp.App”
xmlns=”
http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
StartupUri=”Window1.xaml” Startup=”OnAppStartup”
>
<Application.Resources>
</Application.Resources>
</Application>

Application.xaml.cs

public partial class App : System.Windows.Application
{
public string Locale = null;
public string OptionalDownload = null;
public void OnAppStartup(object sender, StartupEventArgs e)
{
string cookie = Application.GetCookie(new Uri(“
http://bombayboy1″));
string[] split = cookie.Split(new char[] { ‘=’, ‘&’ });
if (split[1] == “Locale” && split[2] != string.Empty)
{
Locale = split[2];
}
if (split[3] == “OptionalDownload” && split[4] != string.Empty)
{
OptionalDownload = split[4];
}
}
}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: