Introduction

Having set up forms authentication for my little project (which is still on github) I found the need to put a login/logout link/thing on my viewpages.
Since I could not immediately find how to this I asked on the > e and got a swift answer. That answer helped me along, but we still hit a little bump in the road. Here is my journey.

The view

In essence it is very simple to make the login/logout link since you are able to use the Nancy context in your view.

All you need is this.

XML
1
2
3
4
5
6
7
@If Url.RenderContext.Context.CurrentUser Is Nothing Then 
        @<a href="/login">Login</a>
    Else
        @Url.RenderContext.Context.CurrentUser.UserName  
        @<a href="/logout">Logout</a>
    End If
    
@If Url.RenderContext.Context.CurrentUser Is Nothing Then 
        @<a href="/login">Login</a>
    Else
        @Url.RenderContext.Context.CurrentUser.UserName  
        @<a href="/logout">Logout</a>
    End If
    

When a user is not logged in (sometimes also known as logged out) the login link will appear which will guide you to the loginpage. Once the user is logged in we will show his username and the logout link so he can press that and be amazed.

The VB razor syntax was kind of hard to figure out but nothing a little trail and error won’t fix.

And then you go and try this and notice the nice errormessage you will get.

With this in the details view.

Error Details

Error compiling template: Views/Master.vbhtml

Errors:
[BC30652] Line: 8 Column: 0 – Reference required to assembly ‘Nancy, Version=0.14.1.0, Culture=neutral, PublicKeyToken=null’ containing the type ‘Nancy.ViewEngines.IRenderContext’. Add one to your project. (show)
[BC30652] Line: 11 Column: 0 – Reference required to assembly ‘Nancy, Version=0.14.1.0, Culture=neutral, PublicKeyToken=null’ containing the type ‘Nancy.ViewEngines.IRenderContext’. Add one to your project. (show)

Details:



@RenderBody()

So we need to reference Nancy. But how?

By adding some xml to our web.config of course.

XML
1
2
3
4
5
6
7
8
9
10
11
<configSections>
    <section name="razor" type="Nancy.ViewEngines.Razor.RazorConfigurationSection, Nancy.ViewEngines.Razor" />
  </configSections>
  <razor disableAutoIncludeModelNamespace="false">
    <assemblies>
      <add assembly="Nancy" />
    </assemblies>
    <namespaces>
      <add namespace="Nancy.ViewEngines" />
    </namespaces>
  </razor>
<configSections>
    <section name="razor" type="Nancy.ViewEngines.Razor.RazorConfigurationSection, Nancy.ViewEngines.Razor" />
  </configSections>
  <razor disableAutoIncludeModelNamespace="false">
    <assemblies>
      <add assembly="Nancy" />
    </assemblies>
    <namespaces>
      <add namespace="Nancy.ViewEngines" />
    </namespaces>
  </razor>

And now we get our nice login link.

Or of course our nice logout link and username when we are logged in.

Don’t forget that if you have a test project to add an app.config file and add those same lines as above, else your tests will fail.

Alas this is not enough. Our client doesn’t want us to show the username of the logged in user but his or hers real name.

But currentuser only returns us the usernmae. And why is that?
Because currentuser is of type IUserIdentity and that only has two properties, namely: username and claims. And we used IUserIdentity when we made our AuthenticatedUser Class. So nancy is really returning us an AuthenticatedUser object and we can add stuff to that. Like the realname of the user.

Like this.

vb.net
1
2
3
4
5
6
7
8
9
10
11
12
Imports Nancy.Security
 
Namespace Security
 
    Public Class AuthenticatedUser
        Implements IUserIdentity
 
        Public Property UserName() As String Implements IUserIdentity.UserName
        Public Property Claims() As IEnumerable(Of String) Implements IUserIdentity.Claims
        Public Property RealName As String
    End Class
End Namespace
Imports Nancy.Security

Namespace Security

    Public Class AuthenticatedUser
        Implements IUserIdentity

        Public Property UserName() As String Implements IUserIdentity.UserName
        Public Property Claims() As IEnumerable(Of String) Implements IUserIdentity.Claims
        Public Property RealName As String
    End Class
End Namespace

Of course we now also have to update our userservice, usermodel, and the two user views to account for this added property.You can sse those changes in the code on github BTW.

And now we can adapt our loginscript to show the realname instead of the username.

XML
1
2
3
4
5
6
7
@If Url.RenderContext.Context.CurrentUser Is Nothing Then 
        @<a href="/login">Login</a>
    Else
        @CType(Url.RenderContext.Context.CurrentUser, AuthenticatedUser).RealName  
        @<a href="/logout">Logout</a>
    End If
    
@If Url.RenderContext.Context.CurrentUser Is Nothing Then 
        @<a href="/login">Login</a>
    Else
        @CType(Url.RenderContext.Context.CurrentUser, AuthenticatedUser).RealName  
        @<a href="/logout">Logout</a>
    End If
    

I just cast currentuser to the type Authenticateduser and use it’s realname.

Of course this means I also need to add my assembly to the list of assemblies razor needs and add the namespace.

Something like this.

XML
1
2
3
4
5
6
7
8
9
10
<razor disableAutoIncludeModelNamespace="false">
    <assemblies>
      <add assembly="Nancy" />
      <add assembly="NancyDemo.VB" />
    </assemblies>
    <namespaces>
      <add namespace="Nancy.ViewEngines" />
      <add namespace="NancyDemo.VB.Security" />
    </namespaces>
  </razor>
<razor disableAutoIncludeModelNamespace="false">
    <assemblies>
      <add assembly="Nancy" />
      <add assembly="NancyDemo.VB" />
    </assemblies>
    <namespaces>
      <add namespace="Nancy.ViewEngines" />
      <add namespace="NancyDemo.VB.Security" />
    </namespaces>
  </razor>

And now our view looks like this.

And the sky is the limit again.

Have fun.