[UPDATED – SEE EntitySpaces, Silverlight, and WCF a Fantastic Combination FOR OUR NEW AND FAR SUPERIOR APPROACH]
Besides the enhancements mentioned in the DynamicQuery Enhancements post, this release addresses some important issues discovered in our previous alpha concerning Silverlight and WCF. You should uninstall the prior alpha before upgrading. Our Silverlight assembly is now named EntitySpaces.DynamicQuery.Silverlight.dll. There is, also, a new class called esDataContractSerializer (available in the .NET 3.5 assemblies) that can be used in any WCF or Silverlight application. Take a look at the code sample below which demonstrates an entire conversation from Server to Client and back to the Server again. Using this approach all of your methods would use strings to send data to and receive data from the server. Of course, you can use the auto generated proxy classes created by Visual Studio but the nice thing about this approach is that the row-state of all of the data is maintained automatically and then saving becomes trivial.
public void TestCollection(){ EmployeesCollection coll = new EmployeesCollection(); coll.Query.SelectAllExcept(coll.Query.Photo); coll.Query.es.Top = 3; if (coll.Query.Load()) { // Create Our Server Side Proxy Stub BusinessObjects.EmployeesCollectionProxyStub server = new BusinessObjects.EmployeesCollectionProxyStub(coll); // Serialize it into a XML string and return this string to our Silverlight or WCF Client string xml = esDataContractSerializer.ToXml(server); // Deserialize the string above into our Client Side Proxy under Silverlight or our WCF Client Proxies.EmployeesCollectionProxyStub client = esDataContractSerializer.FromXml(xml, typeof(Proxies.EmployeesCollectionProxyStub)) as Proxies.EmployeesCollectionProxyStub; // Set a property and notice that esRowState goes to Modified client.Collection[0].LastName = "Squarepants"; // Serialize our Client Side Proxy into xml and send it back to the server xml = esDataContractSerializer.ToXml(client); // Deserialize it on the server back into a Server Side Proxy Stub, the esRowState is modifed as we would expect BusinessObjects.EmployeesCollectionProxyStub server1 = esDataContractSerializer.FromXml(xml, typeof(BusinessObjects.EmployeesCollectionProxyStub)) as BusinessObjects.EmployeesCollectionProxyStub; // Now save the Entity server1.GetCollection().Save(); }}
public void TestCollection(){ EmployeesCollection coll = new EmployeesCollection(); coll.Query.SelectAllExcept(coll.Query.Photo); coll.Query.es.Top = 3; if (coll.Query.Load()) { // Create Our Server Side Proxy Stub BusinessObjects.EmployeesCollectionProxyStub server = new BusinessObjects.EmployeesCollectionProxyStub(coll);
// Serialize it into a XML string and return this string to our Silverlight or WCF Client string xml = esDataContractSerializer.ToXml(server);
// Deserialize the string above into our Client Side Proxy under Silverlight or our WCF Client Proxies.EmployeesCollectionProxyStub client = esDataContractSerializer.FromXml(xml, typeof(Proxies.EmployeesCollectionProxyStub)) as Proxies.EmployeesCollectionProxyStub;
// Set a property and notice that esRowState goes to Modified client.Collection[0].LastName = "Squarepants";
// Serialize our Client Side Proxy into xml and send it back to the server xml = esDataContractSerializer.ToXml(client);
// Deserialize it on the server back into a Server Side Proxy Stub, the esRowState is modifed as we would expect BusinessObjects.EmployeesCollectionProxyStub server1 = esDataContractSerializer.FromXml(xml, typeof(BusinessObjects.EmployeesCollectionProxyStub)) as BusinessObjects.EmployeesCollectionProxyStub;
// Now save the Entity server1.GetCollection().Save(); }}
You can also use this same approach with the single entity based proxies. For example, the EmployeeProxyStub class.
The PopulateEmployees() method below is the method that populates the grid in our soon to be released Silverlight demo. The method executes under Silverlight after the user types in his search criteria and hit’s the Search button. Notice that the query classes (both proxy and full server) contain their own ToXml / FromXml methods. This is because when we serialize and deserialize queries we are doing so for complex object graphs with circular references. This is more complex than what our esDataContractSerializer class is designed for.
private void PopulateEmployees(){ try { NorthwindClient.NorthwindClient service = new NorthwindClient.NorthwindClient(); Proxies.EmployeesQueryProxyStub q = new Proxies.EmployeesQueryProxyStub("emp"); q.Select(q.EmployeeID, q.FirstName, q.LastName, q.Title, q.HomePhone, q.HireDate, q.BirthDate); q.Where( q.FirstName.Like("%" + SearchTextBox.Text + "%") | q.LastName.Like("%" + SearchTextBox.Text + "%")); q.OrderBy(q.LastName.Ascending); q.es.Top = 5; // Notice we send the XML representation of the Query to the Server via the Async call “GetEmployees” service.GetEmployeesCompleted += GetEmployeesCompleted; service.GetEmployeesAsync(Proxies.EmployeesQueryProxyStub.SerializeHelper.ToXml(q)); } catch (Exception exc) { Console.WriteLine(exc.StackTrace); }}
private void PopulateEmployees(){ try { NorthwindClient.NorthwindClient service = new NorthwindClient.NorthwindClient();
Proxies.EmployeesQueryProxyStub q = new Proxies.EmployeesQueryProxyStub("emp"); q.Select(q.EmployeeID, q.FirstName, q.LastName, q.Title, q.HomePhone, q.HireDate, q.BirthDate); q.Where( q.FirstName.Like("%" + SearchTextBox.Text + "%") | q.LastName.Like("%" + SearchTextBox.Text + "%")); q.OrderBy(q.LastName.Ascending); q.es.Top = 5;
// Notice we send the XML representation of the Query to the Server via the Async call “GetEmployees” service.GetEmployeesCompleted += GetEmployeesCompleted; service.GetEmployeesAsync(Proxies.EmployeesQueryProxyStub.SerializeHelper.ToXml(q)); } catch (Exception exc) { Console.WriteLine(exc.StackTrace); }}
The above code has called GetEmployees (a WCF service method on the server). This is what our WCF Service method on the server that receives the query looks like.
public string GetEmployees(string serializedQuery){ List<Type> types = new List<Type>(); types.Add(typeof(EmployeesQuery)); // Deserialize our EmployeesQueryProxyStub class into our full blown server side query so we can execute it EmployeesQuery employeesQuery = EmployeesQuery.SerializeHelper.FromXml( serializedQuery, typeof(EmployeesQuery), types) as EmployeesQuery; EmployeesCollection employeesCollection = new EmployeesCollection(); if (employeesCollection.Load(employeesQuery)) { // Okay, we have loaded it, lets send the results back in string form EmployeesCollectionProxyStub proxy = new EmployeesCollectionProxyStub(employeesCollection); return esDataContractSerializer.ToXml(proxy); } return null;}
public string GetEmployees(string serializedQuery){ List<Type> types = new List<Type>(); types.Add(typeof(EmployeesQuery)); // Deserialize our EmployeesQueryProxyStub class into our full blown server side query so we can execute it EmployeesQuery employeesQuery = EmployeesQuery.SerializeHelper.FromXml( serializedQuery, typeof(EmployeesQuery), types) as EmployeesQuery;
EmployeesCollection employeesCollection = new EmployeesCollection(); if (employeesCollection.Load(employeesQuery)) { // Okay, we have loaded it, lets send the results back in string form EmployeesCollectionProxyStub proxy = new EmployeesCollectionProxyStub(employeesCollection); return esDataContractSerializer.ToXml(proxy); }
return null;}
Back under Silverlight in the browser our async GetEmployeesCompleted method is called, and we bind the data to the grid.
void GetEmployeesCompleted(object sender, GetEmployeesCompletedEventArgs e){ try { WaitText.Visibility = Visibility.Collapsed; string serializedEmployees = e.Result; // Turn the XML into a Proxies.EmployeesCollectionProxyStub collection Proxies.EmployeesCollectionProxyStub employees = esDataContractSerializer.FromXml( serializedEmployees, typeof(Proxies.EmployeesCollectionProxyStub)) as Proxies.EmployeesCollectionProxyStub; // Now Databind EmployeesDataGrid.ItemsSource = employees.Collection; } catch (Exception exc) { Console.WriteLine(exc.StackTrace); }}
void GetEmployeesCompleted(object sender, GetEmployeesCompletedEventArgs e){ try { WaitText.Visibility = Visibility.Collapsed;
string serializedEmployees = e.Result; // Turn the XML into a Proxies.EmployeesCollectionProxyStub collection Proxies.EmployeesCollectionProxyStub employees = esDataContractSerializer.FromXml( serializedEmployees, typeof(Proxies.EmployeesCollectionProxyStub)) as Proxies.EmployeesCollectionProxyStub;
// Now Databind EmployeesDataGrid.ItemsSource = employees.Collection; } catch (Exception exc) { Console.WriteLine(exc.StackTrace); }}
This approach offers some real advantages. You can later send the serialized collection back to the server with added, updated, and deleted rows. Once on the server, deserialize it, and simply call Save on the full server side collection. This is because our proxies maintain the rowstate for you. We are still working out the kinks as we build our Silverlight application. The one problem we have right now is the Silverlight grid seems to revert back to the original data and lose our cell edits. However, this happens with the Visual Studio proxies as well. Once we get this issue resolved and are fully saving data, we will publish our Silverlight demo. If you want to use this technique, you will need to generate the client side proxies and include them in your Silverlight or WCF client application. Be sure and click the new checkbox named “Serializable Queries” on the Advanced Tab of the Generated Master template. However, as you can see from the DynamicQuery Enhancements post, we are doing more than just addressing Silverlight and WCF development.
The bug that was affecting project files has been fixed. This occurred if you edited a template instance in an existing project, and saved without visiting all of the tabs. With this fix, un-visited tabs no longer revert to their default values. There is also a Twitter toolbar button on the What’s New page so you can easily get to our Twitter page. This alpha still only supports Microsoft SQL Server.
From Mobile Devices to large scale enterprise solutions in need of serious transaction support, EntitySpaces can meet your needs. Whether you’re writing an ASP.NET application with Medium Trust requirements, a Mono application, or a Windows.Forms application, the EntitySpaces architecture is there for you. EntitySpaces is provider independent, which means that you can run the same binary code against any of the supported databases. EntitySpaces is available in both C# and VB.NET. EntitySpaces uses no reflection, no XML files, and sports a tiny foot print of less than 200k. Pound for pound, EntitySpaces is one tough, dependable .NET architecture.
EntitySpaces LLCPersistence Layer and Business Objects for Microsoft .NEThttp://www.entityspaces.net
Page rendered at Tuesday, February 09, 2010 1:32:52 AM (Eastern Standard Time, UTC-05:00)
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.