Series Overview
This article is the second in a series of posts for teams who wish to build .NET desktop applications that communicate securely with backend services.
Table of Contents
- Intro — Modern Desktop Apps And Their Complex Architecture | Choosing a Framework/App Architecture for Desktop & Mobile Cross-Platform Apps / GitHub sample
- Part 1 — Connect a WinForms Data Grid to an Arbitrary ASP.NET Core WebAPI Service Powered by EF Core — Architecture and Data Binding / GitHub sample
- Part 2 — Connect a WinForms Data Grid to an Arbitrary ASP.NET Core WebAPI Service Powered by EF Core — Add Editing Features / GitHub sample
- Part 3 (TBD) — Connect a WinForms Data Grid to an Arbitrary ASP.NET Core WebAPI Service Powered by EF Core — Authenticate users and protect data / GitHub sample
- Part 4 — Connect a .NET Desktop Client to a Secure Backend Web API Service (EF Core with OData)
- Part 5 — Connect a .NET Desktop Client to a Backend Using a Middle Tier Server (EF Core without OData) (this post)
- Part 6 (TBD) — Connect a .NET Desktop Client to Azure Databases with Data API Builder
- Part 7 (TBD) — Connect a .NET Desktop Client to GraphQL APIs
We also have related blog series, which may be of interest for you as well: JavaScript — Consume the DevExpress Backend Web API with Svelte (7 parts from data editing to validation, localization, reporting).
Target Audience
The target audience for this post is as follows:
- EF Core/XPO Developers planning to modernize an existing application or create a new project. Using the techniques herein, you will be able to maintain an existing data context (
DbContext
orSession
) while establishing remote/secure connections from any .NET client to an RDBMS-based data store. You can reuse your current DbContext and EF Core data model with little or no modification. - ADO.NET Developers using direct SQL, stored procedures, or similar data access methods. This post will help you get started with EF Core, Microsoft's ORM. With EF Core, you can leverage the benefits of a distributed app architecture and introduce role-based access control alongside user authentication.
Why Use a Middle Tier Application Server?
As you know, direct client-database connections can expose sensitive data. A middle-tier server introduces an important security layer - and when designed properly - can effectively manage authentication, authorization, and encryption for your next great app. With this additional layer of protection, desktop UI clients cannot access database connection information or modify database tables directly.
Image may be NSFW.Clik here to view.

