Creating a Custom Login Page for a LightSwitch Application


When configuring a Visual Studio LightSwitch application to use Forms authentication, the application user is prompted with the following login UI when they open the application:

original-login

Many LightSwitch customers have asked about creating their own custom UI in place of this default login experience.  Maybe you’d like to display the company logo, for example.  This post will show you the steps for creating your own fully customizable login page.

LightSwitch doesn’t have not have built-in support for customizing this UI.  However, since LightSwitch is an ASP-NET based application you can use the features in ASP.NET to workaround this.  What I’m going to demonstrate here is how to create an ASPX page that will authenticate the user when they open the app.  Since you write the content of the ASPX page, you get to control exactly how it looks to the user.  But I’ll make it easy for you by providing some sample markup that you can use and customize.

NOTE:
These instructions are for creating a custom login page for Web-based LightSwitch applications (meaning, the application is hosted within the browser).  There isn’t a way to create a custom login page for a Desktop LightSwitch application.  In addition, these instructions assume that you have Visual Studio Professional or higher installed in addition to LightSwitch.  This isn’t necessarily required, but it makes the task of adding ASPX files to the project simpler; otherwise, you’d have to do this by hand which I won’t be describing in this post.

First, let’s start with a brand new LightSwitch project and open up the application properties window:

open-app-properties

In the application properties window, select the Access Control tab and enable Forms authentication:

enable-forms-auth

Select the Application Type tab and change the client type to Web:

web-app-type

Now switch Solution Explorer into File View in order to manage the physical files that make up a LightSwitch application:

switch-to-file-view 

Next, click the “Show All Files” toolbar button.  This shows all the hidden files within the project.

show-all-files

This is what the resulting project looks like now:

expanded-project

Add a new ASPX page to the ServerGenerated project by selecting the ServerGenerated project and hit Ctrl+Shift+A.  Then select “Web Form” from the Web node and change the filename to “Home.aspx”.  Click the Add button. 

add-login-page

Follow the same steps again to add another ASPX file but name this one “Login.aspx”.  You should now have two ASPX files in your ServerGenerated project:

home-and-login

Open Login.aspx and paste over the existing markup with the following:

C#:

<%@ Page Title="Log In" Language="C#" AutoEventWireup="true"
    CodeBehind="Login.aspx.cs" Inherits="LightSwitchApplication.Login" %>

<form id="Form1" runat="server">
  <div style="text-align:center">
   <!— Add an optional image by replacing this fake image URL with your own –>
   <!--<asp:Image runat="server" ImageUrl="http://contoso.com/logo.gif" />-->
   <asp:Login runat="server" BackColor="#F7F6F3"
           BorderColor="#E6E2D8" BorderPadding="4"
           BorderStyle="Solid" BorderWidth="1px"
           Font-Names="Verdana" Font-Size="0.8em"
           ForeColor="#333333">
       <InstructionTextStyle Font-Italic="True" ForeColor="Black" />
       <LoginButtonStyle BackColor="#FFFBFF" BorderColor="#CCCCCC"
           BorderStyle="Solid" BorderWidth="1px" Font-Names="Verdana"
           Font-Size="0.8em" ForeColor="#284775" />
       <TextBoxStyle Font-Size="0.8em" />
       <TitleTextStyle BackColor="#5D7B9D" Font-Bold="True"
           Font-Size="0.9em" ForeColor="White" />
   </asp:Login>
 </div>
</form>

VB:

<%@ Page Title="Log In" Language="vb" AutoEventWireup="true"
    CodeBehind="Login.aspx.vb" Inherits=".Login" %>

<form id="Form1" runat="server">
  <div style="text-align:center">
   <!— Add an optional image by replacing this fake image URL with your own –>
   <!--<asp:Image runat="server" ImageUrl="http://contoso.com/logo.gif" />-->
   <asp:Login runat="server" BackColor="#F7F6F3"
           BorderColor="#E6E2D8" BorderPadding="4"
           BorderStyle="Solid" BorderWidth="1px"
           Font-Names="Verdana" Font-Size="0.8em"
           ForeColor="#333333">
       <InstructionTextStyle Font-Italic="True" ForeColor="Black" />
       <LoginButtonStyle BackColor="#FFFBFF" BorderColor="#CCCCCC"
           BorderStyle="Solid" BorderWidth="1px" Font-Names="Verdana"
           Font-Size="0.8em" ForeColor="#284775" />
       <TextBoxStyle Font-Size="0.8em" />
       <TitleTextStyle BackColor="#5D7B9D" Font-Bold="True"
           Font-Size="0.9em" ForeColor="White" />
   </asp:Login>
 </div>
