Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Integrating Visual Studio LightSwitch Application Into An Existing Website using IFrames

0.00/5 (No votes)
25 Oct 2011 1  
An advanced LightSwitch tutorial covering PreProcess Queries, Email, PopUps, WCF RIA Services, and HTML pages
Image 1
Image 2

Live Example

For an Introductory Article on LightSwitch, See

Note: You must have Visual Studio Professional, or higher, to perform all the steps in this tutorial.

You can download Visual Studio LightSwitch from this link:

Putting Multiple LightSwitch Applications Into Your Website

Microsoft Visual Studio LightSwitch suffers from what I call the "full screen limitation". LightSwitch wants to fill the entire screen, and it wants to manage the roles and users. This is fine if you only have one application, however in many situations, you want a LightSwitch application to be part of a group of applications in a single portal. You want all applications to share the same users, roles and database.

Unlike the article Online Ordering, that describes a normal "LightSwitch only" deployment, this article will explore the techniques used to deploy a LightSwitch application inside a ASP.NET application that contains other applications. In this article, DotNetNuke will be used, however, everything here can be used in any ASP.NET application.

The key to integrating LightSwitch into an ASP.NET application, is to use IFrames.

The Requirements

In this example, we will create an application that meets the following requirements:

  • Allow Registered Users (the Posters), the ability to create Posts of things they have for sale, without the need to post their email address
  • Allow Anonymous Users (the Buyers) the ability to see the Posts without requiring them to have the Silverlight plug-in installed
  • Allow the Buyers the ability to respond to a Post, and automatically email the Poster
  • Allow the Poster the ability to view and respond to all communications sorted by Post
  • Allow Administrators the ability to edit all data

This may not be considered a large application, but it would take a few days effort. With LightSwitch, you can create the entire application in about an hour.

Walk-Through of the 'Things For Sale' Application

Image 3

You can try out the live Things For Sale application at this link:

When you are not logged-in, you will see a list of Posts that you can browse.

Image 4

You can click on a Post to send the Poster a message.

Image 5

When you log in, you will have the ability to create Posts, and to see any Messages related to a Post (you will be emailed when a new Message is created for one of your Posts).

Image 6

Also note, that there are a lot of other features such as Concurrency Checking and Automatic Ellipses that LightSwitch implements automatically.

Creating the Application

Image 7

You can download Visual Studio LightSwitch from this link:

After installing it, use File, New Project to create a LightSwitch application.

Image 8

Double-click on Properties in the Solution Explorer.

Image 9

Set the application as a Web application.

Image 10

Set it to use Forms Authentication.

Categories Table And Screen

Image 11

Creating a table for Categories and a screen to edit them, this is a task that can be completed in under a minute.

Right-click on the Data Sources node in the Solution Explorer, and select Add Table.

Image 12

Click on the table name to change the name. Enter Category for the name.

Image 13

Create the table above.

Image 14

Right-click on the Screens node, and select Add Screen...

Image 15

Create an Editable Grid Screen using Categories (LightSwitch automatically 'pluralizes' the name of the table).

Image 16

The screen will display.

Image 17

Hit F5 to run the application.

Image 18

We can now create Categories in the application.

Close your web browser to stop the application.

Create the Remaining Tables

Image 19

Create a Post table with the schema above.

Image 20

Create a Message table with the schema above.

Create Relationships

Image 21

Open the Message table, and click the Relationship button.

Image 22

In the Add New Relationship box, enter the settings above.

Image 23

Open the Post table.

In the Add New Relationship box, enter the settings above.

Image 24

The relationships are complete.

Setting relationships is very important with LightSwitch. It allows important features, such as allowing you to create screens, where the Posts and the Messages related to the Posts, always stay in sync, without requiring any code.

It is very rare for any Entity (table) to not have a relationship to one or more other Entities.

Set Default Values on Record Creation

Image 25

Open the Message table, and select Write Code, then Message Created.

Change the method to the following:

 partial void Message_Created()
{
    this.MessageCreated = DateTime.UtcNow;
}

This will set the date for a Message when it is created. Notice that we are using "UtcNow" so that the time is recorded in Coordinated Universal Time (UTC) time. When we display the time, we can convert it to the user's local time.

Image 26

