XPO – 11.1 Sneak Peek - WCF services for IObjectLayer

XPO Team Blog
17 May 2011

In the two previous blog posts, we already described how to provide the IDataStore and ICachedDataStore implementations, working via WCF Services. In this blog post, we will talk about implementing a distributed object layer service (IObjectLayer/ISerializableObjectLayer), working via WCF. Creating a WCF service for ISerializableObjectLayer is a bit more complex than for IDataStore and ICachedDataStore, but it is still very similar.

First, we will create a new Class Library project and add a Customer class via the Persistent Object item template to it (you can see the source code of this class in our first blog). Then, we will create a new WCF Service Application project and remove files with auto-generated interfaces for the service. Since our service needs to know about persistent classes, we will add a project reference to our class library and modify our service class as follows:

  1: using DevExpress.Xpo;
  2: using DevExpress.Xpo.DB;
  3: using DevExpress.Xpo.Metadata;
  4: using ClassLibrary1;
  5: ...
  6: public class Service1: SerializableObjectLayerService {
  7:     public Service1()
  8:         :base(new ObjectServiceProxy()){
  9:     } 
 10:     static Service1() {
 11:         string connectionString = MSSqlConnectionProvider.GetConnectionString("localhost", "ServiceDB");
 12:         IDataStore dataStore = XpoDefault.GetConnectionProvider(connectionString, AutoCreateOption.DatabaseAndSchema);
 13:         XPDictionary dictionary = new ReflectionDictionary();
 14:         dictionary.CollectClassInfos(typeof(Customer).Assembly);
 15:         XpoDefault.DataLayer = new ThreadSafeDataLayer(dictionary, dataStore);
 16:         XpoDefault.Session = null; 
 17:     }
 18: }
 19: public class ObjectServiceProxy : SerializableObjectLayerProxyBase {
 20:     protected override SerializableObjectLayer GetObjectLayer() {
 21:         return new SerializableObjectLayer(new UnitOfWork(), true);
 22:     }
 23: }

To finish with the service, we will need to change some binding properties in its Web.config file:

  1: <system.serviceModel>
  2:  <services>
  3:    <service name="WcfService2.Service1" behaviorConfiguration="WcfService2.Service1Behavior">
  4:      <!-- Service Endpoints -->
  5:      <endpoint address="" binding="basicHttpBinding"
  6: contract="DevExpress.Xpo.DB.ISerializableObjectLayerService">
  7:        <identity>
  8:          <dns value="localhost"/>
  9:        </identity>
 10:      </endpoint>
 11:    </service>
 12:  </services>
 13:  <behaviors>
 14:    <serviceBehaviors>
 15:      <behavior name="WcfService2.Service1Behavior">
 16:        <serviceMetadata httpGetEnabled="true"/>
 17:        <serviceDebug includeExceptionDetailInFaults="false"/>
 18:      </behavior>
 19:    </serviceBehaviors>
 20:  </behaviors>
 21: </system.serviceModel>

At this time, our service is ready to use and all that we need to do is to write the client part.

For the client, we will add a Console Application into our existing solution and add a project reference to the class library with our Customer persistent class. The Main() method should also be modified as follows:

  1: using DevExpress.Xpo;
  2: using DevExpress.Xpo.DB;
  3: using DevExpress.Xpo.Metadata;
  4: using ClassLibrary1;
  5: ...
  6: namespace ObjectWcfClient {
  7:     class Program {
  8:         static IObjectLayer ObjectLayer;
  9:         static void Main(string[] args) {
 10:             ISerializableObjectLayer serializableObjectLayer =  
 11:                 new SerializableObjectLayerServiceClient("BasicHttpBinding_ObjectLayer");
 12:             serializableObjectLayer.CanLoadCollectionObjects.ToString(); //Check connection
 13:             XpoDefault.DataLayer = null;
 14:             XpoDefault.Session = null;
 15:             ObjectLayer = new SerializableObjectLayerClient(serializableObjectLayer);
 17:             using(UnitOfWork uow = new UnitOfWork(ObjectLayer)) {
 18:                 using(XPCollection<Customer> customers = new XPCollection<Customer>(uow)){
 19:                     foreach(Customer customer in customers) {
 20:                         Console.WriteLine("Company Name = {0}; ContactName = {1}", 
 21:                             customer.CompanyName, customer.ContactName);
 22:                     }
 23:                 }
 24:             } 
 25:             Console.WriteLine("Press any key...");
 26:             Console.ReadKey();
 27:         }
 28:     }
 29: }

