本主題描述瞭如何實現一個 WCF 中間層應用程式伺服器及如何配置 XAF客戶端連接到此伺服器。 註意 本主題演示可以由解決方案嚮導自動生成的代碼。執行操作時,如果你想要在現有的 XAF 解決方案中實現的顯示的功能。如果您要創建一個新的 XAF 解決方案,請使用嚮導。 完整的樣例項目是在 http:/
本主題描述了如何實現一個 WCF 中間層應用程式伺服器及如何配置 XAF客戶端連接到此伺服器。
1.打開現有的 XAF 解決方案,啟用新的安全系統,創建幾個用戶帳戶。如果您沒有此現有的解決方案,看這裡如何創建一個基於客戶端的安全 (2 層架構) 教程。 2.向 XAF 解決方案中添加一個控制台應用程式項目。這個項目將代表在此示例中的應用程式伺服器。 3.將引用添加到您的 XAF 解決方案 (例如,MySolution.Module、 MySolution.Module.Win 和 MySolution.Module.Web) 的模塊項目。右鍵項目,單擊創建新項目,然後在對話框中選擇“添加引用......” ,切換到項目選項卡,選擇模塊項目,並單擊確定。
4.打開新創建的項目的 Program.cs (Program.vb) 文件。將以下代碼添加到 Main 方法 (在此示例中,假定您的 XAF 解決方案稱為"MySolution")。
using System; using System.Collections.Generic; using System.ServiceModel; using DevExpress.Persistent.Base; using DevExpress.Xpo; using DevExpress.Xpo.DB; using DevExpress.ExpressApp; using DevExpress.ExpressApp.MiddleTier; using DevExpress.ExpressApp.Security; using DevExpress.ExpressApp.Security.ClientServer; using DevExpress.ExpressApp.Security.ClientServer.Wcf; using DevExpress.ExpressApp.Security.Strategy; using DevExpress.ExpressApp.Web.SystemModule; using DevExpress.ExpressApp.Win.SystemModule; using DevExpress.ExpressApp.Xpo; // ... static void Main() { try { Console.WriteLine("Starting..."); DataSet dataSet = new DataSet(); string connectionString = "Integrated Security=SSPI;Pooling=false;Data Source=(local);Initial Catalog=MySolution"; ValueManager.ValueManagerType = typeof(MultiThreadValueManager<>).GetGenericTypeDefinition(); ServerApplication serverApplication = new ServerApplication(); serverApplication.ApplicationName = "MySolution"; serverApplication.Modules.Add(new MySolution.Module.MySolutionModule()); serverApplication.Modules.Add(new SystemWindowsFormsModule()); serverApplication.Modules.Add(new SystemAspNetModule()); serverApplication.CreateCustomObjectSpaceProvider += delegate(object sender, CreateCustomObjectSpaceProviderEventArgs e) { e.ObjectSpaceProvider = new XPObjectSpaceProvider(connectionString, null); }; serverApplication.DatabaseVersionMismatch += delegate(object sender, DatabaseVersionMismatchEventArgs e) { e.Updater.Update(); e.Handled = true; }; Console.WriteLine("Setup..."); serverApplication.Setup(); Console.WriteLine("CheckCompatibility..."); serverApplication.CheckCompatibility(); serverApplication.Dispose(); Console.WriteLine("Starting server..."); QueryRequestSecurityStrategyHandler securityProviderHandler = delegate() { return new SecurityStrategyComplex( typeof(SecuritySystemUser), typeof(SecuritySystemRole), new AuthenticationStandard()); }; IDisposable[] disposable; IDataLayer dataLayer = new SimpleDataLayer(XpoTypesInfoHelper.GetXpoTypeInfoSource().XPDictionary, DevExpress.Xpo.DB.MSSqlConnectionProvider.CreateProviderFromString(connectionString, DevExpress.Xpo.DB.AutoCreateOption.None, out disposable)); SecuredDataServer dataServer = new SecuredDataServer(dataLayer, securityProviderHandler); ServiceHost serviceHost = new ServiceHost(new WcfSecuredDataServer(dataServer)); serviceHost.AddServiceEndpoint(typeof(IWcfSecuredDataServer), WcfDataServerHelper.CreateDefaultBinding(), "http://localhost:1451/DataServer"); serviceHost.Open(); Console.WriteLine("Server is started. Press Enter to stop."); Console.ReadLine(); Console.WriteLine("Stopping..."); serviceHost.Close(); Console.WriteLine("Server is stopped."); } catch(Exception e) { Console.WriteLine("Exception occurs: " + e.Message); Console.WriteLine("Press Enter to close."); Console.ReadLine(); } }
註意
- ServerApplication.ApplicationName 屬性值是客戶端應用程式的名稱 (即 XafApplication.ApplicationName) 相同。
- ServerApplication.Modules 集合應包含由客戶端應用程式直接引用的模塊。要查看哪些客戶端應用程式要求哪些模塊,可以在 WinApplication/WebApplication 的InitializeComponent方法中找到。
- QueryRequestSecurityStrategyHandler 對象指定了用戶類型、 角色類型和身份驗證。
- 服務終結點是通過 ServiceHost.AddServiceEndpoint 方法添加的。
- 如果您使用自定義許可權請求和自定義登錄參數,在用戶初始化數據伺服器之前註冊通過靜態的 WcfDataServerHelper.AddKnownType 方法。
- 如果您想要使用一個自定義的綁定對象,不要使用 WcfDataServerHelper.CreateDefaultBinding 方法。自己創建所需的綁定對象並將它傳遞給ServiceHost.AddServiceEndpoint 方法。
-
當使用 AuthenticationActiveDirectory 時, all the methods of the application server should be invoked in the caller's context (a Windows account under which the client application is running). Refer to the Delegation and Impersonation with WCF and Security in Remoting articles in MSDN for more details on how this can be done, depending on the transport technology used. For instance, in the case of WCF, you can modify the ServiceAuthorizationBehavior.ImpersonateCallerForAllOperations property in the code of your service.
- 打開 Windows 窗體應用程式項目的 Program.cs (Program.vb) 文件。修改 Main 方法,如下所示。
using System.ServiceModel; using DevExpress.ExpressApp; using DevExpress.ExpressApp.Security; using DevExpress.ExpressApp.Security.ClientServer; using DevExpress.ExpressApp.Security.ClientServer.Wcf; // ... [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); EditModelPermission.AlwaysGranted = System.Diagnostics.Debugger.IsAttached; MySolutionWindowsFormsApplication winApplication = new MySolutionWindowsFormsApplication(); string connectionString = "http://localhost:1451/DataServer"; try { WcfSecuredDataServerClient clientDataServer = new WcfSecuredDataServerClient( WcfDataServerHelper.CreateDefaultBinding(), new EndpointAddress(connectionString)); ServerSecurityClient securityClient = new ServerSecurityClient(clientDataServer, new ClientInfoFactory()); securityClient.IsSupportChangePassword = true; winApplication.ApplicationName = "MySolution"; winApplication.Security = securityClient; winApplication.CreateCustomObjectSpaceProvider += delegate( object sender, CreateCustomObjectSpaceProviderEventArgs e) { e.ObjectSpaceProvider = new DataServerObjectSpaceProvider(clientDataServer, securityClient); }; winApplication.Setup(); winApplication.Start(); clientDataServer.Close(); } catch(Exception e) { winApplication.HandleException(e); } }
-
ServerSecurityClient.IsSupportChangePassword 屬性指示可以通過 ChangePasswordByUser 和 ResetPasswords 操作更改用戶密碼。如果在伺服器端使用AuthenticationStandard 身份驗證,則將此屬性設置為 true。IfAuthenticationActiveDirectory 使用時,無需初始化的 IsSupportChangePassword 屬性,因為它的預設值為 false。請註意,此設置只會影響的 ChangePasswordByUser 和 ResetPasswords 操作的可見性,請不要授予寫許可權給用戶的 StoredPassword 屬性。創建相應的成員級別許可權,以允許非管理用戶更改他們的密碼。
-
備註:
在調試時,伺服器主機名是在連接字元串中的"localhost"。更改根據伺服器端設置的埠號。(因為它預設應用程式項目中完成的),您也可以從通過配置應用程式對象的配置文件讀取連接字元串。為簡單起見在這裡連接是硬編碼的。 如果您使用自定義許可權請求和自定義登錄參數,在用戶客戶端應用程式在初始化之前註冊通過靜態的 WcfDataServerHelper.AddKnownType 方法。
-
備註:
- 當應用程式伺服器正在使用中時,在伺服器端執行相容性檢查。在 XafApplication.DatabaseVersionMismatch 的事件發生時,應無條件地引發異常。編輯WinApplication.cs (WinApplication.vb) 文件,並按以下方式修改 DatabaseVersionMismatchevent 處理程式。
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."); } } }
-
編輯 Module.cs (Module.vb) 文件位於與平臺無關模塊項目(即你的XXX.Module項目)。註冊以下列方式使用的安全類型。(就是用戶和角色所使用的類型)
using DevExpress.ExpressApp.Security.Strategy; // ... public sealed partial class MySolutionModule : ModuleBase { // ... protected override IEnumerable<Type> GetDeclaredExportedTypes() { List<Type> result = new List<Type>(base.GetDeclaredExportedTypes()); result.AddRange(new Type[] { typeof(SecuritySystemUser), typeof(SecuritySystemRole) }); return result; } }
上面的代碼需要引用 DevExpress.ExpressApp.Security.v15.2 程式集。
預設情況下,導航欄中不會顯示角色的列表,這個行為與2層架構不同,如果想要顯示角色列表,需要手動的在xafml中增加角色列表,列表的名稱是:"SecuritySystemRole_ListView"。
現在你可以運行在應用伺服器和客戶端應用程式。在解決方案資源管理器中將應用程式伺服器項目設置為啟動項目,並且運行伺服器。要運行客戶端應用程式,右擊解決方案資源管理器中的應用程式項目,然後選擇調試 |啟動新實例。下圖顯示了伺服器和客戶端。