Skip to main content
A newer version of this page is available. .

Middle Tier Security - WCF Service

  • 11 minutes to read

Important

This topic demonstrates the code that can be generated automatically by the Solution Wizard. Proceed, if you want to implement the demonstrated functionality in the existing XAF solution. If you are creating a new XAF solution, use the wizard instead.

When the security engine is running in a client application, the database is exposed to a client workstation. An end-user can see the connection string in the application’s configuration file and can use it to directly access the database tables, bypassing the security engine. This topic demonstrates how to place the Middle Tier application server between your application and the database server. The server will use Windows Communication Foundation (WCF). Restricted data will be filtered out by the server, and clients may have no direct access to the database server and may not even know its actual network location. The diagram below illustrates such a configuration.

MiddleTier_Diagram

Note

  • The Middle Tier does not support the Entity Framework data model, it is for XPO only.
  • The Middle Tier does not make a lot of sense for an ASP.NET or Mobile application from a logical, maintenance and performance point of view. These applications are client-server by default.

  • The Middle Tier and the database engine can be physically located on the same server. Technically, the application server can also be installed at the end-user workstation together with the application itself, but such a configuration makes no sense from a security standpoint.
  • The Middle Tier application server is a regular WCF service and you can use standard approaches to secure and deploy it (see Programming WCF Security).

Tip

A complete sample project is available in the DevExpress Code Examples database at How to: Implement middle tier security with the WCF service.

Create and Configure the Server

While debugging, it is convenient to use the Application Server that is implemented as a simple console application. Later, you will be able to convert it to a Windows Service, which can be deployed in the production environment (see Run the Application Server as a Windows Service). To add the Console Application Server project to your XAF solution, use the Application Server Project template of the DevExpress v18.1 XAF Solution Wizard.

  • Right-click the solution in the Solution Explorer.
  • In the invoked context menu, choose Add | New Project….
  • Choose the DevExpress v18.1 XAF Solution Wizard template.
  • Specify the project name (e.g., MySolution.AppServer) and click OK.
  • Select the Application Server Project in the Solution Wizard and click Next.
  • Specify what type of authentication you use (Standard or Active Directory), choose the WCF Service database security type and click Finish.

The created application server will connect directly to your application’s database, and handle initial database creation and updates. Therefore, the application server must be aware of the client application name, security system settings, modules used in the client application and the database connection string. To configure the newly added server, modify the following two files: Program.cs (Program.vb) and App.config.

Below is the list of required modifications to the Program.cs (Program.vb) file.

  • The ServerApplication.ApplicationName property value. It should be the same as your client application name (i.e., XafApplication.ApplicationName);
  • The ServerApplication.Modules collection. It should contain modules that are directly referenced by your client application. To see which client application modules are required, refer to the InitializeComponent method code in your WinApplication/WebApplication descendant. Add the required module projects references (e.g., MySolution.Module.Win and MySolution.Module.Web). Right-click the newly created Application Server project and choose Add reference…. In the invoked dialog, switch to the Projects tab, select module projects and click OK. Add platform-dependent modules to the ServerApplication.Modules collection. Adding of the platform-agnostic module is not required because platform-dependent modules include it.
  • The network port to be listened to by the server. This setting is provided by the ServiceHost.AddServiceEndpoint method in the address parameter.

The snippet below illustrates these modifications in the Program.cs (Program.vb) file.

static void Main(string[] args) {
    try {
        // ...
        ServerApplication serverApplication = new ServerApplication();
        serverApplication.ApplicationName = "MySolution";

        serverApplication.Modules.BeginInit();
        serverApplication.Modules.Add(new DevExpress.ExpressApp.Security.SecurityModule());
        serverApplication.Modules.Add(new MySolution.Module.Win.MySolutionWindowsFormsModule());
        serverApplication.Modules.Add(new MySolution.Module.Win.MySolutionAspNetModule());
        serverApplication.Modules.EndInit();

        // ...
        Func dataServerSecurityProvider = () => {
            SecurityStrategyComplex security = new SecurityStrategyComplex(
                typeof(PermissionPolicyUser), typeof(PermissionPolicyRole), new AuthenticationStandard());
            security.SupportNavigationPermissionsForTypes = false;
            return security;
        };
        serviceHost = new WcfXafServiceHost(connectionString, dataServerSecurityProvider);
        serviceHost.AddServiceEndpoint(typeof(IWcfXafDataServer), 
            WcfDataServerHelper.CreateNetTcpBinding(), "net.tcp://localhost:1451/DataServer");
        serviceHost.Open();
        // ...
    }
    catch(Exception e) {
        Console.WriteLine("Exception occurs: " + e.Message);
        Console.WriteLine("Press Enter to close.");
        Console.ReadLine();
    }
}

Tip

Remember to add the required references to your module projects (e.g., MySolution.Module.Win and MySolution.Module.Web). Right-click the newly created Application Server project and choose Add reference…. In the invoked dialog, switch to the Projects tab, select module projects and click OK.

Note

Finally, provide the connection string that will be used to access your database server in the App.config file.

<?xml version="1.0"?>
<configuration>
  <connectionStrings>
    <add name="ConnectionString" connectionString=
        "Integrated Security=SSPI;Pooling=false;
        Data Source=.\SQLEXPRESS;Initial Catalog=MySolution" />
  </connectionStrings>
</configuration>

Configure the Client

