Getting the NTLM Username into your Silverlight application

Sometimes you want to know the username of a user that's logged on to your domain. This specially the occasion for intranet applications. Let's assume we are building an intranet application because this is the only occasion where a NTLM username is valid I guess. There is no way we can get the NTLM Username directly from within Silverlight yet. So we have two options left: Client Side Javascript and Server Side scripting.

Client Side

Let's begin with the Client Side Javascript. At least we should start investigating it. The first piece of code I found makes use of ActiveX, see the following:

var wshshell=new ActiveXObject("wscript.shell"); var username=wshshell.ExpandEnvironmentStrings("%username%");

Sadly it throws an error, not a good start. Google again. Not many options left, most people just say it isn't possible. After a while I found the following:

var wshNetwork = new ActiveXObject("WScript.Network"); var username = WshNetwork.UserName;

But this also throws an error. So I guess we are left to the Server Side solution.

Server Side

So what we have left is Server Side scripting. We can again take different approaches like calling the server side through Ajax but I took the easy way, by just generating the NTLM Username into the HTML. We can make use of the InitParams to pass some startup parameters to the Silverlight control. The InitParams is a string that has comma-separated name-value pairs that are separated by the equals sign. So this could look like the following in HTML:

<param name="InitParams" value="name1=value1,name2=value2" />

What we do in the ASPX page where the Silverlight control is hosted, add the following code in the Page_Load:

1 if (User != null && User.Identity != null && User.Identity.IsAuthenticated) 2 Silverlight1.InitParameters = string.Format("User.Identity.Name={0}", User.Identity.Name);

In Silverlight we can read this value in the App.xaml.cs.

1 private void Application_Startup(object sender, StartupEventArgs e) 2 { 3 string userName = e.InitParams["User.Identity.Name"]; 4 this.RootVisual = new Page(); 5 }

The generated HTML looks like the following:

<param name="InitParams" value="User.Identity.Name=DOMAINNAME\Username"></param>

Linq to SQL doing it manually: Part 3 - Relationships

Beside column mapping we did in Part 1 of the "Linq to SQL doing it manually" series. We also want to have relationships, this part will be all about relationships. The series contains the following parts:

When we take a look at the generated code for a one-to-many relation it has the following looks.

For the one-side:

1 private EntityRef<Post> _Post; 2 [Association(Name="Post_PostTagRelation", Storage="_Post", ThisKey="PostId", OtherKey="Id", IsForeignKey=true)] 3 public Post Post 4 { 5 get 6 { 7 return this._Post.Entity; 8 } 9 set 10 { 11 Post previousValue = this._Post.Entity; 12 if (((previousValue != value) 13 || (this._Post.HasLoadedOrAssignedValue == false))) 14 { 15 this.SendPropertyChanging(); 16 if ((previousValue != null)) 17 { 18 this._Post.Entity = null; 19 previousValue.PostTagRelations.Remove(this); 20 } 21 this._Post.Entity = value; 22 if ((value != null)) 23 { 24 value.PostTagRelations.Add(this); 25 this._PostId = value.Id; 26 } 27 else 28 { 29 this._PostId = default(System.Guid); 30 } 31 this.SendPropertyChanged("Post"); 32 } 33 } 34 } 35 36 private System.Guid _PostId; 37 [Column(Storage="_PostId", DbType="UniqueIdentifier NOT NULL", IsPrimaryKey=true)] 38 public System.Guid PostId 39 { 40 get 41 { 42 return this._PostId; 43 } 44 set 45 { 46 if ((this._PostId != value)) 47 { 48 if (this._Post.HasLoadedOrAssignedValue) 49 { 50 throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException(); 51 } 52 this.OnPostIdChanging(value); 53 this.SendPropertyChanging(); 54 this._PostId = value; 55 this.SendPropertyChanged("PostId"); 56 this.OnPostIdChanged(); 57 } 58 } 59 }

For the many-side:

1 private EntitySet<PostTagRelation> _PostTagRelations; 2 [Association(Name="Post_PostTagRelation", Storage="_PostTagRelations", ThisKey="Id", OtherKey="PostId")] 3 public EntitySet<PostTagRelation> PostTagRelations 4 { 5 get 6 { 7 return this._PostTagRelations; 8 } 9 set 10 { 11 this._PostTagRelations.Assign(value); 12 } 13 }

I think this is a lot of code. So let's try to minimize this.

For the one-side:

1 [Column(IsPrimaryKey = true)] 2 private Guid PostId { get; set; } 3 4 [Association(IsForeignKey = true, ThisKey = "PostId")] 5 public Post Post { get; set; }

For the many-side:

1 private IList<PostTagRelation> postTagRelations = new List<PostTagRelation>(); 2 [Association(Storage = "postTagRelations", OtherKey = "PostId")] 3 public IList<PostTagRelation> PostTagRelations 4 { 5 get { return postTagRelations; } 6 set { postTagRelations = value; } 7 }

A lot less code I would guess. From 72 lines to just 12 lines. But we are not there yet. After some testing I found out the generated relation is bi-directional, and the relation I created is just uni-directional. What does this mean? This means that if you manipulated either post.PostTagRelations or postTagRelation.Post the other will be changed as well in a bi-directional relation. I remember in the past you had to do something special to make this work with NHibernate. I have no solution for this right now, but you can take a look at how other people did something similar on CodePlex. One of the troubles I find in the solution they propose is the usage of EntityRef and EntitySet. Those are both parts of Linq to SQL and would kind of interfere with my other code-parts, if used.

Another feature that is lost is lazy loading. I must admit I don't hate it being lost. I think people must think about persistence before doing everything automatically. So if we want to load only the tags we don't have to anything special. But if we also want to load the PostTagRelations and the Posts with the tags we will have to add some DataLoadOptions. The following code example show how it works.

1 using (var context = new Context("")) 2 { 3 var dataLoadOptions = new DataLoadOptions(); 4 dataLoadOptions.LoadWith<Tag>(t => t.PostTagRelations); 5 dataLoadOptions.LoadWith<PostTagRelation>(ptr => ptr.Post); 6 //dataLoadOptions.LoadWith<PostTagRelations>(ptr => ptr.Tag); 7 context.LoadOptions = dataLoadOptions; 8 9 var dotNetTag = (from tag in context.Tags 10 where tag.Name.Equals(".NET") 11 select tag).Single(); 12 13 Assert.Equal(3, dotNetTag.PostTagRelations.Count()); 14 15 var posts = from postTagRelation in dotNetTag.PostTagRelations 16 where postTagRelation.Post != null 17 select postTagRelation.Post; 18 Assert.Equal(3, posts.Count()); 19 20 var tags = from postTagRelation in dotNetTag.PostTagRelations 21 where postTagRelation.Tag != null 22 select postTagRelation.Tag; 23 Assert.Equal(3, tags.Count()); 24 }

The only thing I must admit, line 23 fails. The tags aren't loaded in the PostTagRelations. I tried adding line 6 but this did throw an exception: "System.InvalidOperationException : Cycles not allowed in LoadOptions LoadWith type graph." I have no solution for this yet, but it has something to do with the bi-directional issue I also found.

There are some areas of improvement on the relationships with Linq to SQL.

Certified? Indoor Skydiving

Just a few weeks ago I was on a trip with my department of Rubicon. Besides a good dinner we also went skydiving, indoor skydiving in Roosendaal. If you have a chance to take a sky dive lesson, I think you should take it. Thanks to Robert Krom for taking the picture. Me, skydiving indoorskydive