Open the Post table, and select Write Code, then Post Updating.

Change the method to the following:

 partial void Posts_Updating(Post entity)
{
    entity.PostUpdated = DateTime.UtcNow;
}

Image 27

Open the Post table, and select Write Code, then Post Created.

Change the method to the following:

 partial void Post_Created()
{
    this.PostedBy = this.Application.User.Name;
    this.PostCreated = DateTime.UtcNow;
    this.PostUpdated = DateTime.UtcNow;
    this.Active = true;
}

Note the line:

this.PostedBy = this.Application.User.Name;

This is all that is required to segment the data by user.

At run-time, the DotNetNuke site (or any ASP.NET site running under Forms Authentication), will provide the username for "this.Application.User.Name".

In a later step, we will use a PreProcess query to restrict a user to only see their own Posts (and Messages).

Sending Emails

Image 28

This application will require emails to be sent. Let's enable that functionality now.

To do this, we will need to switch to File View.

Image 29

In the Server project, add references to System.configuration and System.Messaging.

Image 30

Add a class called MailHelper.cs to the UserCode folder of the Server project.

Use the following code:

// Adapted from:
// http://www.paulspatterson.com/technology/lightswitch/
//   microsoft-lightswitch-sending-emails-from-the-client/#more-2896

using System.Net;
using System.Net.Mail;
using System.Configuration;
using System;

namespace LightSwitchApplication
{
    public class MailHelper
    {
        private string _SMTPSendingEmailAddress { get; set; }
        private string _SMTPServer { get; set; }
        private string _SMTPUserId { get; set; }
        private string _SMTPPassword { get; set; }
        private int _SMTPPort { get; set; }
        private bool _SMTPSSL { get; set; }

        private string _MailFromName { get; set; }
        private string _MailToEmail { get; set; }
        private string _MailToName { get; set; }
        private string _MailSubject { get; set; }
        private string _MailBody { get; set; }

        public MailHelper(
            string SendFromName, string SendToEmail,
            string SendToName, string Subject,
            string Body)
        {
            _MailFromName = SendFromName;
            _MailToEmail = SendToEmail;
            _MailToName = SendToName;
            _MailSubject = Subject;
            _MailBody = Body;

            _SMTPSendingEmailAddress = Convert.ToString
                    (ConfigurationManager.AppSettings["SMTPSendingEmailAddress"]);
            _SMTPServer = Convert.ToString(ConfigurationManager.AppSettings["SMTPServer"]);
            _SMTPUserId = Convert.ToString(ConfigurationManager.AppSettings["SMTPUserID"]);
            _SMTPPassword = Convert.ToString(ConfigurationManager.AppSettings["SMTPPassword"]);
            _SMTPPort = Convert.ToInt32(ConfigurationManager.AppSettings["SMTPPort"]);
            _SMTPSSL = Convert.ToBoolean(ConfigurationManager.AppSettings["SMTPSSL"]);
        }

        public void SendMail()
        {
            MailMessage mail = new MailMessage();

            System.Net.Mail.MailAddress mailFrom =
                new System.Net.Mail.MailAddress(_SMTPSendingEmailAddress, _MailFromName);

            System.Net.Mail.MailAddress mailTo =
                new System.Net.Mail.MailAddress(_MailToEmail, _MailToName);

            var _with1 = mail;
            _with1.From = mailFrom;
            _with1.To.Add(mailTo);
            _with1.Subject = _MailSubject;
            _with1.Body = _MailBody;

            SmtpClient smtp = new SmtpClient(_SMTPServer, _SMTPPort);
            smtp.EnableSsl = _SMTPSSL;

            smtp.Credentials =
                new NetworkCredential(_SMTPUserId, _SMTPPassword);

            smtp.Send(mail);
        }
    }
}

Image 31

Click on the project name in the Solution Explorer, then select Show All Files.

Image 32

This will allow you to see the ServerGenerated project.

This project is created by LightSwitch and used when LightSwitch is deployed as a web application. It is the place where we will eventually place the .aspx files that will generate the HTML pages. For now, we only want to add some entries to the Web.config file:

Image 33

This will allow us to easily change the SMTP Mail Server settings when the application is deployed.

Image 34

Switch back to Logical View.

Image 35