</form>

For more details on how to customize the Login control to suit your needs, see the following MSDN article: Customizing the Appearance of ASP.NET Login Controls.

For the Home.aspx page, you can leave the default markup code since this page will never be visible by the user.  We’re only going to use it as a redirection mechanism.

NOTE:

This redirection logic is only needed to workaround an issue in LightSwitch V1 where it will remove from the web.config file at publish-time a configuration setting that will deny anonymous users access.   If you have the ability to modify your web.config file after the app has been published, you can configure it to deny anonymous users by adding the following to the system.web section of the web.config file:

<authorization>
  <deny users="?"/>
</authorization>

If you end up doing this, the Home page described in this blog post would not be necessary within your site.

To setup the redirection logic, open up the code-behind for the Home page, Home.aspx.cs, and replace its contents with the following code:

C#:

using System;
using System.Web.Security;

namespace LightSwitchApplication
{
    public partial class Home : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!this.User.Identity.IsAuthenticated)
            {
                FormsAuthentication.RedirectToLoginPage();
            }
            else
            {
                this.Response.Redirect(FormsAuthentication.DefaultUrl);
            }
        }
    }
}

VB:

Imports System.Web.Security

Public Class Home
    Inherits System.Web.UI.Page



Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles Me.Load If Not Me.User.Identity.IsAuthenticated Then FormsAuthentication.RedirectToLoginPage() Else Me.Response.Redirect(FormsAuthentication.DefaultUrl) End If End Sub
End Class

Next, we need to configure the default page for the site to use this new Home page.  Open the web.config file contained in the ServerGenerated folder.  It will have a section that looks like this:

<defaultDocument>
  <files>
    <clear />
    <add value="default.htm" />
  </files>
</defaultDocument>

To configure the new default page, change “default.htm” to “Home.aspx”.

In addition, we need to configure default.htm to be the page that is redirected to after a successful login.  To do this, find the forms element in the web.config file and add the bolded text:

<authentication mode="Forms">
  <forms name="CustomLoginApp" defaultUrl="default.htm" />
</authentication>

The last step is to configure the main LightSwitch project to be aware of the new ASPX files that were added so that they will be published along with the app. To do this, unload the main LightSwitch project:

unload-project

With the project unloaded, open the physical .LSPROJ file in the IDE:

edit-unloaded-project

Do a search for “_BuildFile” and append the following text within that section of the file:

<_BuildFile Include="ServerGenerated\Login.aspx">
  <SubFolder>
  </SubFolder>
  <PublishType>
  </PublishType>
</_BuildFile>
<_BuildFile Include="ServerGenerated\Home.aspx"> <SubFolder> </SubFolder> <PublishType> </PublishType> </_BuildFile>

Reload the LightSwitch project:

reload-project

Your LightSwitch app is now configured to use your new custom Login page.  When you publish your app and connect to it, you’ll be redirected to your login page.  After successfully logging in, you’ll be redirected to the LightSwitch app.

