You are here:   Blog
Register   |  Login

 

Jul 6

Written by: Michael Washington
7/6/2012 3:00 PM  RssIcon

image

Visual Studio LightSwitch provides the fastest and easiest way to create Line-Of-Business, Forms-Over-Data applications. Previously LightSwitch produced only Silverlight applications. Now with LightSwitch in Visual Studio 2012, LightSwitch now allows you to communicate with its security and business layer through OData. There is an announced LightSwitch HTML Client currently in preview, but that uses JQuery Mobile, and therefore is targeted toward mobile devices such as tablets and cell phones. When one desires a full screen desktop HTML interface such as a DotNetNuke module, OData provides the necessary communication.

What Is OData?

OData is a protocol used to expose and consume data over the web. It uses a common REST-like (representational state transfer) interface to communicate, rather than the usual pre-defined application specific interfaces used by traditional web services. OData is a project created by Microsoft. The home page for the project is at: http://www.odata.org.

As described in the article: LightSwitch Architecture: OData (John Rivard) (http://blogs.msdn.com/b/lightswitch/archive/2012/03/22/lightswitch-architecture-odata.aspx), OData allows CRUD (Create, Read, Update, Delete) operations. This allows you to have full data interaction when you use OData. In addition, OData provides a mechanism to query the data.

The Application

image

Basic CRUD functionality is demonstrated in the example application. It allows you to create new call records in the form at the bottom, and they display them in the grid at the top. You can update and delete the items in the grid (note: OData does support paging, but that was not implemented in this example).

image

LightSwitch has many features that allow you to easily implement business rules, security rules, and business types. In this example, the Phone Number business type, is set for the PhoneNumber field in the PhoneCall table in LightSwitch.

image

Without the need to write a single line of code, the business type is enforced when calling the LightSwitch application through OData from DotNetNuke.

The Previous Application

image

We start with the application created in the article: Easy DotNetNuke LightSwitch Deployment.

image

This article describes the steps needed to point the LightSwitch application to the DotNetNuke database and security when you publish it.

image

However, it produces a Silverlight application that runs in an IFrame in a DotNetNuke site. This actually provides the best user interface as far as performance, but when you must have an HTML page you can create one using OData.

Creating The DotNetNuke OData Service Reference

When you create an OData module using server side code, you need to create a service reference, and that creates a proxy class that you use to communicate with the OData service. In a non-DotNetNuke project you would simply add the service reference. With a DotNetNuke module, you need to add the service reference in an external project so that it creates an assembly (a .dll) that you can package with the module when you move your code from development to production.

To create a DotNetNuke module, you need to set up your DotNetNuke development environment. Use any method you are comfortable with. We are using the latest DotNetNuke 6 for this example, but here are some articles I created for DotNetNuke 4 and 5 that I still use:

Note: for questions on developing DotNetNuke modules, see the following forums: http://www.dotnetnuke.com/Resources/Forums/GroupID/92.aspx.

image

In order for DotNetNuke to call LightSwitch, you need the ASP.NET OData libraries. You should have OData installed on your machine if you have the latest service pacs, otherwise you can get it from here: http://msdn.microsoft.com/en-us/data/ee720179.

image.

Open your DotNetNuke development site in Visual Studio 2010. If Visual Studio asks to upgrade the Target Framework to ASP.NET 4.0 say no. A DotNetNuke site should only be upgraded to ASP.NET 4.0 using the method described here: http://www.dotnetnuke.com/Resources/Blogs/EntryId/2619/Upgrading-DotNetNuke-to-ASP-NET-4-0.aspx (note: at the time of that post OData did not exist for ASP.NET 4.0. We will use ASP.NET 3.5 in this tutorial, but it will also work for any higher version).

image

Add a new project to the Solution.

image

Add a new Class Library.

image

Delete the Class1.cs file that is created.

image

In the Properties for the project, set the Framework to 3.5.

image

Select Add Reference.

image

Add a reference to System.Web.

image

Add a Service Reference.

image

The address to the LightSwitch OData service is the web address plus ApplicationData.svc (see Learn How To Make OData Calls In LightSwitch 2011).

image

We enter that web address in the Address box in the Service Reference dialog.

image

When the authentication box pops up click Yes.

image

Because we have forms authentication enabled in the LightSwitch application, it requires us to enter a user name and password that is able to access the service. Because we have the LightSwitch applications Web.config file configured to use the DotNetNuke site for authentication, we simply use a valid account from the DotNetNuke site.

Note: The authentication boxes will pop up again. You need to repeat the process twice.

image

The service will be discovered and show in the Services box. Enter a Namespace and click OK.

image

The service will be created.

image

Add a new class file to the project.

Use the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Services.Client;
using System.Net;
using System.Threading;
using System.IO;
using System.Security;
using System.Web;
using Microsoft.VisualBasic;
using System.Web.Security;
namespace CallLogOData.wsCallLogOData
{
    public partial class ApplicationData
    {
        partial void OnContextCreated()
        {
            this.SendingRequest +=
               new EventHandler<SendingRequestEventArgs>(OnSendingRequest);
        }
        void OnSendingRequest(object sender, SendingRequestEventArgs e)
        {
            // Get the Forms auth cookie
            var AuthCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
            if (AuthCookie != null)
            {
                Cookie objCookie = new Cookie();
                objCookie.Domain = HttpContext.Current.Request.Url.DnsSafeHost;
                objCookie.Expires = AuthCookie.Expires;
                objCookie.HttpOnly = AuthCookie.HttpOnly;
                objCookie.Name = AuthCookie.Name;
                objCookie.Path = AuthCookie.Path;
                objCookie.Secure = AuthCookie.Secure;
                objCookie.Value = AuthCookie.Value;
                ((HttpWebRequest)e.Request).CookieContainer = new CookieContainer();
                ((HttpWebRequest)e.Request).CookieContainer.Add(objCookie);
            }
        }
    }
}

 

This is a partial class that will get the authentication cookie that the user gets when they log into DotNetNuke. The code creates and passes an authentication cookie on each OData call. This is done because the cookie type that OData understands is not the cookie type that the web browsers use (see: Calling LightSwitch 2011 OData Using Server Side Code).

 

image

Add a reference in the DotNetNuke project.

image

Add the reference to the OData proxy project.

The DotNetNuke module, to be created in the next step, will call this proxy to communicate with LightSwitch.

image

Also, add a reference in the DotNetNuke project to System.Data.Services.Client.

Note: This puts an entry in the web.config for “System.Data.Services.Client”. You would need to place that entry in the web.config of any other DotNetNuke site you need to use with OData.

Creating The DotNetNuke Module

image

Run your DotNetNuke site, and open it in a web browser.

log in as the Host account, and from the Host menu, select Extensions.

image

Hover over the Manage box and select Create New Module.

image

Select New.

image

Add a Module Folder.

image

Name it CallLog.

image

Fill in the remaining fields and click Create Module.

 

image

A page will be created and the module will show on the page.

image

In Visual Studio, refresh the DesktopModules folder.

image

We need code behind for the View.ascx file, so delete the one created by the DotNetNuke wizard.

image

Add New Item to the CallLog folder.

image

Add a new Web User Control called View.ascx.

image

Paste the following code in the View.ascx file:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="View.ascx.cs" Inherits="DesktopModules_CallLog_View" %>
<style type="text/css">
    .style1
    {
        font-weight: normal;
    }
</style>
<asp:DataList ID="dlPhoneCalls" runat="server" GridLines="Both">
    <HeaderTemplate>
    &nbsp;</td><td>
        <strong>Description</strong> </td>
        <td>
            <strong>Person Calling</strong>
        </td>
        <td>
            <strong>Phone Number</strong>
        </td>
        <td>
            <strong>Call Type</strong>
    </HeaderTemplate>
    <ItemTemplate>
    <asp:Button ID="btnDelete" runat="server" Text="Delete" 
            CommandArgument='<%# Eval("Id") %>' onclick="btnDelete_Click" />    
            <asp:Button ID="btnUpdate" runat="server" onclick="btnUpdate_Click" 
                Text="Update"  CommandArgument='<%# Eval("Id") %>'/>
                </td><td>
        <asp:TextBox ID="Description" runat="server" Text='<%# Eval("Description") %>' />
        </td>
        <td>
            <asp:TextBox ID="PersonCalling" runat="server" Text='<%# Eval("PersonCalling") %>' />
        </td>
        <td>
            <asp:TextBox ID="PhoneNumber" runat="server" Text='<%# Eval("PhoneNumber") %>' />
        </td>
        <td>
            <asp:Label ID="lblCallType" runat="server" Text='<%# Eval("CallType") %>' Visible="False" />
            <asp:DropDownList ID="ddlGridCallType" runat="server" 
                ondatabound="ddlCallType_DataBound">
                <asp:ListItem>Sales</asp:ListItem>
                <asp:ListItem>Service</asp:ListItem>
                <asp:ListItem>Other</asp:ListItem>
            </asp:DropDownList>
    </ItemTemplate>
</asp:DataList>
<p>
    &nbsp;</p>
<h2 class="style1">
    Insert New:</h2>
<table>
    <tr>
        <td align="right">
            <strong>Description</strong>
        </td>
        <td>
            <asp:TextBox ID="txtDescription" runat="server"></asp:TextBox>
        </td>
    </tr>
    <tr>
        <td align="right">
            <strong>Person Calling</strong>
        </td>
        <td>
            <asp:TextBox ID="txtPersonCalling" runat="server"></asp:TextBox>
        </td>
    </tr>
    <tr>
        <td align="right">
            <strong>Phone Number</strong>
        </td>
        <td>
            <asp:TextBox ID="txtPhoneNumber" runat="server"></asp:TextBox>
        </td>
    </tr>
    <tr>
        <td align="right">
            <strong>Call Type</strong>
        </td>
        <td>
            <asp:DropDownList ID="ddlCallType" runat="server">
                <asp:ListItem>Sales</asp:ListItem>
                <asp:ListItem>Service</asp:ListItem>
                <asp:ListItem>Other</asp:ListItem>
            </asp:DropDownList>
        </td>
    </tr>
    <tr>
        <td align="right">
            &nbsp;
        </td>
        <td align="right">
            <asp:Button ID="btnSubmit" runat="server" OnClick="btnSubmit_Click" Text="Submit" />
        </td>
    </tr>
</table>
<asp:Label ID="lblError" runat="server" EnableViewState="False" ForeColor="Red"></asp:Label>

image

 

Paste the following code in the View.ascx.cs file:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Linq;
using System.IO;
public partial class DesktopModules_CallLog_View : 
    DotNetNuke.Entities.Modules.PortalModuleBase
{
    // Url of the LightSwitch OData service
    string strURL = @"http://localhost/CallLogDNN62/applicationdata.svc/";
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            // Must be logged in to make the OData call to LightSwitch
            // because LightSwitch has forms authentication enabled
            if (this.UserId > -1)
            {
                RefreshGrid();
            }
        }
    }
    // Utility
    #region ShowError(Exception ex)
    private void ShowError(Exception ex)
    {
        // see: http://msdn.microsoft.com/en-us/magazine/hh580732.aspx
        if (ex.InnerException != null)
        {
            // This is a complex error 
            var sr = new StringReader(ex.InnerException.Message);
            using (sr)
            {
                XElement root = XElement.Load(sr);
                IEnumerable<XElement> message =
                    from el in root.Elements()
                    where el.Name.LocalName == "message"
                    select el;
                foreach (XElement el in message)
                {
                    // Check for validation error from LightSwitch		
                    int intErrorStartPosition = el.Value.IndexOf(@"<ValidationResult>");
                    if (intErrorStartPosition > 0)
                    {
                        // Get the inner exception message
                        int intStartPosition = el.Value.IndexOf(@"<Message>", intErrorStartPosition);
                        int intEndPosition = el.Value.IndexOf(@"</Message>", intErrorStartPosition);
                        intStartPosition = intStartPosition + 9;
                        // Get the error 
                        string ErrorMessage = el.Value.Substring(intStartPosition, 
                            (intEndPosition - (intStartPosition)));
                        // Display tee error
                        lblError.Text = String.Format(@"{0}<br />", ErrorMessage);
                    }
                }
            }
            sr.Close();
        }
        else
        {
            // This is a simple error -- just show Message
            lblError.Text = String.Format(@"{0}", ex.Message);
        }
    }
    #endregion
}

 