In contrast to client-side security, we will perform all configurations in code, without the use of the application designer. To configure the Windows Forms application, add a reference to System.ServiceModel.dll and DevExpress.ExpressApp.Security.v18.1.dll assemblies, and modify the Program.cs (Program.vb) file.

using System.ServiceModel;
using DevExpress.ExpressApp.Security.ClientServer.Wcf;
// ...  
string connectionString = "net.tcp://localhost:1451/DataServer";
winApplication.DatabaseUpdateMode = DatabaseUpdateMode.Never;
WcfSecuredClient wcfSecuredClient = new WcfSecuredClient(WcfDataServerHelper.CreateNetTcpBinding(), new EndpointAddress(connectionString));
MiddleTierClientSecurity security = new MiddleTierClientSecurity(wcfSecuredClient);
security.IsSupportChangePassword = true;
winApplication.Security = security;
winApplication.CreateCustomObjectSpaceProvider +=
    delegate(object sender, CreateCustomObjectSpaceProviderEventArgs e) {
        e.ObjectSpaceProvider = new MiddleTierServerObjectSpaceProvider(wcfSecuredClient);
    };
winApplication.Setup();
winApplication.Start();
wcfSecuredClient.Dispose();

The ServerSecurityClient.IsSupportChangePassword property indicates whether or not user passwords can be changed using the ChangePasswordByUser and ResetPasswords Actions. If the AuthenticationStandard authentication is used at the server side, set this property to true. If the AuthenticationActiveDirectory is in use, there is no need to initialize the IsSupportChangePassword property as its default value is false. Note that this setting only influences the visibility of the ChangePasswordByUser and ResetPasswords Actions, and do not grant a write permission to the user’s StoredPassword property. Create the corresponding member-level permission to allow non-administrative users to change their passwords.

Note

While debugging, the server host name is “localhost” in the connection string. Change the port number according to the server-side setting. You can also read the connection string from the configuration file using the ConfigurationManager object (as it is done in the default application project). Here, the connection is hardcoded for the sake of simplicity.

When the application server is in use, the compatibility check is performed at the server side. You should unconditionally throw an exception when the XafApplication.DatabaseVersionMismatch event occurs. Edit WinApplication.cs (WinApplication.vb) and WebApplication.cs (WebApplication.vb) files as follows.

public partial class MySolutionWindowsFormsApplication : WinApplication {
    //...
   private void MySolutionWindowsFormsApplication_DatabaseVersionMismatch(
        object sender, DevExpress.ExpressApp.DatabaseVersionMismatchEventArgs e) {
        throw new InvalidOperationException(
            "The application cannot connect to the specified database " +
            "because the latter does not exist or its version is older " +
            "than that of the application.");
        }
    }
}

Register types used by security within a platform-agnostic module. Edit the Module.cs (Module.vb) file in the following manner.

using DevExpress.Persistent.BaseImpl.PermissionPolicy;
// ...
public sealed partial class MySolutionModule : ModuleBase {
    // ...
    protected override IEnumerable<Type> GetDeclaredExportedTypes() {
        List<Type> result = new List<Type>(base.GetDeclaredExportedTypes());
        result.AddRange(new Type[] { typeof(PermissionPolicyUser), typeof(PermissionPolicyRole) });
        return result;
    }
}

A reference to the DevExpress.ExpressApp.Security.v18.1 assembly is required to compile the code above.

Important

The application server does not pass the currently used role type to the client. This is the designed behavior. That is why the Role navigation item is not available by default. To add it, use the approach described in the Add an Item to the Navigation Control topic. (The required List View identifier is “PermissionPolicyRole_ListView” by default.)

Run both the Server and the Client.

Set the Application Server project as a startup in the Solution Explorer and run the server. You will see the console window with the following output:

Starting...

Setup...

CheckCompatibility...

Starting server...

Server is started. Press Enter to stop.

Note

If a Windows Security Alert dialog is also displayed, click Allow access within this dialog.

To run the client application, right-click the application project within the Solution Explorer and choose Debug | Start new instance. The image below illustrates the server and client.

ClientServer_Wcf_StandardAuth

Display Server-Side Exception Details in the Client Application

For debugging purposes, you may wish to enable the passing of server error information to the client. This will allow you to debug errors like “The server was unable to process the request due to an internal error“. Modify the ServiceHost object initialization in the following manner.

WcfXafServiceHost serviceHost = new WcfXafServiceHost(connectionString, dataServerSecurityProvider);
ServiceDebugBehavior debug = serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>();
if(debug == null) {
    serviceHost.Description.Behaviors.Add(
    new ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true });
}
else {
    if(!debug.IncludeExceptionDetailInFaults) {
        debug.IncludeExceptionDetailInFaults = true;
    }
}

Use this code only when debugging. Remove it before deploying your service to the production environment. For details, refer to the ServiceBehaviorAttribute.IncludeExceptionDetailInFaults Property topic in MSDN.

Troubleshooting

If “The application cannot connect to the specified database” error occurs at the client, please ensure that both client and server have the same modules set. Refer to the Visual Studio Output window content or see the client application log (eXpressAppFramework.log). For instance, the following message indicates that the SystemAspNetModule module is not added to the server’s Modules collection. (The missing module version is displayed as “0.0.0.0”.)

module 'SystemAspNetModule' (DevExpress.ExpressApp.Web.v18.1). Local version: 18.1.1.0, Version on DB: 0.0.0.0

To fix the issue, add this module to the ServerApplication.Modules collection as shown in the Create and Configure the Server section of this topic.

See Also