Comments (16)

  1. adefwebserver says:

    You Rock!. I am at the Visual Studio Live Conference in Orlando right now, and this has come up multiple times.

  2. Thanks very much for this! This is a much needed feature that you've made easy.

    My only worry is what will happen when v2 is released and this breaks! Still, we'll wait until that happens eh?

    Thanks again.

  3. AlexFormoso says:

    Will you be so kind to post this workaround to the Desktop Apps too, please?

  4. mthalman says:

    @AlexFormoso:

    As I mentioned, this ASP.NET-based solution is not possible with desktop apps.  Although not a recommended approach, there is a way to modify the Silverlight controls of the built-in Login page at runtime.  This approach is described in this thread: social.msdn.microsoft.com/…/6dde7955-6a18-41d8-a4fd-78610a37bdad.  This is not a recommended approach because it relies on the internal implementation of how LightSwitch defines the Silverlight login page.  It may change in the future which could potentially break this solution.

  5. hatipoglu79 says:

    Thank you for sharing but if users want to reset their password??

  6. mthalman says:

    @hatipoglu79:

    To implement a password reset mechanism in your custom login page, ASP.NET provides a PasswordRecovery control.  See msdn.microsoft.com/…/ms178335.aspx for more information.

  7. Quinton says:

    Wow, thanks for sharing this!!!!!!!!!

  8. Thanks Matt

    This is functionallity that is asked many times on forum.

    Best regards

  9. Peter says:

    Cool, just need this at the moment.  Thanks a lot.

  10. Robin Lutteke says:

    Hi,

    Great post! But i have a question. When they are logged in they need to get a role. Something like read only account  and an account that can edit data. Is this posible?

    Thanks you for your response!

  11. mthalman says:

    @Robin:

    Assignments of users to roles can be managed via the built-in administration screens within the LightSwitch application.  See the Roles and Users section of msdn.microsoft.com/…/ff851957.aspx.

  12. I know that part of LightSwitch, but when the use login the application doesnt know my user. It says that it is a test user. What am i doing wrong?

    This is my code for Login:

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

    using System.Web.UI;

    using System.Web.UI.WebControls;

    using System.Web.Security;

    using System.Xml;

    using System.IO;

    using System.Net;

    namespace LightSwitchApplication

    {

       public partial class Login : System.Web.UI.Page

       {

           // Local specific CAS hostprivate const

           string CASHOST = "login.hro.nl/…/";

           // After the page has been loaded, this routine is called.protected void

           protected void Page_Load(object sender, EventArgs e)

           {

               // Look for the "ticket=" after the "?" in the URL  

               string tkt = Request.QueryString["ticket"]; //[CAS:"ticket"];  

               // This page is the CAS service=, but discard any query string residue  

               string service = Request.Url.GetLeftPart(UriPartial.Path);

               // First time through there is no ticket=, so redirect to CAS login  

               if (tkt == null || tkt.Length == 0)

               {

                   string redir = CASHOST + "login?" + "service=" + service;

                   //string redir = CASHOST + "login?" + "service=" + service + "&rcl=63";

                   Response.Redirect(redir);

                   return;

               }

               // Second time (back from CAS) there is a ticket= to validate  

               string validateurl = CASHOST + "serviceValidate?" + "ticket=" + tkt + "&" + "service=" + service;

               StreamReader Reader = new StreamReader(new WebClient().OpenRead(validateurl));

               string resp = Reader.ReadToEnd();

               // I like to have the text in memory for debugging rather than parsing the stream  

               // Some boilerplate to set up the parse.  

               NameTable nt = new NameTable();

               XmlNamespaceManager nsmgr = new XmlNamespaceManager(nt);

               XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None);

               XmlTextReader reader = new XmlTextReader(resp, XmlNodeType.Element, context);

               string netid = null;

               while (reader.Read())

               {

                   if (reader.IsStartElement())

                   {

                       string tag = reader.LocalName;

                       if (tag == "user")

                           netid = reader.ReadString();

                   }

               }

               if (netid == null)

               {

                   Label1.Text = "CAS returned to this application, but then refused to validate your identity.";

               }

               else

               {

                   FormsAuthentication.RedirectFromLoginPage(netid, false);

                   // set netid in ASP.NET blocks  

               }

           }

       }

    }

    I need to know my user and give him a role.

    Great post! Cheers!!!

  13. mthalman says:

    @Robin:

    I assume you are running your application from the IDE?  During development, LightSwitch bypasses the normal user login and makes use of its own "Test User" account.  You'll need to publish your application somewhere to actually see LightSwitch make use of your user account.

  14. Really a great post, but is it also posible to change the AspNetProfileProvider property FullName?

    I want change it too the name of the login person.

    Cheers!

  15. mthalman says:

    @Robin:

    Sure, you can write code like the following:

    ProfileBase profile = System.Web.Profile.ProfileBase.Create("username");

    profile.SetPropertyValue("FullName", "Robin Lutteke");

    profile.Save();

  16. Hi!

    Is this applicable to Windows Authentication? I mean, can you create a custom login page for LightSwitch when it is set to use Windows Authentication? Or is there a way to use Forms Authentication against Active Directory ie. domain login?

    Thanks.