Archive

Posts Tagged ‘Browser’

Getting the user credentials both in and out of the browser in Silverlight

January 15, 2011 5 comments

Silverlight is quite powerful and gives you a lot of flexibility. You can have your application run in the browser our you can opt for a more Windows like experience and run your application Out of the Browser. One of the frustrations that I have encountered in the past, is trying to write my code so that it supports both.

A common scenario is trying to get the current user signed into the computer. With Silverlight running in the browser, this is quite easy by passing information into the InitParams. But this becomes quite a bit more difficult when you are trying to do the same Out of the Browser.

The following is a screen shot of retrieving the currently signed in user from a web page:

Current User - Browser

In discussing this issue with some colleagues of mine, it came to me that solving the problem for out of the browser could be quite simple if we allow for elevated priviledges. My solutions was to use COM Automation.

The following is the same application now running out of the browser displaying the currently signed in user:

Current User - Out Of Browser

In this post we will go through getting the currently signed in user from the hosting web page and then via COM.

We will start with the web page first. First of all, you need to have a web page that has code-behind associated with it. The default behavior of Visual Studio is to create an ASPX page without any code-behind. The following is a code snippet of the hosting web page:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="TestComInterop.Web.Default" %>




    TestComInterop
    <!--
    html, body {
	    height: 100%;
	    overflow: auto;
    }
    body {
	    padding: 0;
	    margin: 0;
    }
    #silverlightControlHost {
	    height: 100%;
	    text-align:center;
    }
    
-->
    <script src="Silverlight.js" type="text/javascript"><!--mce:0--></script>
    <script type="text/javascript"><!--mce:1--></script>


<form id="form1" style="height: 100%;">
<div id="silverlightControlHost"></div>
</form>


I posted the whole in its entirety but there is only one element that you need to pay attention to with the ID=”InitParameters”. We will use this Literal tag to inject our current user from the code-behind.

Now let’s look at the code-behind:

public partial class Default : System.Web.UI.Page
{
	protected void Page_Load(object sender, EventArgs e)
	{
		Response.Cache.SetCacheability(HttpCacheability.NoCache);
		ConfigureSilverlightDeploymentSettings(InitParameters);
	}

	private static void ConfigureSilverlightSettings(Literal settings)
	{
		StringBuilder sb = new StringBuilder();
		sb.Append("<param name=\"InitParams\" value=\"");
		sb.Append("UserName");
		sb.Append("=");
		sb.Append(System.Security.Principal.WindowsIdentity.GetCurrent().Name);
		sb.Append("\" />");
		settings.Text = sb.ToString();
	}
};

Basically, I am turning off caching in the Page_Load method as well as calling the ConfigureSilverlightSettings method. It is in this method that we dynamically construct a Param with the name of “InitParams”. This is the mechanism that Silverlight gains access to parameters we wish to pass to it externally. We then just create a key/value pair setting the UserName value to GetCurrent().Name property from System.Security.Principal.WindowsIdentity.

The last piece of this puzzle is to see how this is accessed from Silverlight. This leads us to the App.xaml.cs file. For brevity, I am only going to show you the Application_Startup method as it is the only thing that concerns us:

private void Application_Startup(object sender, StartupEventArgs e)
{
	this.RootVisual = new MainPage();

	if (Application.Current.IsRunningOutOfBrowser)
	{
		if (AutomationFactory.IsAvailable)
		{
			using (dynamic wScript = AutomationFactory.CreateObject("WScript.Network"))
			{
				this.UserName = string.Format(@"{0}\{1}", wScript.UserDomain, wScript.UserName);
			}
		}
	}
	else
	{
		// We are running in the browser and can use the HTML-Bridge to get our user.
		this.UserName = e.InitParams.ContainsKey("UserName") ? e.InitParams["UserName"] : "UNKNOWN";
	}

	Application.Current.Resources.Add("UserName", this.UserName);
}

I am showing you the solution for both but I want you to first focus on the else condition. Basically, we are just pulling the key/value pair from the InitParams object off of the StartupEventArgs object. I also ensure that we get a dummy value if no “UserName” exists as a key.

The final step is to add this to the Application.Current.Resources dictionary so that we can access it globally. You may have your own mechanism or may want to use your favorite DI/IOC container to handle this as well.

This really completes the web page workflow. Since we have the code for the App.xaml.cs file, let’s examine how this is accomplished out of the browser. If you look above, we are first checking to be sure that the application IsRunningOutOfBrowser. We also check to be sure that we have elevated priviledges to use COM Automation. Once this is established the we simply create a “WScript.Network” object. This allows us to use the Windows Script API and access the networking stack. Finally we format a string so that it looks just like what we would get from the web page.

The last piece of the puzzle is displaying the message box. The code-behind from the MaingPage.xaml file has the follwoing content:

public partial class MainPage : UserControl
{
	public MainPage()
	{
		InitializeComponent();
	}

	private void Button_Click(object sender, RoutedEventArgs e)
	{
		if (Application.Current.IsRunningOutOfBrowser)
		{
			MessageBox.Show(string.Format("OOB Current User: {0}", Application.Current.Resources["UserName"]));
		}
		else
		{
			MessageBox.Show(string.Format("Browser Current User: {0}", Application.Current.Resources["UserName"]));
		}
	}
};

I only added a condition test so that the screen shots would be different. The rest is just accessing the Resources property off of the Application.Current object. Again, you could do this quite differently using DI/IOC in your code.

I have zipped up a sample application to download here.

Hope this helps….

Follow

Get every new post delivered to your Inbox.

Join 175 other followers