Open the Message table, and select the Messages_Inserted method.

Use the following code for the method (to send the email):

#region Messages_Inserted
partial void Messages_Inserted(Message entity)
{
    string strSubject = "Message From ThingsForSale";

    string strMessage = String.Format("{0}",
        "This is a message From the Things For Sale program.")
        + Environment.NewLine + Environment.NewLine;

    strMessage = strMessage + String.Format("Regarding the post '{0}'",
        entity.Post.Description) + Environment.NewLine;

    strMessage = strMessage + String.Format("This message was sent by {0}",
        entity.NameFrom) + Environment.NewLine + Environment.NewLine;

    strMessage = strMessage + String.Format("Message: {0}",
        entity.MessageText) + Environment.NewLine;

    // Create the MailHelper class created in the Server project.
    MailHelper mailHelper =
        new MailHelper(
            entity.NameFrom,
            entity.EmailTo,
            entity.NameTo,
            strSubject,
            strMessage);

    // Send Email
    mailHelper.SendMail();
}
#endregion

Create the Posts And Messages Screen

Image 36

In the Solution Explorer, right-click on the Screens node and select Add Screen...

Image 37

Create a List and Details Screen.

Note: Because we created relationships between the tables, we can enable Posts and Messages to be on the same screen, by simply checking a box.

Image 38

The screen will show:

Image 39

When you run the application, you will be able to enter Posts and Messages.

Deploy Application into a DotNetNuke Website

Follow the directions here to deploy the application into a DotNetNUke website: Easy DotNetNuke LightSwitch Deployment.

Image 40

We now have the basic layout illustrated above. The LightSwitch application is running in an IFrame and has the same Database Connection, MachineKey, and Forms Cookie, so it is able to communicate with the DotNetNuke site hosting it, and share user authentication.

For many applications, this is enough. In our example, we need to determine if a user is an Administrator or not, because we want to provide additional features to Administrators.

We could simply add the DotNetNuke user and roles tables to the LightSwitch application as external tables, but I have found that this can sometimes cause the user table to lock (see this link for more information).

Image 41

Adding a WCF RIA Service prevents any locking issues.

Creating a WCF RIA Service

(Note: You must have Visual Studio Professional, or higher, to perform the following steps.)

(See this link for official information on creating WCF RIA Services for LightSwitch.)

Image 42

Add a New Project.

Image 43

Create a new Class Library.

Image 44

Right-click on the Class1.cs file that is created and delete it.

Image 45

Add a Entity Data Model...

Image 46

Connect to the DotNetNuke database.

Image 47

Normally, we only need to add the vw_UserRoles view to determine if a user is an Administrator or not.

However, we will also add the Category, Post, and Message tables, because we will also use the Entity Data Model for the .aspx (HTML) pages that we will create in a later step.

Image 48

Build the project.

Image 49

Add a Domain Service Class.

Image 50

We only need the vw_userRoles in the Domain Service Class. Also, un-check Enable client access for added security because we won't need it.

Image 51

The Domain Service Class will be created.

Add [Query(IsDefault = true)] to the top of the method (that is automatically created).

Image 52

Save the file and Build Solution.

Image 53

Right-click on the Data Sources node, and select Add Data Source...

Image 54

Select WCF RIA Service and click Next.

(Do not be surprised if the box goes away and nothing happens for a long time. Also, the box may now be hidden behind the Visual Studio main window.)

Image 55

Click Add Reference.

Image 56

Select the Data Project and click OK.

Image 57

Wait for the Domain Service Class to appear in the list box. Sometimes, it can take 1-2 minutes.

When it appears, select it, and click Next.

Image 58

Select the Entity to use by checking its box (in this case, we want to use the vw_UserRoles).

Don't bother entering anything for the Connection String because we will set it in the Web.config manually.

Click Finish.

Image 59

The data source will show up.

Image 60

Copy the connection string from the App.config of the data project.

Image 61

Switch to File View, and open the Web.config, and add the connection string.

Using the WCF RIA Service

Image 62

To demonstrate how we can use our new WCF RIA Service, open the EditableCategoriesGrid screen and select the EditableCategoriesGrid_CanRun event.

Change the method to the following code:

partial void EditableCategoriesGrid_CanRun(ref bool result)
{
    // Must be an Administrator for this link to show
    var WorkSpace = this.CreateDataWorkspace();

    var UserInRole = (from DNNUser in WorkSpace.DNNDomainServiceData.vw_UserRoles
                      where DNNUser.Username == this.User.Name
                      where DNNUser.RoleName == "Administrators"
                      select DNNUser).FirstOrDefault();

    result = (UserInRole != null);
}

Image 63

Click on the project in the Solution Explorer.

Image 64

This will allow you to select Publish.

Re-publish the application.

You will have to redo all the changes you made to the web.config when you followed the directions described in Easy DotNetNuke LightSwitch Deployment because new things have been added to the web.config when we created the WCF RIA Service.

Image 65

When you run the application in the DotNetNuke website, only an administrator will see the link to edit the Categories.

Enabling Security using a Pre-Process Query

Image 66

One of the requirements is that an administrator can see all Posts, but a non-administrator can only see their own Posts (and Messages).

Open the Posts Entity, and select Posts All PreprocessQuery.

Change the code to the following:

 partial void Posts_All_PreprocessQuery(ref IQueryable<Post> query)
{
    // Only run this PreProcess Query if user is Authenticated
    if (this.Application.User.IsAuthenticated)
    {
        string UserName = this.Application.User.Name;

        // Connect to DotNetNuke Data
        var WorkSpace = this.Application.CreateDataWorkspace();

        var UserInRole = (from DNNUser in WorkSpace.DNNDomainServiceData.vw_UserRoles
                          where DNNUser.Username == UserName
                          where DNNUser.RoleName == "Administrators"
                          select DNNUser).FirstOrDefault();

        // If User is not an Administrator
        // The User can only see their own posts
        if (UserInRole == null)
        {
            query = query.Where(x => x.PostedBy == this.Application.User.Name);
        }
    }
}

Modal Windows (PopUps)

Image 67

Modal Windows (otherwise known as Popups) are an important User Interface tool because they require the user to complete the task set before them before doing anything else.

In this sample application, we want Popups to show when a user is viewing an existing Message or responding to a Message.

There are other Popups, but they are created automatically by LightSwitch.

Image 68

Currently, when an existing Message is opened, it shows all the fields like the image above.

Image 69

We desire the PopUp to resemble the image above.

To do this, we will make our own PopUp and then override the code that opens the current PopUp, to open our PopUp.

Image 70

In the screen designer, select the Details Column, then Add the Selected Item for Messages.

Image 71

It will display.

Image 72

Change the section to a Modal Window.

Image 73

Change all the TextBoxes to Labels and delete the remaining items.

Image 74

Select the Modal Window, and note the name of the window. Uncheck the Show Button box (otherwise LightSwitch would show a button at the bottom of the screen to open the window).

Image 75

Click on the Messages Data Grid, expand the Command Bar, right-click on the Edit button, and select Override Code.

Change the code to the following:

 partial void MessagesEditSelected_Execute()
{
    this.OpenModalWindow("Messages_SelectedItem");
}

Image 76

Now if we select the Edit button, it opens our custom Popup.

We will add a Respond button in the next step, that will allow us to actually create a Message, as a response to a Message entered in the HTML page (to be created in a later step).

Note: To understand the next steps, it is suggested that you read: This Is How LightSwitch Does MVVM.

Image 77

Switch to File View, and add a Reference, in the Client project, to System.Windows.Controls (this is so we can programmatically interact with a PopUp as a ChildWindow).

Image 78

Select Add Data Item...

Image 79

Create a Local Property of type Message and call it Message_Response.

Image 80

It will show on the screen's "View Model" (see: This Is How LightSwitch Does MVVM for an explanation of View Model).

Image 81

Select the Details Column section, and add the Message Response property to the screen.

Image 82

Change it to Modal Window.

Image 83

The properties will show.

Image 84

  • Remove all the controls except the Name To, Email To, and Message Text
  • Change the Name To to a Label
  • In the Properties of the Modal Window, uncheck Show Button

Image 85

Add a Button to the Command Bar of the Modal Window and call it SaveResponse.

Image 86

In the Properties for the Button, change the Display Name to Save Message.

Image 87

Right-click on the Button, and select Edit Execute Code.