Display Data

To display data use the following method:

 

    private void RefreshGrid()
    {
        // Create DataContext
        CallLogOData.wsCallLogOData.ApplicationData objApplicationData =
            new CallLogOData.wsCallLogOData.ApplicationData(new Uri(strURL));
        var result = from PhoneCalls in objApplicationData.PhoneCalls
                     select PhoneCalls;
        dlPhoneCalls.DataSource = result;
        dlPhoneCalls.DataBind();
    }

 

Also, to set the dropdown in each row to the proper value, use the following code:

 

    protected void ddlCallType_DataBound(object sender, EventArgs e)
    {
        // Get an instance of the DropDownList
        DropDownList objDropDownList = (DropDownList)sender;
        // Get the selected value from the hidden Label
        Label objLabel = (Label)objDropDownList.Parent.FindControl("lblCallType");
        // Set the selected value in the DropDownList
        objDropDownList.SelectedValue = objLabel.Text;
    }

 

Insert Data

To insert data, use the following code:

 

    protected void btnSubmit_Click(object sender, EventArgs e)
    {
        // Create DataContext
        CallLogOData.wsCallLogOData.ApplicationData objApplicationData =
            new CallLogOData.wsCallLogOData.ApplicationData(new Uri(strURL));
        try
        {
            // Create a new PhoneCall
            CallLogOData.wsCallLogOData.PhoneCall objPhoneCall =
                new CallLogOData.wsCallLogOData.PhoneCall();
            // Set values
            objPhoneCall.CallType = ddlCallType.SelectedValue;
            objPhoneCall.Description = txtDescription.Text;
            objPhoneCall.PersonCalling = txtPersonCalling.Text;
            objPhoneCall.PhoneNumber = txtPhoneNumber.Text;
            objPhoneCall.MessageTakenBy = UserInfo.Username;
            // Add new PhoneCall
            objApplicationData.AddToPhoneCalls(objPhoneCall);
            // Save changes
            objApplicationData.SaveChanges(
                System.Data.Services.Client.SaveChangesOptions.Batch);
            // Refresh the Grid
            RefreshGrid();
        }
        catch (Exception ex)
        {
            ShowError(ex);
            return;
        }
    }

 