When using a Middle Tier Server architecture, DbContext and other EF Core CRUD APIs are still used in UI client app code - which interacts with the server remotely. Only the server has direct access to the database. Before passing data to the client's DbContext, the server enforces security measures such as authentication, authorization, and data validation.
The DevExpress Middle Tier Security App Server
By introducing a middle tier:
- You separate the client interface from backend logic and database access. This separation simplifies client application development and reduces code duplication, as the same logic can be reused by multiple UI clients - making the 'system' easier to maintain/scale.
- You can focus on creating intuitive interfaces without worrying about database access/and many security-related issues.
Our XAF (Cross-Platform .NET App UI) and Universal Subscription include a Middle Tier Server that allows EF Core developers to maintain their standard DbContext while establishing remote and secure database connections from .NET clients, such as WinForms or WPF. The server's security system engine supports Type, Record, and Field Level Authorization. This security system also powers our free Backend Web API Service - used by many XAF and non-XAF DevExpress users across multiple platforms, including JS, .NET MAUI, Blazor.
The DevExpress Middle Tier solution "replaces" direct database connections with middleware, ensuring that only authorized users can access specific/sensitive data or perform granted actions:
var httpRemoteRepository = new HttpRemoteRepository(httpClient, typeof(EFCoreDbContext).FullName);
var optionsBuilder = new DbContextOptionsBuilder<EFCoreDbContext>();
optionsBuilder.UseMiddleTier(opt =>
opt.UseRemoteRepository(httpRemoteRepository));
optionsBuilder.UseChangeTrackingProxies();
optionsBuilder.UseLazyLoadingProxies();
var dbContextOptions = optionsBuilder.Options;
var dbContext = new EFCoreDbContext(dbContextOptions);
var users = dbContext.Employees.ToList();
WinForms Demo Application
We've developed a GitHub example that implements middleware in a real-world scenario. The example connects a Windows Forms (.NET 8) client application to a secure backend using the DevExpress ASP.NET Core Middle Tier server.
The example demonstrates the following capabilities:
- How to build a data model for application business entities and security policies with EF Core.
- How to use the DevExpress ASP.ENT Core Middle Tier Security Server to connect a Windows Forms .NET 8 client application to a backend.
- How to define access permissions and activate authentication/authorization for a .NET 8 WinForms app.
- How to create a login form.
- How to customize UI/UX for a given user based on associated access permissions.
- How to create an edit form to modify and save data (CRUD).
The example creates Admin and User roles and defines the following permissions:
- Admin: Read/Write (full access)
- User: Read Only (data editing is not allowed)
public class Updater : ModuleUpdater {
private const string AdministratorUserName = "Admin";
private const string AdministratorRoleName = "Administrators";
private const string DefaultUserName = "User";
private const string DefaultUserRoleName = "Users";
//...
private PermissionPolicyRole GetUserRole() {
PermissionPolicyRole userRole = ObjectSpace.FirstOrDefault<PermissionPolicyRole>(u => u.Name == DefaultUserRoleName);
if(userRole == null) {
userRole = ObjectSpace.CreateObject<PermissionPolicyRole>();
userRole.Name = DefaultUserRoleName;
userRole.AddTypePermission<Employee>(SecurityOperations.Read, SecurityPermissionState.Allow);
userRole.AddTypePermission<Employee>(SecurityOperations.Write, SecurityPermissionState.Deny);
}
return userRole;
}
//...
}
The LogIn form attempts to log the user into the security system:
using(AuthForm authForm = new AuthForm()) {
if(authForm.ShowDialog() == DialogResult.OK) {
MiddleTierStartupHelper.WaitMiddleTierServerReady(MiddleTierStartupHelper.EFCoreWebApiMiddleTierInstanceKey, TimeSpan.MaxValue);
// User authorization.
var securedClient = RemoteContextUtils.CreateSecuredClient(System.Configuration.ConfigurationManager.AppSettings["endpointUrl"], authForm.Login, authForm.Password);
RemoteContextUtils.SecuredDataServerClient = securedClient;
DbContextOptions<DXApplication1EFCoreDbContext> options = RemoteContextUtils.CreateDbContextOptions(securedClient);
RemoteContextUtils.Options = options;
Application.Run(new MainForm());
}
else
break;
}
Image may be NSFW.Clik here to view.

SetUpBinding
method creates a DbContext and binds the grid to data:
public partial class MainForm : RibbonForm {
EntityServerModeSource serverModeSource = new EntityServerModeSource();
DXApplication1EFCoreDbContext dbContext = null;
public MainForm() {
InitializeComponent();
SetUpBinding();
}
void SetUpBinding() {
dbContext?.Dispose();
dbContext = RemoteContextUtils.GetDBContext();
serverModeSource = new EntityServerModeSource() { ElementType = typeof(Employee), KeyExpression = "ID" };
serverModeSource.QueryableSource = dbContext.Employees;
gridControl.DataSource = serverModeSource;
}
}
Highlighted code snippets enable/disable Ribbon commands (New, Edit, Delete) based on access permissions for the current (logged in) user:
public MainForm() {
InitializeComponent();
SetUpBinding();
bbiNew.Enabled = RemoteContextUtils.IsGranted(typeof(Employee), SecurityOperations.Create);
bbiDelete.Enabled = RemoteContextUtils.IsGranted(typeof(Employee), SecurityOperations.Delete);
bbiEdit.Enabled = RemoteContextUtils.IsGranted(typeof(Employee), SecurityOperations.Write);
}
Clik here to view.

Summary
Whether you're an EF Core/XPO developer looking to modernize legacy software, or an ADO.NET developer tasked to deliver a secure/scalable solution, implementing a middle tier server is an important step forward. The DevExpress XAF-based Middle Tier solution allows you to quickly integrate a middle tier server (with minimal modifications) into your system architecture, improving maintainability and your solution's overall security posture.
Your Feedback Matters
Image may be NSFW.Clik here to view.