Example E4932
Visible to All Users

How to create a data caching service that helps improve performance in distributed applications

Files to look at:

Scenario:
In the How to connect to a remote data service instead of using a direct database connection example we described how to connect to the WCF service via console application.
If you want to take advantages of XPO data caching using this solution, the only difference is in using the ICachedDataStore interface and the CachedDataStoreService base service class that implements this interface.

Steps to implement
1. Create a data service and console applications as described in the How to connect to a remote data service instead of using a direct database connection example.
2. Modify the service class as shown in the WCFService1\Service1 code file: use the CachedDataStoreService as base class, create a connection provide and data store.
3. Modify the web.configfile as shown in the WCFService1\web.config file.

There is no need to modify the client part since the service name has not been changed, and in addition, the “data caching domain” of our service is automatically detected by XPO.
It is easy to configure which tables should be cached and which ones shouldn't using the following code from the Service1 code file:

C#
DataCacheRoot dataCacheRoot = new DataCacheRoot(dataStore) dataCacheRoot.Configure(new DataCacheConfiguration(DataCacheConfigurationCaching.InList, "Customer") MainDataStore = dataCacheRoot;
Visual Basic
Dim dataCacheRoot As New DataCacheRoot(dataStore) dataCacheRoot.Configure(New DataCacheConfiguration(DataCacheConfigurationCaching.InList, "Customer")) MainDataStore = dataCacheRoot

This approach is useful for tables, which are frequently changed.

4. Create a data caching service based on the SqlDependency feature of the MS SQL Server. This approach is demonstrated in the WCFService2.Service1.xx file.

Important notes

If you are using an XAF client, then in the simplest case, you can just set the XafApplication.ConnectionString to the address of your data store service (http://localhost:55777/Service1.svc). Refer to the Connect an XAF Application to a Database Provider help article for more details.

Troubleshooting

  1. If WCF throws the "Entity is too large" error, you can apply a standard solution from StackOverFlow: http://stackoverflow.com/questions/10122957/
  2. If WCF throws the "The maximum string content length quota (8192) has been exceeded while reading XML data. " error, you can extend bindings in the following manner:
XML
<bindings> <basicHttpBinding> <binding name="ServicesBinding" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" transferMode="Streamed" > <readerQuotas maxDepth="2147483647" maxArrayLength="2147483647" maxStringContentLength="2147483647"/> </binding> </basicHttpBinding> </bindings>

See The maximum string content length quota (8192) has been exceeded while reading XML data

See also:
How to connect to a remote data service instead of using a direct database connection
How to implement a distributed object layer service working via WCF
How to connect to a remote data service from a Silverlight application

How to connect to remote data store and configure WCF end point programmatically

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

ConsoleApplication1/Customer.cs(vb)
C#
using DevExpress.Xpo; namespace ConsoleApplication1 { public class Customer : XPObject { public Customer(Session session) : base(session) { } string _CompanyName; public string CompanyName { get { return _CompanyName; } set { SetPropertyValue("CompanyName", ref _CompanyName, value); } } string _CompanyAddress; public string CompanyAddress { get { return _CompanyAddress; } set { SetPropertyValue("CompanyAddress", ref _CompanyAddress, value); } } string _ContactName; public string ContactName { get { return _ContactName; } set { SetPropertyValue("ContactName", ref _ContactName, value); } } string _Country; public string Country { get { return _Country; } set { SetPropertyValue("Country", ref _Country, value); } } string _Phone; public string Phone { get { return _Phone; } set { SetPropertyValue("Phone", ref _Phone, value); } } } }
ConsoleApplication1/Program.cs(vb)
C#
using System; using DevExpress.Xpo; using DevExpress.Xpo.DB; using DevExpress.Data.Filtering; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { XpoDefault.DataLayer = XpoDefault.GetDataLayer("http://localhost:55777/Service1.svc", AutoCreateOption.DatabaseAndSchema); XpoDefault.Session = null; using (UnitOfWork uow = new UnitOfWork()) { if (uow.FindObject(typeof(Customer), new BinaryOperator("ContactName", "Alex Smith", BinaryOperatorType.Equal)) == null) { Customer custAlex = new Customer(uow); custAlex.ContactName = "Alex Smith"; custAlex.CompanyName = "DevExpress"; custAlex.Save(); Customer Tom = new Customer(uow); Tom.ContactName = "Tom Jensen"; Tom.CompanyName = "ExpressIT"; Tom.Save(); uow.CommitChanges(); } using (XPCollection<Customer> customers = new XPCollection<Customer>(uow)) { foreach (Customer customer in customers) { Console.WriteLine("Company Name = {0}; ContactName = {1}", customer.CompanyName, customer.ContactName); } } } Console.WriteLine("Press any key..."); Console.ReadKey(); } } }
WcfService1/Service1.svc.cs(vb)
C#
using DevExpress.Xpo; using DevExpress.Xpo.DB; using DevExpress.Xpo.DB.Helpers; namespace WcfService1 { public class Service1 : CachedDataStoreService { public static ICachedDataStore MainDataStore; static Service1() { string connectionString = MSSqlConnectionProvider.GetConnectionString("localhost", "ServiceDB"); IDataStore dataStore = XpoDefault.GetConnectionProvider(connectionString, AutoCreateOption.DatabaseAndSchema); DataCacheRoot dataCacheRoot = new DataCacheRoot(dataStore); dataCacheRoot.Configure(new DataCacheConfiguration(DataCacheConfigurationCaching.InList, "Customer")); MainDataStore = dataCacheRoot; } public Service1() : base(MainDataStore) { } } }
WcfService1/Web.config
Code
<?xml version="1.0" encoding="utf-8"?> <configuration> <appSettings /> <system.web> <compilation debug="true" targetFramework="4.7.2" /> <httpRuntime /> </system.web> <system.serviceModel> <services> <service name="WcfService1.Service1" behaviorConfiguration="WcfService1.Service1Behavior"> <!-- Service Endpoints --> <endpoint address="" binding="basicHttpBinding" contract="DevExpress.Xpo.DB.ICachedDataStoreService"> <identity> <dns value="localhost" /> </identity> </endpoint> </service> </services> <behaviors> <serviceBehaviors> <behavior name="WcfService1.Service1Behavior"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> <system.webServer> <modules runAllManagedModulesForAllRequests="true" /> <!-- To browse web app root directory during debugging, set the value below to true. Set to false before deployment to avoid disclosing web app folder information. --> <directoryBrowse enabled="true" /> </system.webServer> </configuration>
WcfService2/Service1.svc.cs(vb)
C#
using System; using DevExpress.Xpo; using DevExpress.Xpo.DB; using DevExpress.Xpo.DB.Helpers; namespace WcfService1 { public class Service1 : CachedDataStoreService { public static ICachedDataStore MainDataStore; static Service1() { string connectionString = MSSqlConnectionProvider.GetConnectionString("localhost", "ServiceDB"); MSSqlConnectionProvider dataStore = (MSSqlConnectionProvider)XpoDefault.GetConnectionProvider( connectionString, AutoCreateOption.DatabaseAndSchema ); IDisposable[] objectsToDispose; MainDataStore = (ICachedDataStore)MSSql2005SqlDependencyCacheRoot.CreateSqlDependencyCacheRoot( dataStore, new DataCacheConfiguration(DataCacheConfigurationCaching.InList, "Customer"), out objectsToDispose ); } public Service1() : base(MainDataStore) { } } }
WcfService2/Web.config
Code
<?xml version="1.0" encoding="utf-8"?> <configuration> <appSettings /> <system.web> <compilation debug="true" targetFramework="4.7.2" /> <httpRuntime /> </system.web> <system.serviceModel> <services> <service name="WcfService1.Service1" behaviorConfiguration="WcfService1.Service1Behavior"> <!-- Service Endpoints --> <endpoint address="" binding="basicHttpBinding" contract="DevExpress.Xpo.DB.ICachedDataStoreService"> <identity> <dns value="localhost" /> </identity> </endpoint> </service> </services> <behaviors> <serviceBehaviors> <behavior name="WcfService1.Service1Behavior"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> <system.webServer> <modules runAllManagedModulesForAllRequests="true" /> <!-- To browse web app root directory during debugging, set the value below to true. Set to false before deployment to avoid disclosing web app folder information. --> <directoryBrowse enabled="true" /> </system.webServer> </configuration>

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.