Update Data

To update data, use the following code:

 

    protected void btnUpdate_Click(object sender, EventArgs e)
    {
        // Get an instance of the Button
        Button UpdateButton = (Button)sender;
        // Get the ID of the current record from the CommandArgument
        int intID = Convert.ToInt32(UpdateButton.CommandArgument);
        // Create DataContext
        CallLogOData.wsCallLogOData.ApplicationData objApplicationData =
            new CallLogOData.wsCallLogOData.ApplicationData(new Uri(strURL));
        try
        {
            // Get the record
            var result = (from PhoneCalls in objApplicationData.PhoneCalls
                          where PhoneCalls.Id == intID
                          select PhoneCalls).FirstOrDefault();
            if (result != null)
            {
                // Get the values
                TextBox Description = 
                    (TextBox)UpdateButton.Parent.FindControl("Description");
                TextBox PersonCalling = 
                    (TextBox)UpdateButton.Parent.FindControl("PersonCalling");
                TextBox PhoneNumber = 
                    (TextBox)UpdateButton.Parent.FindControl("PhoneNumber");
                DropDownList ddlGridCallType = 
                    (DropDownList)UpdateButton.Parent.FindControl("ddlGridCallType");
                // Update the record
                result.Description = Description.Text;
                result.PersonCalling = PersonCalling.Text;
                result.PhoneNumber = PhoneNumber.Text;
                result.CallType = ddlGridCallType.SelectedValue;
                objApplicationData.UpdateObject(result);
                // Save changes
                objApplicationData.SaveChanges(
                    System.Data.Services.Client.SaveChangesOptions.Batch);
                // Refresh the Grid
                RefreshGrid();
            }
        }
        catch (Exception ex)
        {
            ShowError(ex);
            return;
        }
    }

 