The final step will be adding the App.config file into the client project and modifying it as follows:

  1: <?xml version="1.0" encoding="utf-8" ?>
  2: <configuration>
  3:   <system.serviceModel>
  4:     <bindings>
  5:       <basicHttpBinding>
  6:         <binding name="BasicHttpBinding_ObjectLayer" maxBufferSize="2147483647"
  7:             maxReceivedMessageSize="2147483647">
  8:           <security mode="None" />
  9:         </binding>
 10:       </basicHttpBinding>
 11:     </bindings>
 12:     <client>
 13:       <endpoint address="http://localhost:64466/Service1.svc" binding="basicHttpBinding"
 14:           bindingConfiguration="BasicHttpBinding_ObjectLayer"
 15:           contract="DevExpress.Xpo.DB.ISerializableObjectLayerService" name="BasicHttpBinding_ObjectLayer" />
 16:     </client>
 17:   </system.serviceModel> 
 18: </configuration>

Now if we run the service and client parts, we will see the following output:

As you can see, our client connects to the service and loads serialized persistent objects from it, and not just plain statements (insert, update, delete, select). You can learn more on which capabilities it opens for XPO customers at the end of our introductory blog for the object layer.

Happy XPOing!Winking smile

Free DevExpress Products – Get Your Copy Today

The following free DevExpress product offers remain available. Should you have any questions about the free offers below, please submit a ticket via the DevExpress Support Center at your convenience. We’ll be happy to follow-up.
Nate Laff
Nate Laff

Since the developer is not controlling the service implementation itself, what is the advantage to using this over the IDataStore method?

The IDataStore is just tunneling to the DB where this is actually processing server side, right?

17 May 2011
Nick Khorin
Nick Khorin

Nate, I think that SerializableObjectLayerService is included in XPO for the same reason as WebServiceDataStore: a ready-to-use implementation of a service. You, as a developer, can implement it in your own way, and the easiest approach to get started is to copy code from XPO to your project. Let's wait for v11.1. I'm also eager to see how guys implemented SerializableObjectLayerService.

18 May 2011
Steven Rasmussen
Steven Rasmussen

Hi Dennis - this is great stuff!  I'm still waiting for the big announcement regarding how this has paved the way for the new security system in XAF that will be released in 11.1 :)

18 May 2011
Robert Fuchs
Robert Fuchs

@Steven ... why this has *not* paved the way for the new security system in XAF that will *not* be released in 11.1


AFAIK, Robert

18 May 2011
Steven Rasmussen
Steven Rasmussen

That's pretty disappointing :(

18 May 2011
Michael Proctor [DX-Squad]
Michael Proctor [DX-Squad]

As the ObjectLayer was only "mentioned" for 10.2 as a included but not documented feature, I didn't put it high on my priorities.

However the next iteration of my project, this is now planned to be implemented.

Currently my project uses WCF services using the IDatastore as my contract. This is working well especially with Noemax WCFX extensions (compression/fast xml writer/reader). However as realised by other XPO'ers, we are abstracting the raw datastore, therefore all security has to be on the client, which is not the ideal scenario.

The ObjectLayer to my understanding is allowing us to abstract at the DataLayer, meaning the Service will get a bunch of Objects that need to be saved or a bunch of objects it needs to send out. This allows us more control at the server to make decisions such as to confirm if the user saving is indeed allowed to modify this record, possibly only save particular fields of the object, which works the other way whereby when retrieving data we can clear fields out before sent over the wire (and ensure that the blank fields are saved back to the datastore)

Another feature I have planned using this is moving my auditing feature to the server. This is not only more secure, but also reduces the amount of data sent over the wire. Currently when a user performs a save I am sending both the object to be saved plus an additional audit object containing what fields changed. This effectively doubles my transfer on modificaiton of data. Moving this to the server immediately drops it.

Overall I am very excited to get my teeth stuck into this, (hopefully about 2 weeks) to which I will be blogging my results.

Great work guys.

18 May 2011
Slava D (DevExpress)
Slava D (DevExpress)

Thank you for the feedback, guys!

@Michael Proctor:

Yes, you are absolutely right. Your explanation is so complete that I even have nothing to add. Thank you. :D

19 May 2011
Robert Thomas
Robert Thomas

Is there an example on how to use this for XAF?

12 June 2011
Kobus  Smit
Kobus Smit

Hi Michael

Did you progress with your IObjectLayer project? I'm really interested in that blog post :)

Do you perhaps have an XAF example using WCF services?

Currently my users are complaining about speed connecting the WinForms UI to a remote database. I hope that WCF + the Noemax compression might improve the performance...



25 July 2011
Michael Proctor [DX-Squad]
Michael Proctor [DX-Squad]

Hi guys just a quick update to say I have started my blog posts



Hope these help a little

28 July 2011
Kobus  Smit
Kobus Smit

Thanks Michael, will check it out!

2 August 2011
stefano del furia
Gian Luca Gennaioli

Hi guys, i would like to know if some can point me to some examples of using WCF + the Noemax library and use it with XPO.

i has been able to work with IDataStore and WCF and i would like to use the Noemax library to improve performance.


3 November 2011

Please login or register to post comments.