Transfer Data via ASP.NET Core Web API / REST API
- 8 minutes to read
You can use a REST API to transfer data over the web. A REST API service is directly connected to a data store (DevExpress.Xpo.DB) and exchanges data records with client applications.
To transfer data over the web, use the following XPO components:
- A backend part - WebApiDataStoreService - helps you implement the XPO controller and actions required for the client part.
- A client part - WebApiDataStoreClient - helps you to connect to a backend service.
On the backend side, the web API controller must accept POST requests to the following actions:
/updateschema?doNotCreateIfFirstTableNotExist={true|false}
/selectdata
/modifydata
Tip
You can download a complete example here:
- A client part: a Blazor WebAssembly CRUD app
- A server part: an ASP.NET Web API app
Create a Web API Controller (ASP.NET Core Web API)
The steps below describe how to add an XPO web API controller to an ASP.NET Core Web API application.
Register WebApiDataStoreService in a service collection on startup. Add XML Serializer formatters to MVC services.
using DevExpress.Xpo; using DevExpress.Xpo.DB; // ... // configure WebApiDataStoreService string connectionString = builder.Configuration.GetConnectionString("MyConnectionString"); IDataStore dataStore = XpoDefault.GetConnectionProvider(connectionString, AutoCreateOption.SchemaAlreadyExists); builder.Services.AddSingleton(new WebApiDataStoreService(dataStore)); // add XML Serializer formatters builder.Services.AddMvc() .AddXmlSerializerFormatters();
Tip
More information: Dependency Injection.
Add a controller with three POST methods:
UpdateSchema
,SelectData
, andModifyData
.using System.Threading.Tasks; using DevExpress.Xpo.DB; using Microsoft.AspNetCore.Mvc; // ... // In this example, the controller URI is `[Your Service Address]/xpo`. [ApiController] [Route("[controller]/[action]")] public class XpoController : ControllerBase { readonly WebApiDataStoreService DataStoreService; public XpoController(WebApiDataStoreService dataStoreService) { this.DataStoreService = dataStoreService; } [HttpPost] public Task<OperationResult<UpdateSchemaResult>> UpdateSchema([FromQuery] bool doNotCreateIfFirstTableNotExist, [FromBody] DBTable[] tables) { return DataStoreService.UpdateSchemaAsync(doNotCreateIfFirstTableNotExist, tables); } [HttpPost] public Task<OperationResult<SelectedData>> SelectData([FromBody] SelectStatement[] selects) { return DataStoreService.SelectDataAsync(selects); } [HttpPost] public Task<OperationResult<ModificationResult>> ModifyData([FromBody] ModificationStatement[] dmlStatements) { return DataStoreService.ModifyDataAsync(dmlStatements); } }
Support Cached Data Store
On the client side, create a WebApiDataStoreClient object and pass it as a parameter to the DataCacheNode constructor. Use this DataCacheNode instance as IDataStore. For example, pass it as a parameter to the SimpleDataLayer or ThreadSafeDataLayer constructor.
ICacheToCacheCommunicationCore cacheRoot = new WebApiDataStoreClient(httpClient, AutoCreateOption.SchemaAlreadyExists);
IDataStore dataStore = new DataCacheNode(cacheRoot);
To configure the Data Cache Root on the server side:
Wrap an IDataStore instance in a DataCacheRoot object.
using DevExpress.Xpo; using DevExpress.Xpo.DB; // ... // configure WebApiDataStoreService string connectionString = builder.Configuration.GetConnectionString("MyConnectionString"); IDataStore dataStore = XpoDefault.GetConnectionProvider(connectionString, AutoCreateOption.SchemaAlreadyExists); dataStore = new DataCacheRoot(dataStore); builder.Services.AddSingleton(new WebApiDataStoreService(dataStore)); // add XML Serializer formatters builder.Services.AddMvc() .AddXmlSerializerFormatters();
Add the following POST methods to the controller:
ModifyDataWithCookie
NotifyDirtyTables
ProcessCookie
SelectDataWithCookie
UpdateSchemaWithCookie
using System.Threading.Tasks; using DevExpress.Xpo.DB; using Microsoft.AspNetCore.Mvc; // ... // In this example, the controller URI is `[Your Service Address]/xpo`. [ApiController] [Route("[controller]/[action]")] public class XpoController : ControllerBase { readonly WebApiDataStoreService DataStoreService; public XpoController(WebApiDataStoreService dataStoreService) { this.DataStoreService = dataStoreService; } // ... [HttpPost] public OperationResult<DataCacheModificationResult> ModifyDataWithCookie([FromBody] WebApiDataContainer<ModificationStatement[]> data) { return DataStoreService.ModifyDataWithCookie(data); } [HttpPost] public OperationResult<DataCacheResult> NotifyDirtyTables([FromBody] WebApiDataContainer<string[]> data) { return DataStoreService.NotifyDirtyTables(data); } [HttpPost] public OperationResult<DataCacheResult> ProcessCookie([FromBody] DataCacheCookie data) { return DataStoreService.ProcessCookie(data); } [HttpPost] public OperationResult<DataCacheSelectDataResult> SelectDataWithCookie([FromBody] WebApiDataContainer<SelectStatement[]> data) { return DataStoreService.SelectDataWithCookie(data); } [HttpPost] public OperationResult<DataCacheUpdateSchemaResult> UpdateSchemaWithCookie([FromQuery] bool doNotCreateIfFirstTableNotExist, [FromBody] WebApiDataContainer<DBTable[]> data) { return DataStoreService.UpdateSchemaWithCookie(doNotCreateIfFirstTableNotExist, data); } }
Create a Web API Controller (ASP.NET MVC Web API)
The steps below describe how to add an XPO web API controller to an ASP.NET MVC Web API application.
Create WebApiDataStoreService in the Global.asax file and share it via a static field.
// Startup.cs // ... using DevExpress.Xpo; using DevExpress.Xpo.DB; namespace DxSample.Server { public class WebApiApplication : System.Web.HttpApplication { static WebApiDataStoreService fDataStoreService; public static WebApiDataStoreService DataStoreService => fDataStoreService; protected void Application_Start() { // ... string connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString; connectionString = XpoDefault.GetConnectionPoolString(connectionString); IDataStore dataStore = XpoDefault.GetConnectionProvider(connectionString, AutoCreateOption.DatabaseAndSchema); fDataStoreService = new WebApiDataStoreService(dataStore); } } }
Tip
More information: Dependency Injection.
Set an XML Serializer for all required types in the App_Start\WebApiConfig.cs file.
// ... using DevExpress.Xpo.DB; namespace DxSample.Server { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // ... // Web API routes config.MapHttpAttributeRoutes(); // NEW CODE config.Formatters.XmlFormatter.SetSerializer<OperationResult<UpdateSchemaResult>>(new XmlSerializer(typeof(OperationResult<UpdateSchemaResult>))); config.Formatters.XmlFormatter.SetSerializer<OperationResult<SelectedData>>(new XmlSerializer(typeof(OperationResult<SelectedData>))); config.Formatters.XmlFormatter.SetSerializer<OperationResult<ModificationResult>>(new XmlSerializer(typeof(OperationResult<ModificationResult>))); config.Formatters.XmlFormatter.SetSerializer<DBTable[]>(new XmlSerializer(typeof(DBTable[]))); config.Formatters.XmlFormatter.SetSerializer<SelectStatement[]>(new XmlSerializer(typeof(SelectStatement[]))); config.Formatters.XmlFormatter.SetSerializer<ModificationStatement[]>(new XmlSerializer(typeof(ModificationStatement[]))); // ... } } }
Add a controller with three POST methods:
UpdateSchema
,SelectData
, andModifyData
.using DevExpress.Xpo.DB; using System.Threading.Tasks; using System.Web.Http; namespace DxSample.Server.Controllers { [RoutePrefix("xpo")] public class XpoController : ApiController { [HttpPost] [Route("UpdateSchema")] public Task<OperationResult<UpdateSchemaResult>> UpdateSchema(bool doNotCreateIfFirstTableNotExist, [FromBody] DBTable[] tables) { return WebApiApplication.DataStoreService.UpdateSchemaAsync(doNotCreateIfFirstTableNotExist, tables); } [HttpPost] [Route("SelectData")] public Task<OperationResult<SelectedData>> SelectData([FromBody] SelectStatement[] selects) { return WebApiApplication.DataStoreService.SelectDataAsync(selects); } [HttpPost] [Route("ModifyData")] public Task<OperationResult<ModificationResult>> ModifyData([FromBody] ModificationStatement[] dmlStatements) { return WebApiApplication.DataStoreService.ModifyDataAsync(dmlStatements); } } }
Connect a Client Application to a Web API Service
You can connect a client application to a web service in any of the following ways:
Option 1. Use XpoDefault.GetConnectionProvider or XpoDefault.GetDataLayer Methods
Call the XpoDefault.GetConnectionProvider or XpoDefault.GetDataLayer method as described in the following help topic: Connect to a Data Store. The connection string format is as follows:
"XpoProvider=WebApi;uri=https://example.com/xpo/"
You can use the static WebApiDataStoreClient.GetConnectionString(String) method to create a connection string.
Option 2. Connect with HttpClient
Create an HttpClient component, assign an HTTP address to the HttpClient.BaseAddress property, and pass the HttpClient instance to the WebApiDataStoreClient constructor. Optionally, initialize other HttpClient properties, such as HttpClient.DefaultRequestHeaders.
Note
Since WebApiDataStoreClient uses the HttpClient component, HttpClient.BaseAddress should point to a controller route. Note that HttpClient merges BaseAddress with a relative URI according to section [5.2.3. Merge Paths] of RFC 3986. This means that HttpClient excludes the last segment of the BaseAddress. To prevent this, add a slash /
to the end of the BaseAddress.
This URI is correct: https://example.com/xpo/
This URI is not correct: https://example.com/xpo
Configure HttpClient options
To use the advanced HttpClient features (for example, the automatic HTTP content response decompression), connect the application to a Web API service using Option 2. Note that users will lose the ability to dynamically set the data store type using the XpoProvider
connection string parameter.
using System;
using System.Net;
using System.Net.Http;
using DevExpress.Xpo.DB;
using DevExpress.Xpo.DB.Helpers;
// ...
var handler = new HttpClientHandler() { AutomaticDecompression = System.Net.DecompressionMethods.Brotli };
var httpClient = new HttpClient(handler, true);
httpClient.BaseAddress = new Uri("https://localhost:5001/xpo/");
httpClient.DefaultRequestHeaders.Add("Accept-Encoding", "br");
IDataStore dataStore = new WebApiDataStoreClient(httpClient, autoCreateOption);
To allow users to specify the data store type with the XpoProvider
parameter, register a new provider name associated with a method that creates a provider instance.
using System;
using System.Net;
using System.Net.Http;
using DevExpress.Xpo;
using DevExpress.Xpo.DB;
using DevExpress.Xpo.DB.Helpers;
// ...
DataStoreBase.RegisterDataStoreProvider("WebApiWithBrotli", CreateDataStoreFromString);
string connectionString = @"XpoProvider=WebApiWithBrotli;uri=https://localhost:5001/xpo/";
IDataStore dataStore = XpoDefault.GetConnectionProvider(connectionString, AutoCreateOption.DatabaseAndSchema);
// ...
static IDataStore CreateDataStoreFromString(string connectionString, AutoCreateOption autoCreateOption, out IDisposable[] toDispose) {
var handler = new HttpClientHandler() { AutomaticDecompression = System.Net.DecompressionMethods.Brotli };
var httpClient = new HttpClient(handler, true);
var parser = new ConnectionStringParser(connectionString);
httpClient.BaseAddress = new Uri(parser.GetPartByName("uri"));
httpClient.DefaultRequestHeaders.Add("Accept-Encoding", "br");
toDispose = new IDisposable[] { httpClient };
return new WebApiDataStoreClient(httpClient, autoCreateOption);
}
Connect a Xamarin App
You can connect a Xamarin app to an XPO in the same way as described in the previous section, but you need to follow extra steps to run the application in simulators. For detailed information, refer to the following help topic: Connect to local web services from iOS simulators and Android emulators.
An Android emulator uses its own network and cannot connect to a web service running on IIS Express, because IIS Express does not allow remote access. The solutions are as follows:
For the ASP.NET Core Web API application: run a web service project using the “Project” profile instead of “IIS Express”.
- For the ASP.NET Web API application: use an open-source iisexpress-proxy tool.
Transfer Data via REST API using JSON Format
If you need a Web API service that returns XPO objects in the JSON format, manually implement the required controllers and the client API. The following examples illustrate how to implement such a service:
- XPO JSON Serialization (.NET Framework)
- OData v4 Service (.NET Framework)
- OData v4 Service (.NET Core)
A 1-Click Solution for Role-based Access Control with Web API Services via XPO (FREE)
XAF’s Solution Wizard scaffolds a Web API Service with integrated authorization & CRUD operations powered by XPO ORM library. You can use OAuth2, JWT or custom strategies for authentication alongside tools like Postman or Swagger for API testing. The built-in security system also filters out secured server data based on permissions granted to users. These basic functions are available free-of-charge: https://www.devexpress.com/security-api-free.