最终实现效果:
作为XAF学习的第二节,仅仅学习了BO的知识可能难度稍大,只需要按照步骤一步一步完成相关知识后续讲解
1、创建项目时,按下图设置我们可以得到一个默认权限的项目
2、打开web项目或win项目下的WinApplication.cs文件
我们可以看到系统自带了2个验证器,此2个验证器是默认的登录窗体
对应下方登录页面
3、项目*.Modeule下BusinessObjects文件夹下创建Employee、Company 的BO对象
using DevExpress.Xpo;
using DevExpress.ExpressApp.DC;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl.PermissionPolicy;
[DefaultClassOptions]
[XafDefaultProperty("UserName"), XafDisplayName("员工")]
public class Employee : PermissionPolicyUser
{
public Employee(Session session) : base(session) { }
private Company company;
[Association("Company-Employees")]
[XafDisplayName("公司")]
public Company Company
{
get { return company; }
set { SetPropertyValue("Company", ref company, value); }
}
}
using DevExpress.Xpo;
using DevExpress.ExpressApp.DC;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
[DefaultClassOptions]
[XafDisplayName("公司"), XafDefaultProperty("Name")]
public class Company : BaseObject
{
public Company(Session session) : base(session) { }
private string name;
[XafDisplayName("名称")]
public string Name
{
get { return name; }
set { SetPropertyValue("Name", ref name, value); }
}
[Association("Company-Employees")]
public XPCollection<Employee> Employees
{
get { return GetCollection<Employee>("Employees"); }
}
}
4、项目*.Modeule下添加参数类CustomLogonParameters.cs、CustomAuthentication.cs
using System;
using System.ComponentModel;
using System.Runtime.Serialization;
using DevExpress.ExpressApp.DC;
using DevExpress.Persistent.Base;
//……
[DomainComponent, Serializable]
[System.ComponentModel.DisplayName("登录")] //登录标题
public class CustomLogonParameters : INotifyPropertyChanged, ISerializable
{
#region 构造方法
public CustomLogonParameters() { }
//ISerializable,序列化
public CustomLogonParameters(SerializationInfo info, StreamingContext context)
{
if (info.MemberCount > 0)
{
UserName = info.GetString("UserName");
Password = info.GetString("Password");
}
}
#endregion
private Company company; //公司
private Employee employee; //员工
private string password; //密码
[ImmediatePostData] //值应该尽快传递给绑定对象,但用户更改值时,允许强制更新
[XafDisplayName("公司")]
public Company Company
{
get { return company; }
set
{
if (value == company) return;
company = value;
Employee = null;
OnPropertyChanged("Company");
}
}
[DataSourceProperty("Company.Employees")]
[ImmediatePostData] //值应该尽快传递给绑定对象,但用户更改值时,允许强制更新
[XafDisplayName("员工")]
public Employee Employee
{
get { return employee; }
set
{
if (Company == null) return;
employee = value;
if (employee != null)
{
UserName = employee.UserName;
}
OnPropertyChanged("Employee");
}
}
[Browsable(false)] //用户名在登录页面不显示
[XafDisplayName("用户名")]
public String UserName { get; set; }
[PasswordPropertyText(true)]
[XafDisplayName("密码")]
public string Password
{
get { return password; }
set
{
if (password == value) { return; }
password = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
//属性更改时引发事件页面上能快速更改事件)
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
[System.Security.SecurityCritical]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("UserName", UserName);
info.AddValue("Password", Password);
}
}
//……
using System;
using DevExpress.ExpressApp;
using DevExpress.Data.Filtering;
using System.Collections.Generic;
using DevExpress.ExpressApp.Security;
//……
/// <summary>
/// 自定义登录参数类
/// </summary>
public class CustomAuthentication : AuthenticationBase, IAuthenticationStandard
{
private CustomLogonParameters customLogonParameters; //登录参数
public CustomAuthentication()
{
customLogonParameters = new CustomLogonParameters();
}
/// <summary>
/// 注销
/// </summary>
public override void Logoff()
{
base.Logoff();
customLogonParameters = new CustomLogonParameters();
}
/// <summary>
/// 重置登录参数
/// </summary>
public override void ClearSecuredLogonParameters()
{
customLogonParameters.Password = "";
base.ClearSecuredLogonParameters();
}
/// <summary>
/// 通过比较登录参数与数据库中用户对象的值,进行验证。
///
/// </summary>
/// <param name="objectSpace">用户数据操作对象空间</param>
/// <returns>经身份验证的用户</returns>
public override object Authenticate(IObjectSpace objectSpace)
{
Employee employee = objectSpace.FindObject<Employee>(new BinaryOperator("UserName", customLogonParameters.UserName));
if (employee == null)
{
throw new ArgumentNullException("Employee");
}
if (!employee.ComparePassword(customLogonParameters.Password))
{
throw new AuthenticationException(employee.UserName, "密码错误.");
}
return employee;
}
/// <summary>
/// 初始化登录参数
/// </summary>
/// <param name="logonParameters">登录参数</param>
public override void SetLogonParameters(object logonParameters)
{
this.customLogonParameters = (CustomLogonParameters)logonParameters;
}
/// <summary>
/// 返回到要添加程序的应用列表
/// </summary>
/// <returns></returns>
public override IList<Type> GetBusinessClasses()
{
return new Type[] { typeof(CustomLogonParameters) };
}
/// <summary>
/// 指示登录过程是否是交互式的(通过登录对话框请求登录参数)
/// </summary>
public override bool AskLogonParametersViaUI
{
get { return true; }
}
/// <summary>
/// 返回登录参数
/// </summary>
public override object LogonParameters
{
get { return customLogonParameters; }
}
/// <summary>
/// 是否启用注销方法,继承AuthenticationBase
/// </summary>
public override bool IsLogoffEnabled
{
get { return true; }
}
}
//……
5、重新打开.Win项目下的WinApplication.cs文件,web版类似
已经发现我们添加的文件,拖拽替换系统自带的对象
替换后:
对 更改验证Model
6、修改Win项目的启动文件Program.cs 及WinApplication.cs
Program.cs
添加1个方法
private static void application_CreateCustomLogonWindowObjectSpace(object sender, CreateCustomLogonWindowObjectSpaceEventArgs e)
{
e.ObjectSpace = ((XafApplication)sender).CreateObjectSpace(typeof(CustomLogonParameters));
if (e.ObjectSpace is NonPersistentObjectSpace)
{
IObjectSpace objectSpaceCompany = ((XafApplication)sender).CreateObjectSpace(typeof(Company));
((NonPersistentObjectSpace)e.ObjectSpace).AdditionalObjectSpaces.Add(objectSpaceCompany);
}
}
在Main函数中调用,应在 winApplication.Setup(); winApplication.Start();代码前添加
winApplication.CreateCustomLogonWindowObjectSpace += application_CreateCustomLogonWindowObjectSpace;
完整版本如下:
using System;
using System.Configuration;
using System.Windows.Forms;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Security;
using DevExpress.ExpressApp.Win;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
using DevExpress.XtraEditors;
namespace DXApplication1cc.Win {
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
DevExpress.ExpressApp.FrameworkSettings.DefaultSettingsCompatibilityMode = DevExpress.ExpressApp.FrameworkSettingsCompatibilityMode.Latest;
#if EASYTEST
DevExpress.ExpressApp.Win.EasyTest.EasyTestRemotingRegistration.Register();
#endif
WindowsFormsSettings.LoadApplicationSettings();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
DevExpress.Utils.ToolTipController.DefaultController.ToolTipType = DevExpress.Utils.ToolTipType.SuperTip;
EditModelPermission.AlwaysGranted = System.Diagnostics.Debugger.IsAttached;
if(Tracing.GetFileLocationFromSettings() == DevExpress.Persistent.Base.FileLocation.CurrentUserApplicationDataFolder) {
Tracing.LocalUserAppDataPath = Application.LocalUserAppDataPath;
}
Tracing.Initialize();
DXApplication1ccWindowsFormsApplication winApplication = new DXApplication1ccWindowsFormsApplication();
winApplication.GetSecurityStrategy().RegisterXPOAdapterProviders();
if(ConfigurationManager.ConnectionStrings["ConnectionString"] != null) {
winApplication.ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
}
#if EASYTEST
if(ConfigurationManager.ConnectionStrings["EasyTestConnectionString"] != null) {
winApplication.ConnectionString = ConfigurationManager.ConnectionStrings["EasyTestConnectionString"].ConnectionString;
}
#endif
#if DEBUG
if(System.Diagnostics.Debugger.IsAttached && winApplication.CheckCompatibilityType == CheckCompatibilityType.DatabaseSchema) {
winApplication.DatabaseUpdateMode = DatabaseUpdateMode.UpdateDatabaseAlways;
}
#endif
winApplication.CreateCustomLogonWindowObjectSpace += application_CreateCustomLogonWindowObjectSpace;
try {
winApplication.Setup();
winApplication.Start();
}
catch(Exception e) {
winApplication.StopSplash();
winApplication.HandleException(e);
}
}
private static void application_CreateCustomLogonWindowObjectSpace(object sender, CreateCustomLogonWindowObjectSpaceEventArgs e)
{
e.ObjectSpace = ((XafApplication)sender).CreateObjectSpace(typeof(CustomLogonParameters));
if (e.ObjectSpace is NonPersistentObjectSpace)
{
IObjectSpace objectSpaceCompany = ((XafApplication)sender).CreateObjectSpace(typeof(Company));
((NonPersistentObjectSpace)e.ObjectSpace).AdditionalObjectSpaces.Add(objectSpaceCompany);
}
}
}
}
WinApplication.cs ,打开后右键查看代码
替换CreateDefaultObjectSpaceProvider方法内的内容为:
//允许在登录窗口中访问公司、员工数据
((SecurityStrategy)Security).AnonymousAllowedTypes.Add(typeof(Company));
((SecurityStrategy)Security).AnonymousAllowedTypes.Add(typeof(Employee));
args.ObjectSpaceProviders.Add(new XPObjectSpaceProvider(args.ConnectionString, args.Connection, false));
args.ObjectSpaceProviders.Add(new NonPersistentObjectSpaceProvider(TypesInfo, null));
6.1 Web版本(基本与Win类似)
修改文件Global.asax文件
using CustomLogonParametersExample.Module;
using CustomLogonParametersExample.Module.BusinessObjects;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Web;
// ...
public class Global : System.Web.HttpApplication {
// ...
protected void Session_Start(Object sender, EventArgs e) {
// ...
WebApplication.Instance.CreateCustomLogonWindowObjectSpace +=
application_CreateCustomLogonWindowObjectSpace;
WebApplication.Instance.Setup();
// ...
}
private static void application_CreateCustomLogonWindowObjectSpace(object sender,
CreateCustomLogonWindowObjectSpaceEventArgs e) {
e.ObjectSpace = ((XafApplication)sender).CreateObjectSpace(typeof(CustomLogonParameters));
if (e.ObjectSpace is NonPersistentObjectSpace) {
IObjectSpace objectSpaceCompany = ((XafApplication)sender).CreateObjectSpace(typeof(Company));
((NonPersistentObjectSpace)e.ObjectSpace).AdditionalObjectSpaces.Add(objectSpaceCompany);
}
}
}
修改WebApplication.cs文件
using System;
using System.Collections.Generic;
using CustomLogonParametersExample.Module;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using DevExpress.ExpressApp.Xpo;
using DevExpress.ExpressApp.Web;
// ...
public partial class CustomLogonParametersExampleAspNetApplication : WebApplication {
private static NonPersistentTypeInfoSource nonPersistentTypeInfoSource;
// ...
protected override void CreateDefaultObjectSpaceProvider(CreateCustomObjectSpaceProviderEventArgs args) {
args.ObjectSpaceProvider =
new XPObjectSpaceProvider(GetDataStoreProvider(args.ConnectionString, args.Connection), true);
if (nonPersistentTypeInfoSource == null) {
nonPersistentTypeInfoSource = new NonPersistentTypeInfoSource(TypesInfo, new List<Type>()
{ typeof(CustomLogonParameters) });
}
args.ObjectSpaceProviders.Add(new NonPersistentObjectSpaceProvider(TypesInfo,
nonPersistentTypeInfoSource));
}
}
7、到此为止项目已经可以正常启动为了方便使用修改.Module项目下的DatabaseUpdate文件夹内的Updater.cs实现内置一些数据
在UpdateDatabaseAfterUpdateSchema方法内的 base.UpdateDatabaseAfterUpdateSchema();后追加
PermissionPolicyRole administrativeRole = ObjectSpace.FindObject<PermissionPolicyRole>(
new BinaryOperator("Name", SecurityStrategy.AdministratorRoleName));
if (administrativeRole == null)
{
administrativeRole = ObjectSpace.CreateObject<PermissionPolicyRole>();
administrativeRole.Name = SecurityStrategy.AdministratorRoleName;
administrativeRole.IsAdministrative = true;
}
const string adminName = "Administrator";
Employee administratorUser = ObjectSpace.FindObject<Employee>(
new BinaryOperator("UserName", adminName));
if (administratorUser == null)
{
administratorUser = ObjectSpace.CreateObject<Employee>();
administratorUser.UserName = adminName;
administratorUser.IsActive = true;
administratorUser.SetPassword("");
administratorUser.Roles.Add(administrativeRole);
}
PermissionPolicyRole userRole = ObjectSpace.FindObject<PermissionPolicyRole>(
new BinaryOperator("Name", "User"));
if (userRole == null)
{
userRole = ObjectSpace.CreateObject<PermissionPolicyRole>();
userRole.Name = "User";
userRole.AddTypePermission<Employee>(
SecurityOperations.ReadOnlyAccess, SecurityPermissionState.Allow);
userRole.AddTypePermission<Company>(
SecurityOperations.ReadOnlyAccess, SecurityPermissionState.Allow);
}
if (ObjectSpace.FindObject<Company>(null) == null)
{
Company company1 = ObjectSpace.CreateObject<Company>();
company1.Name = "Company 1";
company1.Employees.Add(administratorUser);
}
ObjectSpace.CommitChanges();
8、启动项目查看界面
9、发现问题:如何关闭“下拉时选择公司或员工的New按钮”
打开Win项目下的Model.xaml文件按步骤修改
员工(Employee)和公司(Company)的LookupListView视图的AllowNew属性为Fals
问题解决