May
4
Written by:
Michael Washington
5/4/2013 10:29 AM
The primary reason you may want to use WCF RIA Services with Visual Studio LightSwitch is to:
- Combine more than one entity into a single entity.
- Eliminate unneeded columns in an entity to improve performance (otherwise large amounts of data, for example pictures, will be transmitted even when they are not shown).
- Implement calculated fields that allow the resulting values to be searchable and sortable.
Also, the LightSwitch OData services return one Entity collection at a time. This makes grouping and totaling across Entity collections difficult. Using WCF RIA Services provides a clean elegant solution.
The official documentation from Microsoft on creating WCF RIA Services is available at this link.
WCF RIA Services have been covered previously on this site. This article reflects the latest changes in Visual Studio 2012 update 2.
The Sample Application
In the Flower Shop application used in the tutorial: Calling LightSwitch 2011 OData Using Server Side Code we have computed fields in the FlowerShopOrder Entity.
This allows us to easily display the Order Total.
However, if we connect to the OData service for that Entity, we see it does not contain the Order Total.
To get this data, it requires additional queries of the Product Entity to get the Product price, and all the related Order Detail Entities to calculate the Order Total.
This is a problem because not only does it require additional database queries, it requires the client consuming the OData feed to now be responsible for complex business logic.
We can create an OData service with these computed fields using a WCF RIA Service.
Create A WCF RIA Service
First, Add a New Project to the existing LightSwitch project.
Create a .NET Framework 4 Class Library called WCF_RIA_Project.
Delete the Class1.cs file that is automatically created.
Add a New Item to WCF_RIA_Project.
Add a Domain Service Class called WCF_RIA_Service.cs.
When the Add New Domain Service Class box comes up, uncheck Enable client access. Click OK.
This domain class will be exposed by LightSwitch and will pass through its security and business rules.
We need additional references, add the following references to the WCF_RIA_Project…
- System.ComponentModel.DataAnnotations
- System.Configuration
- System.Data.Entity
- System.Runtime.Serialization
- System.ServiceModel.DomainServices.Server (Look in %ProgramFiles%\Microsoft SDKs\RIA Services\v1.0\Libraries\Server)
- System.Web
Add the following Using Statements to the class:
using System.Data.EntityClient;
using System.Web.Configuration;
using LightSwitchApplication.Implementation;
(LightSwitchApplication will display with a squiggly red line because the class is missing, but it will be added in the next step)
Reference The LightSwitch Object Context
Now, we will add code from the LightSwitch project to our WCF RIA Service project. We will add a class that LightSwitch automatically creates, that connects to the database that LightSwitch uses.
We will use this class in our WCF RIA Service to communicate with the LightSwitch database.
Right-click on the WCF_RIA_Project and select Add then Existing Item.
Navigate to ..Server\GeneratedArtifacts (in the LightSwitch project)and click on ApplicationDataObjectContext.cs and Add As Link.
We used “add As Link” so that whenever LightSwitch updates this class, our WCF RIA Service is also updated. This is how our WCF RIA Service would be able to see any new Entities (tables) that were added, deleted, or changed.
The file will show in the project.
Create the Domain Service
Replace the entire code for the WCF_RIA_Service.cs file with the following:
namespace WCF_RIA_Project
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
using System.Data.EntityClient;
using System.Web.Configuration;
using LightSwitchApplication.Implementation;
// This class is used as the class that is returned
// This can have any 'shape' you desire
// Make sure this is outside of the WCF_RIA_Service class
// but inside the WCF_RIA_Project namespace
public class EnhancedFlowerShopOrder
{
[Key]
public int ID { get; set; }
public DateTime OrderDate { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public decimal OrderTotal { get; set; }
}
public class WCF_RIA_Service : DomainService
{
// This Context property is code that connects to the LightSwitch database
// The code in the Database connection region can be reused as it is
#region Database connection
private ApplicationData m_context;
public ApplicationData Context
{
get
{
if (this.m_context == null)
{
string connString =
System.Web.Configuration.WebConfigurationManager
.ConnectionStrings["_IntrinsicData"].ConnectionString;
EntityConnectionStringBuilder builder = new EntityConnectionStringBuilder();
builder.Metadata =
"res://*/ApplicationData.csdl|res://*/ApplicationData.ssdl|res://*/ApplicationData.msl";
builder.Provider =
"System.Data.SqlClient";
builder.ProviderConnectionString = connString;
this.m_context = new ApplicationData(builder.ConnectionString);
}
return this.m_context;
}
}
#endregion
[Query(IsDefault = true)]
public IQueryable<EnhancedFlowerShopOrder> GetAllOrders()
{
// Get all the Orders
var colFlowerShopOrders = from Order in this.Context.FlowerShopOrders
// Shape the results into the
// EnhancedFlowerShopOrder class
select new EnhancedFlowerShopOrder
{
// The Order ID
ID = Order.Id,
// The Order Date
OrderDate = Order.OrderDate,
// The first name of the Customer
FirstName = Order.FlowerShopCustomer.FirstName,
// The last name of the Customer
LastName = Order.FlowerShopCustomer.LastName,
// The order Total
OrderTotal =
// Get all order details lines of the Order
(from FlowerShopOrderDetail in Order.FlowerShopOrderDetail
// Group the products in the Order Details
group FlowerShopOrderDetail
by FlowerShopOrderDetail.Id into g
// Shape a new entity
select new
{
// Create a total property that is the Quantity times the
// Product price
TotalOrder = g.Sum(x => x.Quantity)
* g.Sum(x => x.FlowerShopProduct.Price),
}).Sum(x => x.TotalOrder) // Add the sum of all the TotalOrders
};
return colFlowerShopOrders;
}
// Override the Count method in order for paging to work correctly
protected override int Count<T>(IQueryable<T> query)
{
return query.Count();
}
}
}
Consume The WCF RIA Service
Build the solution.
(You will get a ton or warnings in the immediate window, you can ignore them)
In the Solution Explorer (of the LightSwitch project), right-click on the Data Sources folder and select Add Data Source.
Select WCF RIA Service and click Next.
Click Add Reference.
Select Solution, then Projects, then check the box next to the WCF_RIA_Project.
Click OK.
Wait for the service to show up in the selection box, select it and click Next.
Check the box next to the Entities, and click Finish.
The Entity will display.
We can now add the collection to a screen as we would any other collection.
All the values are searchable and sortable.
WCF RIA Services Can Read, Update, Insert, and Delete
See the article: WCF RIA Service: Combining Two Tables for an example.
Download Code
The LightSwitch project is available at http://lightswitchhelpwebsite.com/Downloads.aspx
(you must have Visual Studio 2012 Update 2 installed to run the code)
23 comment(s) so far...
Thanks again for a great sample Michael. I have been searching for a way to call a Stored Procedure (to get records, not do an update) for a complex set of data in Lightswitch and your article is a more detailed step by step of some others I had been trying to follow without success.
I have gotten through most of your sample, and applied it to my project, but I am stuck at the line below: public IQueryable GetAllOrders() I have a default query that returns all records called GetOpenOrders() and my line reads: public IQueryable GetAllOrders() and I am getting build errors about TrackingStatusOrders not being found in my project. My understanding (guess really) is that TrackingStatusOrders is an IQueryable class that is created for GetOpenOrders() to be loaded into by the code that follows that creates the collection of orders and assigns it to the class. Am I missing something? Do you have a class called EnhancedFlowerShopOrder that I do not see, or is it in the data sources? When searching for info on IQueryable, I am just flooded with results, and I am hoping you can clear that up, since I do not see reference to EnhancedFlowerShopOrder in the project before this line. Thanks again for the wonderful work you are doing with Beth and the MS team.
By Dan Gleason on
5/6/2013 1:47 PM
|
@Dan Gleason - I do have a class called "EnhancedFlowerShopOrder" (it is there in my code) and you need to create a class like it as the class that is returned by your IQueryable.
By Michael Washington on
5/6/2013 1:49 PM
|
Howdy! Thanks for the article! I was wondering if it's possible to access Lightswitch's membership from this. I'd like to create an interface for managing users since each user A) has custom data associated with them in a custom table and B) has relationships to other data in lightswitch.
By Richard Simpson on
5/9/2013 9:07 PM
|
@Richard Simpson - It should be possible but I have no code examples.
By Michael Washington on
5/9/2013 9:07 PM
|
Thanks! Just one question. Why you're using a "Class Library" project instead of using directly a "WCF Ria Service Library" ?
By Pablo on
5/10/2013 10:37 AM
|
@Pablo - When I tried that in the past it did not work for me.
By Michael Washington on
5/10/2013 10:37 AM
|
Michael - thanks for all the great posts over the past couple years. I've used them extensively in my exploration of Lightswitch.
Stupid question: why can't I create a domain service class inside the Lightswitch server project? I'm sure there's a good reason for it, but it seems like it would make everything much easier.
Thanks Jay
By Jay Turpin on
5/29/2013 10:37 AM
|
@Jay Turpin - In the past LightSwitch would not see it there. However, I have not tried that in years.
By Michael Washington on
5/29/2013 10:37 AM
|
@JohnMarsing - Please download the code and compare it to your own.
By Michael Washington on
5/30/2013 8:31 PM
|
I see what the problem is, my LS app was not an HTML client project.
I also see how I can do this with the article you mentioned above "WCF RIA Service: Combining Two Tables" where you need to use the ApplicationData.cs file.
By JohnMarsing on
5/31/2013 2:03 PM
|
@JohnMarsing - Thank you for following up.
By Michael Washington on
5/31/2013 2:15 PM
|
Michael,
Nice article. Question about using RIA to expose a database updatable view...in order to have searchable\sortable 'computed properties'
If the database did the aggregations\calculations in the view T-SQL rather than in the RIA code, would that mean that lightswitch would not recalculate on screens automatically? In other words, after updating quantity or price, in order to display calculations on browse screen, extra code would be required to update the collection and refresh the screen. Is that correct?
By joshBooker on
6/4/2013 10:21 AM
|
@joshBooker - When you refresh the collection you would get the updated calculations just as you would any other field. The key is that you would have to have code to do the refresh.
By Michael Washington on
6/4/2013 10:23 AM
|
Thanks Michael...just to be clear...the extra refresh code is not required when calculations are done in RIA code as in your example since lightswitch 'understands' the linq query on the client-side, correct? As a db guy, I'm more comfortable with t-sql. Since RIA is necessary to easily join tables and make computations sort/seachable, I'm trying to understand the pros and cons of putting aggregates in db vs. RIA. Thanks again.
By joshBooker on
6/4/2013 12:41 PM
|
@joshBooker - It's not really a calculation, it is just another field in the Entity that happens to represent the result of a calculation. A "real calculated field" would update the calculation without requiring you to save the Entity first. With all that said, it is the same if you use a T-SQL View or a WCF RIA Service.
By Michael Washington on
6/4/2013 12:44 PM
|
Hi, Michael. I'm in the middle of creating a WCF RIA Services based lightswitch project. I've created the domain service class. The input datas come from a WCF service (don't ask...). The WCF RIA Service is working just fine, I could make the datasource, and a screen as well. When I want to start the application, during the loading i get this error: "The maximum message size quota for incoming messages (65536) has been exceeded. To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element." I figured out that the amount of my input data is hight, but where could I set the maximum message size quota? I tried in the lightswitch client side ServiceReferences.Client.Config file, or the web.config file with no luck... Thanks
By AdM on
7/10/2013 4:19 AM
|
@Adm - I don't know. I have never had that error before. Make a post in the LightSwitch forums: http://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=lightswitch
By Michael Washington on
7/10/2013 4:20 AM
|
I followed your instructions, however when I went to consume the WCF RIA service, it did not display the classes that I built. I investigated some more and realized that the RIA service needs to point to the .NET 4.0, mine was set to 4.5. You can change the framework in the properties of the RIA class.
Thanks for your help in this. This will really help with my efforts to integrate more/better data in to HTML screens, eliminate code and table space, and make reporting easier as I integrate with Office.
Thanks!
By Louis Garcia on
7/11/2013 4:29 AM
|
Hi Michael. Congratulations for the great work you're doing in supporting LightSwitch community. When I debug my application, my screen with the RIA data shows nothing, only a cross red square, and says as a description, that it can not read any data and that I must verify my network connection. Can you help me with this
By Joao Silva on
7/20/2013 7:00 AM
|
@Joao Silva- I can't tell what the problem is. If my sample works for you, compare the code in the WCF RIA Service to your own. Also ensure you are using asp.net 4.0 not asp.net 4.5. If it still doesn't work post the contents of your WCF RIA Service to the official LightSwitch forums at: http://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=lightswitch
By Michael Washington on
7/20/2013 9:00 AM
|
@Joao Silva- I must insist that you follow my wishes and post to the official LightSwitch forums at: http://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=lightswitch
By Michael Washington on
7/22/2013 8:25 AM
|
Thank you this was Exactly what i Searched for...
By Lenine prasad on
1/3/2014 4:45 AM
|
I made the same mistake as Louis Garcia when following the older instruction on combining tables. You just have to recreate the RIA project and this time select 4.0 not 4.5 at the top of the screen when naming the project before you click ok.
I also used the combining tables example to create a combined products table to use in a one to many relationship with Orders and am passing data to Orders from Customer as well and then have a List and details screen based on Customer with a child entity of Orders so when you select a Customer it shows all of the Orders. Additionally I used the a Un-Required field on Orders with a choice list for Time which you can select after being auto forwarded to List and Details Screen once a New Order is saved. It is a model I will need to implement if I want to have a list of products I keep Up to Date (defaults) and a List my Clients can Keep Up to Date (custom) I even have some code to concatenate the strings " (custom)" to the Internal Products and " (default)" to my External Products. Finally I have code to make the code to make a default for which Combined Product to show but instead of showing this default product I found it actually shows nothing which is even better for my future scenario that way when a combined product is not selected for the order it does not show a line of code like it was before I set up a default = this.dataworkspace.applicationdata.QueryMethodName() . --My code discussion can be found at this link https://social.msdn.microsoft.com/Forums/vstudio/en-US/d6d32ed1-9033-49b0-a14e-082c55dad297/trouble-consuming-ria-service-example?forum=lightswitch#df9ad9da-683e-4992-a6df-adff0dd7dfd6 --My RIA expiriment project can be found at http://www.healthsonictools.com/RIASample.zip
By Jordan on
3/6/2015 12:18 PM
|