Delete Data

To delete data, use the following method:

 

    protected void btnDelete_Click(object sender, EventArgs e)
    {
        // Get an instance of the Button
        Button DeleteButton = (Button)sender;
        // Get the ID of the current record from the CommandArgument
        int intID = Convert.ToInt32(DeleteButton.CommandArgument);
        // Create DataContext
        CallLogOData.wsCallLogOData.ApplicationData objApplicationData =
            new CallLogOData.wsCallLogOData.ApplicationData(new Uri(strURL));
        try
        {
            // Get the record
            var result = (from PhoneCalls in objApplicationData.PhoneCalls
                          where PhoneCalls.Id == intID
                          select PhoneCalls).FirstOrDefault();
            if (result != null)
            {
                // Delete the record
                objApplicationData.DeleteObject(result);
                // Save changes
                objApplicationData.SaveChanges(
                    System.Data.Services.Client.SaveChangesOptions.Batch);
                // Refresh the Grid
                RefreshGrid();
            }
        }
        catch (Exception ex)
        {
            ShowError(ex);
            return;
        }
    }

 

Also See

DotNetNuke articles on LightSwitchHelpWebsite.com:

Easy DotNetNuke LightSwitch Deployment

Deploy Your LightSwitch Application As A DotNetNuke Module

Quick And Easy Data Management With LightSwitch

 

OData articles on LightSwitchHelpWebsite.com:

Shape Your LightSwitch OData Using WCF RIA Services

A Full CRUD LightSwitch JQuery Mobile Application

Calling LightSwitch 2011 OData Using Server Side Code

Using The OData Explorer with LightSwitch OData

Learn How To Make OData Calls In LightSwitch 2011

A LightSwitch Netflix OData Mash-up

 

Books

image

 

Download Code

The LightSwitch project is available at:

http://lightswitchhelpwebsite.com/Downloads.aspx

2 comment(s) so far...


Gravatar

Re: A DotNetNuke HTML Module Calling Visual Studio LightSwitch Using OData

Is this demo running on-line anywhere?

By tlanier on   8/22/2012 1:48 AM
Gravatar

Re: A DotNetNuke HTML Module Calling Visual Studio LightSwitch Using OData

@tlanier - Sorry no.

By Michael Washington on   8/22/2012 4:19 AM

Your name:
Gravatar Preview
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
CAPTCHA image
Enter the code shown above in the box below
Add Comment   Cancel 
Microsoft Visual Studio is a registered trademark of Microsoft Corporation / LightSwitch is a registered trademark of Microsoft Corporation