Change the code to:

 #region SaveResponse_Execute
partial void SaveResponse_Execute()
{
    this.CloseModalWindow("Message_Response");
    this.Save();
}
#endregion

Image 88

Navigate up the object tree to the Command Bar for the Messages Data Grid, and delete the Add button, and add a New Button.

Image 89

Call it RespondToMessage.

Image 90

Drag it to the top of the other two remaining buttons, and right-click on it and select Edit Execute Code.

Use the following code to create a new Message and open the Popup, also to detect when the PopUp is closed (when clicking the x in the upper right corner of the Popup), and to remove any unsaved Messages:

 #region RespondToMessage_Execute
partial void RespondToMessage_Execute()
{
    // Create a new Message
    Message_Response = new Message();

    //Set the Post
    Message_Response.Post = Posts.SelectedItem;

    // Set Email defaults
    Message_Response.MessageBy = this.Application.User.Name;

    // these values are from the currently selected Message
    Message_Response.NameFrom = Messages.SelectedItem.NameTo;
    Message_Response.EmailFrom = Messages.SelectedItem.EmailTo;
    Message_Response.NameTo = Messages.SelectedItem.NameFrom;
    Message_Response.EmailTo = Messages.SelectedItem.EmailFrom;

    this.OpenModalWindow("Message_Response");

    // Wire up an event to detect when the Modal window is closed
    this.FindControl("Message_Response").ControlAvailable +=
        new EventHandler<ControlAvailableEventArgs>(PostsListDetail_ControlAvailable);
}
#endregion

#region PostsListDetail_ControlAvailable
void PostsListDetail_ControlAvailable(object sender, ControlAvailableEventArgs e)
{
    ChildWindow window = (ChildWindow)e.Control;
    window.Closed += new EventHandler(Message_Response_Closed);
}
#endregion

#region Message_Response_Closed
void Message_Response_Closed(object sender, EventArgs e)
{
    ChildWindow window = (ChildWindow)sender;
    if (!(window.DialogResult.HasValue))
    {
        // Remove unsaved records
        foreach (Message message in
                 this.DataWorkspace.ApplicationData.Details.GetChanges()
            .AddedEntities.OfType<Message>())
        {
            message.Details.DiscardChanges();
        }
    }
}
#endregion

Image 91

You will also need to add using System.Windows.Controls; to the top of the class.

Creating HTML Pages

Image 92

Switch to File View.

Add a Reference to System.configuration to the ServerGenerated project.

Image 93

Add an .aspx page called PublicPage.aspx, and use the following code for the code behind (please get the HTML code from the download):

using DNNData;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text.RegularExpressions;
using System.Transactions;
using System.Web.UI;
using System.Web.UI.WebControls;
using LightSwitchApplication;

namespace ApplicationData.Implementation
{
    public partial class PublicPage : System.Web.UI.Page
    {
        #region CurrentPage
        public int CurrentPage
        {
            get
            {
                if (ViewState["CurrentPage"] == null)
                {
                    return 1;
                }
                else
                {
                    return (int)ViewState["CurrentPage"];
                }
            }
            set
            {
                ViewState["CurrentPage"] = value;
            }
        }
        #endregion

