Back to Devexpress

Connect a .NET Desktop Client to a Backend Using a Middle Tier Security Server (EF Core with WebSockets)

windowsforms-405147-data-access-security-connect-to-a-secure-middle-tier-api-server.md

latest10.0 KB
Original Source

Connect a .NET Desktop Client to a Backend Using a Middle Tier Security Server (EF Core with WebSockets)

  • Mar 14, 2025
  • 5 minutes to read

A middle-tier architecture combines all data access and related logic in one place, adding an essential layer of security as it can manage authentication, authorization, and encryption. With this additional layer of protection, desktop UI clients cannot access database connection information or modify database tables directly. 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 and scale.

In a Middle Tier Server architecture, DbContext and other EF Core CRUD APIs are still used in the 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.

Key Components

  1. Entity Framework Core (EF Core)

  2. Middle Tier Server (Data Access and Business Logic Layer)

  3. WinForms UI Client

Demo App for .NET 8

Our sample Windows Forms application demonstrates the following:

  • How to build a data model for application business entities and security policies with EF Core.
  • How to use the DevExpress ASP.NET 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 application.
  • How to create a login form.
  • How to customize the UI/UX for a given user based on associated access permissions.
  • How to create an edit form to modify and save data (CRUD).

View Example: Middle Tier (EF Core)

Implementation Details

Initialization and Authentication

The RemoteContextUtils class implements utility APIs related to remote DbContext and secured communication within client applications. The CreateSecuredClient method securely connects to an EF Core Middle Tier Security application:

csharp
public static WebApiSecuredDataServerClient CreateSecuredClient(string url, string login, string password) {
    var httpClient = new HttpClient();
    httpClient.BaseAddress = new Uri(url);
    httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
    var securedClient = new WebSocketSecuredDataServerClient(httpClient, XafTypesInfo.Instance);
    securedClient.CustomAuthenticate += (sender, arguments) => {
        arguments.Handled = true;
        HttpResponseMessage msg = arguments.HttpClient.PostAsJsonAsync("api/Authentication/Authenticate", (AuthenticationStandardLogonParameters)arguments.LogonParameters).GetAwaiter().GetResult();
        string token = (string)msg.Content.ReadFromJsonAsync(typeof(string)).GetAwaiter().GetResult();
        if(msg.StatusCode == HttpStatusCode.Unauthorized) {
            throw new UserFriendlyException(token);
        }
        msg.EnsureSuccessStatusCode();
        arguments.HttpClient.DefaultRequestHeaders.Authorization
            = new AuthenticationHeaderValue("bearer", token);
    };
    securedClient.Authenticate(new AuthenticationStandardLogonParameters(login, password));
    ((IMiddleTierServerSecurity)securedClient).Logon();
    return securedClient;
}

The RemoteContextUtils.GetDBContext() method returns a secured DbContext for CRUD operations:

csharp
public static DXApplication1EFCoreDbContext GetDBContext() {
    return new DXApplication1EFCoreDbContext(Options);
}
public static DbContextOptions<DXApplication1EFCoreDbContext> CreateDbContextOptions(WebApiSecuredDataServerClient securedClient) {
    var builder = new DbContextOptionsBuilder<DXApplication1EFCoreDbContext>();
    return builder
        .UseLazyLoadingProxies()
        .UseChangeTrackingProxies()
        .UseMiddleTier(securedClient)
        .Options as DbContextOptions<DXApplication1EFCoreDbContext>;
}

Access Permissions

The following code example creates Admin and User roles and defines these permissions:

  • Admin: Read/Write (full access)

  • User: Read Only (data editing is not allowed)

  • Updater.cs

csharp
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;
    }
    private PermissionPolicyRole GetAdminRole() {
        PermissionPolicyRole adminRole = ObjectSpace.FirstOrDefault<PermissionPolicyRole>(u => u.Name == AdministratorRoleName);
        if(adminRole == null) {
            adminRole = ObjectSpace.CreateObject<PermissionPolicyRole>();
            adminRole.Name = AdministratorRoleName;
            adminRole.IsAdministrative = true;
        }
        return adminRole;
    }
    //...
}

Login Form: Validate User Credentials, User Authorization

The LogIn form attempts to log the user into the security system and returns DialogResult.OK if a login was successful:

csharp
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;
}

Bind the DevExpress Data Grid to Remote Data

If user authentication was successful, the SetUpBinding method creates a DbContext and binds the grid to data:

csharp
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;
    }
}

Configure UI Based on Access Permissions

Highlighted lines enable/disable Ribbon commands (New, Edit, Delete) based on access permissions of the current (logged in) user:

csharp
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);
}

View Example: Middle Tier (EF Core)

Important Disclaimer

Important

These deployment recommendations do not apply to all possible configurations and should not be considered comprehensive. We offer these instructions as a getting-started reference. Steps may vary depending on your operating system, installed software, and DevExpress versions. You, the developer, are responsible for the application, database, network, and other configurations based on your client, security, environment, and other requirements. We recommend that you review these settings with your database, network, and IT infrastructure administrators and consider their recommendations tailored to your case.

See Also

Middle Tier Security with EF Core

Create an Application with EF Core Middle Tier Security

Connect a .NET Desktop Client to an ASP.NET Core WebAPI Service Powered by EF Core

Connect a .NET Desktop Client to a Secure Backend Web API Service (EF Core with OData)