Apr
10
Written by:
Michael Washington
4/10/2012 9:33 PM
Visual Studio LightSwitch (In Visual Studio 11 Beta) allows you to access your LightSwitch application via OData. This provides access to the security and business rules of your LightSwitch application.
This article is a continuation of the article: Calling LightSwitch 2011 OData Using Server Side Code. In that article only reading the OData source was covered. In this article we will cover Creating, Reading, Updating, and Deleting (otherwise known as CRUD). We will also use JQuery Mobile and target the sample application to work with mobile devices. This is done only so that we can create a small application to easily present the relevant CRUD operations.
The Application
When the LightSwitch application runs, navigate to MobileMenu.aspx page and you will be presented with a login menu.
Note: If using Internet Explorer 9 in “compatibility mode” the login won’t work so turn it off for testing. I did not detect any problems with any mobile devices.
If a user is an Administrator they will see all Orders, otherwise they will only see (and be able to edit) their own orders.
| |
Clicking on an Order displays the details. To remove an item, set the Quantity to 0 and click Save. | Clicking the Delete button allows an Order to be deleted. A non-administrator will not be able to delete an Order (this is by design). |
| |
Clicking on the dropdown at the bottom of the Order details table allows you to choose a Product to add. | Entering a Quantity and clicking Save adds the Product to the Order. |
The validation, including the messages, are generated by LightSwitch. Error codes are also returned if you need to craft more user friendly validation errors.
The Business Layer
The only difference in the LightSwitch code between this example and the one in: Calling LightSwitch 2011 OData Using Server Side Code is that the CanDelete methods were implemented on the FlowerShopOrder and FlowerShopOrderDetails entities to prevent any non Administrator from deleting:
partial void FlowerShopOrders_CanDelete(ref bool result)
{
result = this.Application.User.HasPermission(Permissions.SecurityAdministration);
}
partial void FlowerShopOrderDetails_CanDelete(ref bool result)
{
result = this.Application.User.HasPermission(Permissions.SecurityAdministration);
}
The ASP.NET Web Pages
The remainder of the application is in the ASP.NET web pages that we can access in the File View.
All the pages are contained in the Server / Mobile folder.
The Android.aspx page was covered in the article: Communicating With LightSwitch Using Android App Inventor.
The OrderEdit.aspx page was added for this tutorial, and the existing Login.aspx page and MobileMenu.aspx pages were altered for this tutorial.
The Login Page
The Login.aspx page was altered to the following code to implement the JQuery Mobile framework that optimizes the page for mobile devices:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="LightSwitchApplication.Login" %>
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
<title>Mobile Login</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" />
<script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
<script src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>
</head>
<body>
<form id="form1" runat="server">
<div data-role="page" class="type-interior">
<div data-role="header" data-theme="b">
<h1>Mobile Menu</h1>
</div>
<!-- /header -->
<div data-role="content">
<asp:login runat="server" id="ctrlLogin" onauthenticate="ctrlLogin_Authenticate">
<LayoutTemplate>
<table border="0" cellpadding="1" cellspacing="0"
style="border-collapse:collapse;" width="100%">
<tr>
<td>
<table border="0" cellpadding="0" width="100%">
<tr>
<td data-role="fieldcontain">
<asp:Label ID="UserNameLabel" runat="server"
AssociatedControlID="UserName">User Name:</asp:Label>
<asp:TextBox ID="UserName" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="UserNameRequired" runat="server"
ControlToValidate="UserName" ErrorMessage="User Name is required."
ToolTip="User Name is required."
ValidationGroup="MainLogin">*</asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td data-role="fieldcontain">
<asp:Label ID="PasswordLabel" runat="server"
AssociatedControlID="Password">Password:</asp:Label>
<asp:TextBox ID="Password" runat="server" TextMode="Password"></asp:TextBox>
<asp:RequiredFieldValidator ID="PasswordRequired" runat="server"
ControlToValidate="Password" ErrorMessage="Password is required."
ToolTip="Password is required."
ValidationGroup="MainLogin">*</asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td>
<asp:CheckBox ID="RememberMe" runat="server" Text="Remember me next time." />
</td>
</tr>
<tr>
<td align="left" style="color:Red;">
<asp:Literal ID="FailureText" runat="server" EnableViewState="False"></asp:Literal>
</td>
</tr>
<tr>
<td align="left" data-role="fieldcontain">
<asp:Button ID="LoginButton" runat="server" CommandName="Login" Text="Log In"
ValidationGroup="MainLogin" data-ajax="false" data-icon="star" data-theme="b" />
<a data-ajax="false" data-icon="star" data-role="button" href="MobileMenu.aspx">
Cancel</a> </td>
</tr>
<tr>
<td align="left">
</td>
</tr>
</table>
</td>
</tr>
</table>
</LayoutTemplate>
</asp:login>
</div>
<!-- /content -->
</div>
<!-- /page -->
</form>
</body>
</html>
This is the code behind in Login.aspx.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace LightSwitchApplication
{
public partial class Login : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// When a user first comes to this page log them out
if (this.Request.QueryString["logoff"] != null)
{
if (this.Request.QueryString["logoff"] == "true")
{
FormsAuthentication.SignOut();
}
}
}
protected void ctrlLogin_Authenticate(object sender, AuthenticateEventArgs e)
{
if (Membership.ValidateUser(ctrlLogin.UserName, ctrlLogin.Password))
{
// Set the forms authentication cookie that will be used in the OData requests
FormsAuthentication.SetAuthCookie(ctrlLogin.UserName, true);
e.Authenticated = true;
Response.Redirect("~/MobileMenu.aspx");
}
else
{
e.Authenticated = false;
ctrlLogin.FailureText = "Login failed";
}
}
}
}
Mobile Menu Page
The MobileMenu.aspx page was altered to the following code:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="MobileMenu.aspx.cs"
Inherits="LightSwitchApplication.Mobile.MobileMenu" %>
<!DOCTYPE html>
<html>
<head>
<title>Orders</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" />
<script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
<script src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>
</head>
<body>
<form id="form1" runat="server">
<div data-role="page" class="type-interior">
<div data-role="header" data-theme="b">
<h1>Orders</h1>
</div>
<!-- /header -->
<div data-role="content">
<asp:datalist class="content-primary" id="gvOrders" style="width: 100%" runat="server">
<ItemTemplate>
<ul data-role="listview" data-inset="true" data-theme="c">
<li><a data-ajax="false" href='<%# Eval("HyperLink") %>'>
<h3><asp:Label runat="server" Text='<%# Eval("OrderName") %>' /></h3>
<p><strong><asp:Label runat="server" Text='<%# Eval("OrderDate") %>' /></strong></p>
</a></li>
</ul>
</ItemTemplate>
</asp:datalist>
<br />
<asp:hyperlink id="lnkLogOff" runat="server" navigateurl="~/Login.aspx?logoff=true"
data-role="button" data-ajax="false" data-icon="star" data-theme="b" text="Log Off" />
</div>
<!-- /content -->
</div>
<!-- /page -->
</form>
</body>
</html>
The MobileMenu.aspx.cs page was altered to the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.VisualBasic;
namespace LightSwitchApplication.Mobile
{
public partial class MobileMenu : System.Web.UI.Page
{
#region BaseSiteUrl
public static string BaseSiteUrl
{
get
{
HttpContext context = HttpContext.Current;
string baseUrl = context.Request.Url.Scheme
+ "://"
+ context.Request.Url.Authority
+ context.Request.ApplicationPath.TrimEnd('/') + '/';
return baseUrl;
}
}
#endregion
protected void Page_Load(object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated) // Logged in
{
ShowOrders();
}
else // Not Logged In
{
Response.Redirect("~/Login.aspx");
}
}
#region ShowOrders
private void ShowOrders()
{
// Create DataContext
ODataServiceReference.ApplicationData objApplicationData =
new ODataServiceReference.ApplicationData(
new Uri(string.Format(@"{0}applicationdata.svc/", BaseSiteUrl)));
// Query OData source
var result = from FlowerShopOrders in objApplicationData.FlowerShopOrders
.Expand(x => x.FlowerShopCustomer)
.Expand(x => x.FlowerShopOrderDetail)
select FlowerShopOrders;
// Collection to hold Orders
List<OrderInfo> colOrderInfo = new List<OrderInfo>();
// Loop thru orders
foreach (var item in result)
{
// Get the Order Total
double dblOrderTotal = 0.00d;
// Create a new DataContext
ODataServiceReference.ApplicationData objApplicationData2 =
new ODataServiceReference.ApplicationData(
new Uri(string.Format(@"{0}applicationdata.svc/", BaseSiteUrl)));
// Query OData source
var objOrderDetails = from OrderDetails in objApplicationData2.FlowerShopOrderDetails
.Expand(x => x.FlowerShopProduct)
where OrderDetails.FlowerShopOrder.Id == item.Id
select OrderDetails;
// Loop thru order details to get order total
foreach (var OrderDetail in objOrderDetails)
{
dblOrderTotal = dblOrderTotal
+ Convert.ToDouble((OrderDetail.FlowerShopProduct.Price * OrderDetail.Quantity));
}
// Create new Order object
OrderInfo objOrderInfo = new OrderInfo();
objOrderInfo.OrderID = item.Id;
objOrderInfo.OrderName =
String.Format("[{0}] {1}, {2} - ${3}",
item.Id,
item.FlowerShopCustomer.LastName,
item.FlowerShopCustomer.FirstName,
dblOrderTotal);
objOrderInfo.OrderDate = item.OrderDate;
objOrderInfo.HyperLink = String.Format(@"OrderEdit.aspx?Id={0}", item.Id);
// Add the order object to the final collection
colOrderInfo.Add(objOrderInfo);
}
// Bind entire collection to GridView
gvOrders.DataSource = colOrderInfo;
gvOrders.DataBind();
}
#endregion
#region OrderInfo
public class OrderInfo
{
int _OrderID;
public int OrderID
{
get { return _OrderID; }
set { _OrderID = value; }
}
string _OrderName;
public string OrderName
{
get { return _OrderName; }
set { _OrderName = value; }
}
DateTime _OrderDate;
public DateTime OrderDate
{
get { return _OrderDate; }
set { _OrderDate = value; }
}
string _HyperLink;
public string HyperLink
{
get { return _HyperLink; }
set { _HyperLink = value; }
}
}
#endregion
}
}
The Order Edit Page
The OrderEdit.aspx page displays a single order, allows Order Detail items to be added, and for Orders to be deleted.
This is the code for the OrderEdit.aspx page:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="OrderEdit.aspx.cs"
Inherits="LightSwitchApplication.Mobile.OrderEdit" %>
<!DOCTYPE html>
<html>
<head>
<title>Order Details</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" />
<script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
<script src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>
<style type="text/css">
table
{
width: 100%;
}
table caption
{
text-align: center;
}
table thead th
{
text-align: left;
border-bottom-width: 1px;
border-top-width: 1px;
}
table th, td
{
text-align: center;
padding: 6px;
}
ul
{
width: 100%;
margin-left: 0px;
padding: 0px;
}
ul li
{
list-style-type: none;
border-bottom: 1px dashed gray;
margin-top: 10px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div data-role="page" class="type-interior">
<div data-role="header" data-theme="b">
<h1>
<asp:label id="lblOrderHeader" runat="server" />
</h1>
</div>
<!-- /header -->
<div data-role="content">
<asp:gridview id="gvOrderDetails" runat="server" autogeneratecolumns="False"
datakeynames="Id" horizontalalign="Center" data-role="fieldcontain"
ShowFooter="True">
<Columns>
<asp:TemplateField HeaderText="Product" ItemStyle-HorizontalAlign="Left">
<FooterTemplate>
<asp:DropDownList ID="dllProducts" runat="server" data-native-menu="false" />
</FooterTemplate>
<ItemTemplate>
<asp:Label ID="lblId" runat="server" Text='<%# Bind("Id") %>' Visible="False" />
<asp:Label ID="lblProduct" runat="server" Text='<%# Bind("Product") %>' />
</ItemTemplate>
<HeaderStyle HorizontalAlign="Center" />
<ItemStyle HorizontalAlign="Left" Width="90%" />
</asp:TemplateField>
<asp:TemplateField HeaderText="Quantity" ItemStyle-HorizontalAlign="Center">
<FooterTemplate>
<asp:TextBox ID="txtInsertQuantity" runat="server" Columns="2" data-mini="true"
MaxLength="3" style="text-align: center" Text='<%# Bind("Quantity") %>'
type="number" Width="40px" />
</FooterTemplate>
<ItemTemplate>
<asp:TextBox ID="txtQuantity" runat="server" Text='<%# Bind("Quantity") %>'
Columns="2" data-mini="true" MaxLength="3" Width="40px" type="number"
style="text-align: center" />
</ItemTemplate>
<HeaderStyle HorizontalAlign="Center" />
<ItemStyle HorizontalAlign="Center" />
</asp:TemplateField>
</Columns>
<EmptyDataTemplate>
No records found
</EmptyDataTemplate>
</asp:gridview>
<asp:Label ID="lblError" runat="server" ForeColor="Red"
ViewStateMode="Disabled"></asp:Label>
<br />
<asp:Button ID="btnSave" runat="server" Text="Save" data-icon="gear"
data-role="button" data-ajax="false" data-theme="e" OnClick="btnSave_Click" />
<asp:Button ID="btnDelete" runat="server" Text="Delete" data-icon="delete"
data-role="button" data-ajax="false" data-theme="a"
OnClientClick='if (!confirm("Are you sure you want to delete?") ){return false;}'
OnClick="btnDelete_Click" />
<asp:hyperlink id="lnkMainMenu" runat="server" navigateurl="~/MobileMenu.aspx" data-role="button"
data-ajax="false" data-icon="star" data-theme="b" text="Main Menu" />
</div>
<!-- /content -->
</div>
<!-- /page -->
</form>
</body>
</html>
This is the code behind:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Linq;
namespace LightSwitchApplication.Mobile
{
public partial class OrderEdit : System.Web.UI.Page
{
#region BaseSiteUrl
public static string BaseSiteUrl
{
get
{
HttpContext context = HttpContext.Current;
string baseUrl = context.Request.Url.Scheme
+ "://"
+ context.Request.Url.Authority
+ context.Request.ApplicationPath.TrimEnd('/') + '/';
return baseUrl;
}
}
#endregion
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
// Display Order Details
LoadOrder();
// Populate the dropdown
PopulateProducts();
}
}
#region PopulateProducts
private void PopulateProducts()
{
if (gvOrderDetails.FooterRow != null)
{
// Create DataContext
ODataServiceReference.ApplicationData objApplicationData =
new ODataServiceReference.ApplicationData(
new Uri(string.Format(@"{0}applicationdata.svc/", BaseSiteUrl)));
// Query OData source
var colFlowerShopProducts = from FlowerShopProducts in objApplicationData.FlowerShopProducts
select FlowerShopProducts;
// Get an instance of the Dropdown
DropDownList dllProducts = (DropDownList)gvOrderDetails.FooterRow.FindControl("dllProducts");
// Bind items to Dropdown
dllProducts.Items.Clear();
dllProducts.DataSource = colFlowerShopProducts;
dllProducts.DataValueField = "Id";
dllProducts.DataTextField = "ProductName";
dllProducts.Attributes.Add("data-overlay-theme", "b");
dllProducts.DataBind();
// Create default entry to top of Dropdown
var objListItem = new ListItem("[Select a Product]", "0");
objListItem.Attributes.Add("data-placeholder", "true");
dllProducts.Items.Insert(0, objListItem);
dllProducts.Items.FindByText("[Select a Product]").Selected = true;
// Add JQuery Mobile attribute to items in Dropdown
for (int i = 0; i < dllProducts.Items.Count; i++)
{
dllProducts.Items[i].Attributes.Add("title", dllProducts.Items[i].Text);
}
}
}
#endregion
#region LoadOrder
private void LoadOrder()
{
if (this.Request.QueryString["Id"] != null)
{
// Load the order based on the Id passed
LoadOrder(Convert.ToInt32(this.Request.QueryString["Id"]));
}
}
#endregion
#region LoadOrder(int Id)
private void LoadOrder(int Id)
{
// Create DataContext
ODataServiceReference.ApplicationData objApplicationData =
new ODataServiceReference.ApplicationData(
new Uri(string.Format(@"{0}applicationdata.svc/", BaseSiteUrl)));
// Collection to hold Order Details
var OrderDetailsInfo = new List<OrderDetailsInfo>();
// Value to hold Order Total
double dblOrderTotal = 0.00d;
// Query OData source
var objOrderDetails = from OrderDetails in objApplicationData.FlowerShopOrderDetails
.Expand(x => x.FlowerShopProduct)
where OrderDetails.FlowerShopOrder.Id == Id
select OrderDetails;
foreach (var item in objOrderDetails)
{
// Create OrderDetails object
OrderDetailsInfo NewOrderDetailsInfo = new OrderDetailsInfo();
// Set values
NewOrderDetailsInfo.Id = item.Id;
NewOrderDetailsInfo.Product = item.FlowerShopProduct.ProductName;
NewOrderDetailsInfo.Quantity = item.Quantity;
// Add Order Detail to final collection
OrderDetailsInfo.Add(NewOrderDetailsInfo);
// Update order total
dblOrderTotal = dblOrderTotal +
Convert.ToDouble((item.FlowerShopProduct.Price * item.Quantity));
}
// Bind collection to Grid
gvOrderDetails.DataSource = OrderDetailsInfo;
gvOrderDetails.DataBind();
// Display the total
lblOrderHeader.Text = String.Format("Total: $ {0}", dblOrderTotal);
}
#endregion
#region btnSave_Click
protected void btnSave_Click(object sender, EventArgs e)
{
try
{
// Get OrderID
int intId = Convert.ToInt32(this.Request.QueryString["Id"]);
// Create DataContext
ODataServiceReference.ApplicationData objApplicationData =
new ODataServiceReference.ApplicationData(
new Uri(string.Format(@"{0}applicationdata.svc/", BaseSiteUrl)));
#region Existing Order Details
// Loop thru the Orders in the Grid
var DataObject = gvOrderDetails.DataSourceObject;
for (int i = 0; i < gvOrderDetails.Rows.Count; i++)
{
// Get an instance of the Label and the TextBox
Label lblId = (Label)gvOrderDetails.Rows[i].Cells[0].FindControl("lblId");
TextBox txtQuantity = (TextBox)gvOrderDetails.Rows[i].Cells[0].FindControl("txtQuantity");
// Convert the Label and the TextBox to values
int intOrderDetailId = Convert.ToInt32(lblId.Text);
int intQuantity = Convert.ToInt32(txtQuantity.Text);
// Query OData source
var objOrderDetail = (from OrderDetails in objApplicationData.FlowerShopOrderDetails
.Expand(x => x.FlowerShopProduct)
where OrderDetails.Id == intOrderDetailId
select OrderDetails).FirstOrDefault();
if (objOrderDetail != null)
{
// If Quantity is set to zero delete the Product entry
if (intQuantity == 0)
{
objApplicationData.DeleteObject(objOrderDetail);
}
else // Update the Product entry
{
objOrderDetail.Quantity = intQuantity;
objApplicationData.UpdateObject(objOrderDetail);
}
}
}
#endregion
#region New Order Details
// Get an instance of the Dropdown
DropDownList dllProducts = (DropDownList)gvOrderDetails.FooterRow.FindControl("dllProducts");
TextBox txtInsertQuantity = (TextBox)gvOrderDetails.FooterRow.FindControl("txtInsertQuantity");
// Convert the Label and the TextBox to values
string strProduct = dllProducts.SelectedItem.Text;
int intProduct = Convert.ToInt32(dllProducts.SelectedValue);
int intInsertQuantity = 0;
// Only try an insert if txtInsertQuantity is an integer
if (int.TryParse(txtInsertQuantity.Text, out intInsertQuantity))
{
if (intProduct != 0 && intInsertQuantity > 0)
{
// Create a new FlowerShopOrderDetail
LightSwitchApplication.ODataServiceReference.FlowerShopOrderDetail objFlowerShopOrderDetail =
new LightSwitchApplication.ODataServiceReference.FlowerShopOrderDetail();
// Set values
objFlowerShopOrderDetail.OrderDetail_Order = intId;
objFlowerShopOrderDetail.OrderDetail_Product = intProduct;
objFlowerShopOrderDetail.Quantity = intInsertQuantity;
// Add new FlowerShopOrderDetail
objApplicationData.AddToFlowerShopOrderDetails(objFlowerShopOrderDetail);
}
}
#endregion
// Save all changes as a single Batch call
objApplicationData.SaveChanges(System.Data.Services.Client.SaveChangesOptions.Batch);
// Go To Main Menu
Server.Transfer("MobileMenu.aspx");
}
catch (Exception ex)
{
ShowError(ex);
return;
}
}
#endregion
#region btnDelete_Click
protected void btnDelete_Click(object sender, EventArgs e)
{
if (this.Request.QueryString["Id"] != null)
{
try
{
// Load the order based on the Id passed
int intId = Convert.ToInt32(this.Request.QueryString["Id"]);
// Create DataContext
ODataServiceReference.ApplicationData objApplicationData =
new ODataServiceReference.ApplicationData(
new Uri(string.Format(@"{0}applicationdata.svc/", BaseSiteUrl)));
// Get all the Order details
var colOrderDetails = from OrderDetails in objApplicationData.FlowerShopOrderDetails
.Expand(x => x.FlowerShopOrder)
where OrderDetails.FlowerShopOrder.Id == intId
select OrderDetails;
foreach (var item in colOrderDetails)
{
// Delete the Order detail item
objApplicationData.DeleteObject(item);
}
objApplicationData.SaveChanges(System.Data.Services.Client.SaveChangesOptions.Batch);
// Get the Order
var objOrder = (from FlowerShopOrders in objApplicationData.FlowerShopOrders
where FlowerShopOrders.Id == intId
select FlowerShopOrders).FirstOrDefault();
if (objOrder != null)
{
// Delete the Order detail item
objApplicationData.DeleteObject(objOrder);
objApplicationData.SaveChanges(System.Data.Services.Client.SaveChangesOptions.Batch);
}
// Return to Main Menu
Server.Transfer("MobileMenu.aspx");
}
catch (Exception ex)
{
ShowError(ex);
}
}
}
#endregion
// 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)
{
lblError.Text = String.Format(@"{0}<br />", el.Value);
}
}
sr.Close();
}
else
{
// This is a simple error -- just show Message
lblError.Text = String.Format(@"{0}", ex.Message);
}
}
#endregion
#region OrderDetailsInfo
public class OrderDetailsInfo
{
int _Id;
public int Id
{
get { return _Id; }
set { _Id = value; }
}
string _Product;
public string Product
{
get { return _Product; }
set { _Product = value; }
}
int _Quantity;
public int Quantity
{
get { return _Quantity; }
set { _Quantity = value; }
}
}
#endregion
}
}
Still… Use The Silverlight Screens When You Can
Silverlight is not “dead”. In fact it provides the best, most efficient user experience.
Also note, It took a full day to write the ASP.NET/JQuery code, and two full days to debug it, while the LightSwitch code that creates the Silverlight user interface was created in less than 15 minutes.
Also See
Calling LightSwitch 2011 OData Using Server Side Code
Communicating With LightSwitch Using Android App Inventor
Learn How To Make OData Calls In LightSwitch 2011
Accessing Your Visual Studio 2011 LightSwitch Application Using OData
Consume a LightSwitch OData Service from a Windows Phone application
Download Code
The LightSwitch project is available at:
http://lightswitchhelpwebsite.com/Downloads.aspx
12 comment(s) so far...
Well thank you very much!!
How the heck am I supposed to concentrate at my day job now; knowing that I can do all this. I need to focus... FOCUS I tell you ...bah, forget it, I just got to try it now.
One of my favourite articles to date Michael!
Cheers,
Paul
By Paul Patterson on
4/11/2012 6:40 AM
|
Awesome!
By DotNetLore on
4/11/2012 6:45 AM
|
@Paul Patterson & @DotNetLore - Thank you for the feedback, it is appreciated.
By Michael Washington on
4/11/2012 7:46 AM
|
Hi Michael, it means that I can use this application with IOS devices?
By lolavar on
5/2/2012 2:10 AM
|
@lolavar - Yes.
By Michael Washington on
5/2/2012 4:43 AM
|
Hey Michael,
Thank you for example. I noticed that whenever you do a Server.Transfer or Response.Redirect from the C# code the page tranfers correctly but the URL is not correct. Example would be when you login instead of http://localhost:16978/MobileMenu.aspx showing in the URL we get http://localhost:16978/login.aspx#/login.aspx. Another example is when you edit an order and go back to the order list instead of http://localhost:17234/MobileMenu.aspx showing in the URL we get http://localhost:17234/OrderEdit.aspx?Id=1#/OrderEdit.aspx?Id=1. This would create problems if user hits refresh. Any idea what is causing this? Thanks for any help.
By David Moss on
6/13/2012 8:23 AM
|
@David Moss - I used Server.Transfer to work around other jQuery Mobile issue I was having. The fact that the URL is not changed on a Server.Transfer is an unfortunate thing.
By Michael Washington on
6/13/2012 8:30 AM
|
Should the "Remember Me" checkbox on the Login.aspx page be working? Username does not seem to be remembered.
Thanks
By David Moss on
10/22/2012 11:25 AM
|
@David Moss - It works for me. Perhaps your cookies are disabled.
By Michael Washington on
10/22/2012 11:30 AM
|
Cookies are enabled on clients. Could it be a server setting in the web.config? Also doesn't work when running with Test User on localhost. Thanks
By David Moss on
10/22/2012 12:07 PM
|
Maybe I'm not understanding the "remember me" functionality. Should it be remembering the "User Name" the next time the login.aspx form is browsed?
By David Moss on
10/22/2012 12:13 PM
|
@David Moss - I just tested and it is not working for me. I was mistaken.
By Michael Washington on
10/22/2012 3:10 PM
|