        #region CurrentPostID
        public int CurrentPostID
        {
            get
            {
                if (ViewState["CurrentPostID"] == null)
                {
                    return -1;
                }
                else
                {
                    return (int)ViewState["CurrentPostID"];
                }
            }
            set
            {
                ViewState["CurrentPostID"] = value;
            }
        }
        #endregion

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                GetPosts(true, CurrentPage);
            }
        }

        #region GetPosts
        private void GetPosts(bool FillCategories, int intPage)
        {
            // Collections to hold the final results
            List<DNNData.Category> lstCategories = new List<DNNData.Category>();

            // Connect to DotNetNuke Data
            string _IntrinsicData = Convert.ToString
                  (ConfigurationManager.ConnectionStrings["DotNetNuke5Entities"]);
            DotNetNuke5Entities db = new DotNetNuke5Entities(_IntrinsicData);

            int intCategoryID = -1;

            // Get selected category
            if (!FillCategories)
            {
                intCategoryID = Convert.ToInt32(ddlCategories.SelectedValue);
            }

            if (FillCategories)
            {
                // execute query
                var colCatagories = (from Cat in db.Categories
                                     select Cat).ToList();

                // Add an All option
                DNNData.Category objCategory = new DNNData.Category();
                objCategory.Id = -1;
                objCategory.CategoryName = "All";
                lstCategories.Add(objCategory);

                // Add Categories
                foreach (var item in colCatagories)
                {
                    lstCategories.Add(item);
                }

                // We now have the results - bind then to the dropdown
                ddlCategories.DataSource = lstCategories;
                ddlCategories.DataBind();
            }

            // Get Posts

            // create query
            var colPosts = from PST in db.Posts
                           select PST;

            // Get active posts
            colPosts = colPosts.Where(x => x.Active == true);

            // Get Category
            if (intCategoryID != -1)
            {
                colPosts = colPosts.Where(x => x.Category.Id == intCategoryID);
            }

            // Do paging
            colPosts =
                colPosts.OrderByDescending(x => x.PostUpdated).
                Skip(((intPage - 1) * 10)).Take(10);

            // We now have the results - bind then to the dropdown
            gvPosts.DataSource = colPosts;
            gvPosts.DataBind();

        }
        #endregion

        #region ddlCategories_SelectedIndexChanged
        protected void ddlCategories_SelectedIndexChanged(object sender, EventArgs e)
        {
            pnlMessage.Visible = false;
            GetPosts(false, CurrentPage);
        }
        #endregion

        #region btnLeft_Click
        protected void btnLeft_Click(object sender, EventArgs e)
        {
            pnlMessage.Visible = false;

            if (CurrentPage > 1)
            {
                CurrentPage--;
            }

            GetPosts(false, CurrentPage);
        }
        #endregion

        #region btnRight_Click
        protected void btnRight_Click(object sender, EventArgs e)
        {
            pnlMessage.Visible = false;

            if (gvPosts.Rows.Count > 0)
            {
                CurrentPage++;
            }

            GetPosts(false, CurrentPage);
        }
        #endregion

        #region gvPosts_RowCommand
        protected void gvPosts_RowCommand(object sender, GridViewCommandEventArgs e)
        {
            LinkButton lnkButtton = (LinkButton)e.CommandSource;
            CurrentPostID = Convert.ToInt32(lnkButtton.CommandArgument);

            pnlMessage.Visible = true;
        }
        #endregion

        #region btnSubmit_Click
        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            try
            {
                Transaction currentTrx = Transaction.Current;
                Transaction.Current = null;

                // Validate
                if (!IsValidEmail(txtEmail.Text))
                {
                    lblError.Text = "Must use a valid Email";
                    return;
                }

                if (txtEmail.Text.Count() < 1)
                {
                    lblError.Text = "Must enter a message";
                    return;
                }

                if (txtEmail.Text.Count() > 255)
                {
                    lblError.Text = "Message must be less than 255 characters";
                    return;
                }

                // Connect to DotNetNuke Data
                string _IntrinsicData = Convert.ToString
                       (ConfigurationManager.ConnectionStrings["DotNetNuke5Entities"]);
                DotNetNuke5Entities db = new DotNetNuke5Entities(_IntrinsicData);

                // Get the information for the user who made the Post
                var DNNUser = (from PST in db.Posts
                               from vw_Users in db.vw_UserRoles
                               where PST.PostedBy == vw_Users.Username
                               where PST.Id == CurrentPostID
                               select vw_Users).FirstOrDefault();

                // Create New Message
                DNNData.Message NewMessage = new DNNData.Message();

                NewMessage.NameFrom = txtName.Text;
                NewMessage.EmailFrom = txtEmail.Text;
                NewMessage.NameTo = DNNUser.DisplayName;
                NewMessage.EmailTo = DNNUser.Email;
                NewMessage.MessageText = txtMessage.Text;
                NewMessage.MessageCreated = DateTime.UtcNow;
                NewMessage.Message_Post = CurrentPostID;

                db.AddToMessages(NewMessage);
                db.SaveChanges();

                // Get the information for the Post
                var PostInfo = (from PST in db.Posts
                                where PST.Id == CurrentPostID
                                select PST).FirstOrDefault();

                // Send Email

                string strSubject = "Message From ThingsForSale";

                string strMessage = String.Format("{0}",
                    "This is a message From the Things For Sale program.")
                    + Environment.NewLine + Environment.NewLine;

                strMessage = strMessage + String.Format("Regarding the post '{0}'",
                    PostInfo.Description) + Environment.NewLine;

                strMessage = strMessage + String.Format("This message was sent by {0}",
                    txtName.Text) + Environment.NewLine + Environment.NewLine;

                strMessage = strMessage + String.Format("Message: {0}",
                    txtMessage.Text) + Environment.NewLine;

                // Create the MailHelper class created in the Server project.
                MailHelper mailHelper =
                    new MailHelper(
                        txtName.Text,
                        DNNUser.Email,
                        DNNUser.DisplayName,
                        strSubject,
                        strMessage);

                // Send Email
                mailHelper.SendMail();


                lblError.Text = "Success";

                // Clear fields
                txtMessage.Text = "";
            }
            catch (Exception ex)
            {
                lblError.Text = ex.Message;
            }
        }
        #endregion

        #region IsValidEmail
        public static bool IsValidEmail(string strIn)
        {
            // Return true if strIn is in valid e-mail format.
            // From: http://msdn.microsoft.com/en-us/library/01escwtf.aspx
            return Regex.IsMatch(strIn,
                   @"^(?("")("".+?""@)|(([0-9a-zA-Z]((\.(?!\.))|
                   [-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-zA-Z])@))" +
                   @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*
                   [0-9a-zA-Z]\.)+[a-zA-Z]{2,6}))$");
        }
        #endregion
    }
}

Creating a Link to the HTML Page in LightSwitch

Image 94

Add a Reference, in the Client project, to System.Windows.Browser.

Image 95

Switch to Logical View.

Add Screen...

Image 96

Add a New Data Screen called PublicPage with no Screen Data selected.

Image 97

Select the PublicPage_Run method.

Change it to the following code:

partial void PublicPage_Run(ref bool handled)
{
    // Set handled to 'true' to stop further processing.
    Dispatchers.Main.Invoke(() =>
    {
        HtmlPage.Window.Navigate(new Uri("PublicPage.aspx", UriKind.Relative));
    });

    handled = true;
}

You will also need to add the following using statements to the class:

using Microsoft.LightSwitch.Threading;
using System.Windows.Browser;

We now need to add the PublicPage.aspx to the build file, so that LightSwitch will include it in the build.

Note: You will want to back up your entire solution before performing the following steps:

Image 98

Switch to File View, right-click on the LightSwitch project and select Unload Project.

Image 99

Right-click on the unloaded project and select Edit.

Image 100

Add the following to the bottom of the _buildFile section:

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

Image 101

Reload the project.

Image 102

Now you can run the project and click on the Public Page link...

Image 103

... and navigate to the HTML page.

In your application, you will want to make the HTML page available for your unauthenticated users.

The live demonstration on the LightSwitchHelpWebsite, has one IFrame that is pointed directly at the PublicPage.aspx, and is only shown to un-authenticated users. A second IFrame, enabled only for Registered users, shows the normal LightSwitch application.

Finishing Touches

Image 104

On the Posts screen, delete Posted By because it is set programmatically.

Image 105

However, notice that it still shows up on the automatically created PopUp.

Image 106

Open the Post Entity, and select the PostedBy field, then un-check the Display by Default box.

Image 107

The PopUp will no longer show the field.

Image 108

On the Posts screen, set the Message Data Grid to Use Read-only Controls.

Image 109

Select the CanExecute Code for the Respond To Message button.

Change the code to the following:

#region RespondToMessage_CanExecute
partial void RespondToMessage_CanExecute(ref bool result)
{
    // Must have a Message Selected
    result = (Messages.SelectedItem != null);
}
#endregion

Do the same for the Message Edit button.

This causes the buttons to be disabled if there is no Message selected.

Image 110

Go into Properties for the project, set the Post List Detail screen as the startup screen.

An Advanced LightSwitch Application

This demonstrates an advanced LightSwitch application. However, there is still a lot more to LightSwitch. For example, the entire UI can be controlled using Silverlight Custom Controls.

There are a ton of tutorials, tips, blogs, and forums at:

Image 111

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here