将Abp移植进.NET MAUI项目(二):配置与基类编写


?

 因为我们要做一个数据持久化型的小应用,所以在完成Abp功能的集成后,我们需要做数据库相关的配置工作

配置数据库

在MauiBoilerplate.Core项目中,添加两个实体类:

我们简单的写一个歌曲(song)的实体类

其中包含了歌曲标题(MusicTitle),艺术家(Artist),专辑(Album),时长(Duration)以及发售日期(ReleaseDate)

    public class Song : FullAuditedEntity<long>
    {
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public override long Id { get; set; }

        public string MusicTitle { get; set; }

        public string Artist { get; set; }

        public string Album { get; set; }

        public TimeSpan Duration { get; set; }

        public DateTime ReleaseDate { get; set; }

    }

在MauiBoilerplate.EntityFrameworkCore项目中:将这个类添加至MauiBoilerplateDbContext中

public class MauiBoilerplateDbContext : AbpDbContext
{
     //Add DbSet properties for your entities...
     public DbSet Song { get; set; }
}

 新建WithDbContextHelper.cs

创建一个静态类WithDbContext,利用Abp的工作单元模式对dbcontext执行操作

    public class WithDbContextHelper
    {
        public static void WithDbContext<TDbContext>(IIocResolver iocResolver, Action contextAction)
    where TDbContext : DbContext
        {
            using (var uowManager = iocResolver.ResolveAsDisposable())
            {
                using (var uow = uowManager.Object.Begin(TransactionScopeOption.Suppress))
                {
                    var context = uowManager.Object.Current.GetDbContext();

                    contextAction(context);

                    uow.Complete();
                }
            }
        }

    }

[可选]种子数据相关类编写

编写种子数据帮助类SeedHelper.cs,与数据库初始化类InitialDbBuilder,这里将在程序启动时向数据库插入一些种子数据

    public static class SeedHelper
    {
        public static void SeedHostDb(IIocResolver iocResolver)
        {
            Helper.WithDbContextHelper.WithDbContext(iocResolver, SeedHostDb);
        }

        public static void SeedHostDb(MauiBoilerplateDbContext context)
        {
            context.SuppressAutoSetTenantId = true;

            // Host seed
            new InitialDbBuilder(context).Create();
        }

    }

编写MauiBoilerplateEntityFrameworkCoreModule.cs

    [DependsOn(
        typeof(MauiBoilerplateCoreModule), 
        typeof(AbpEntityFrameworkCoreModule))]
    public class MauiBoilerplateEntityFrameworkCoreModule : AbpModule
    {
        public bool SkipDbContextRegistration { get; set; }

        public bool SkipDbSeed { get; set; }

        public override void PreInitialize()
        {
            if (!SkipDbContextRegistration)
            {
                Configuration.Modules.AbpEfCore().AddDbContext(options =>
                {
                    if (options.ExistingConnection != null)
                    {
                        DbContextOptionsConfigurer.Configure(options.DbContextOptions, options.ExistingConnection);
                    }
                    else
                    {
                        DbContextOptionsConfigurer.Configure(options.DbContextOptions, options.ConnectionString);
                    }
                });
            }
        }
        public override void Initialize()
        {
 
            IocManager.RegisterAssemblyByConvention(typeof(MauiBoilerplateEntityFrameworkCoreModule).GetAssembly());
            
        }

        public override void PostInitialize()
        {
            Helper.WithDbContextHelper.WithDbContext(IocManager, RunMigrate);
            if (!SkipDbSeed)
            {
                SeedHelper.SeedHostDb(IocManager);
            }
        }

        public static void RunMigrate(MauiBoilerplateDbContext dbContext)
        {
            dbContext.Database.Migrate();
        }


    }

将MauiBoilerplate.EntityFrameworkCore设置为启动项目,选择框架为.net6.0

打开程序包管理器控制台,选择默认项目MauiBoilerplate.EntityFrameworkCore

?编辑

 运行Add-Migration命令,将生成迁移脚本

运行MauiBoilerplate.EntityFrameworkCore,将生成mato.db等三个文件,

?编辑

编写基类(可选)

我们在使用相关的父类时,某某ContentPage,或者某某UserControl时,需要像使用AbpServiceBase一样使用一些常用的功能,比如字符串的本地化,配置,AutoMapper对象等,就像AbpServiceBase的注释里描述的那样:

    ///


    /// This class can be used as a base class for services.
    /// It has some useful objects property-injected and has some basic methods
    /// most of services may need to.
    ///

此时,需要编写一个基类(奈何.net本身没有Mixin模式,C#语言也不支持多继承),这些基类仅是注入了一些常用的Manager,方便代码编写者使用,因此基类的创建不是必须的。

比如可以增加一个ContentPageBase类作为ContentPage实例控件的基类

新建ContentPageBase.cs文件,创建类ContentPageBase继承于ContentPage

    public class ContentPageBase : ContentPage
    {
        public IObjectMapper ObjectMapper { get; set; }


        /// 
        /// Reference to the setting manager.
        /// 
        public ISettingManager SettingManager { get; set; }


        /// 
        /// Reference to the localization manager.
        /// 
        public ILocalizationManager LocalizationManager { get; set; }

        /// 
        /// Gets/sets name of the localization source that is used in this application service.
        /// It must be set in order to use  and  methods.
        /// 
        protected string LocalizationSourceName { get; set; }

        /// 
        /// Gets localization source.
        /// It's valid if  is set.
        /// 
        protected ILocalizationSource LocalizationSource
        {
            get
            {
                if (LocalizationSourceName == null)
                {
                    throw new AbpException("Must set LocalizationSourceName before, in order to get LocalizationSource");
                }

                if (_localizationSource == null || _localizationSource.Name != LocalizationSourceName)
                {
                    _localizationSource = LocalizationManager.GetSource(LocalizationSourceName);
                }

                return _localizationSource;
            }
        }
        private ILocalizationSource _localizationSource;


        /// 
        /// Constructor.
        /// 
        protected ContentPageBase()
        {
            LocalizationSourceName = MauiBoilerplateConsts.LocalizationSourceName;
            ObjectMapper = NullObjectMapper.Instance;
            LocalizationManager = NullLocalizationManager.Instance;
        }

        /// 
        /// Gets localized string for given key name and current language.
        /// 
        /// Key name
        /// Localized string
        protected virtual string L(string name)
        {
            return LocalizationSource.GetString(name);
        }

        /// 
        /// Gets localized string for given key name and current language with formatting strings.
        /// 
        /// Key name
        /// Format arguments
        /// Localized string
        protected virtual string L(string name, params object[] args)
        {
            return LocalizationSource.GetString(name, args);
        }

        /// 
        /// Gets localized string for given key name and specified culture information.
        /// 
        /// Key name
        /// culture information
        /// Localized string
        protected virtual string L(string name, CultureInfo culture)
        {
            return LocalizationSource.GetString(name, culture);
        }

        /// 
        /// Gets localized string for given key name and current language with formatting strings.
        /// 
        /// Key name
        /// culture information
        /// Format arguments
        /// Localized string
        protected virtual string L(string name, CultureInfo culture, params object[] args)
        {
            return LocalizationSource.GetString(name, culture, args);
        }
    }

同理,若我们使用了其他控件类时,可以增加一个Base类作为实例控件的基类的

比如Popup控件,就编写一个PopupBase基类。

在这里我们编写了两个基类

?编辑

 本地化配置

新建一个TranslateExtension.cs作为Xaml标签的本地化处理类

    [ContentProperty("Text")]
    public class TranslateExtension : DomainService, IMarkupExtension
    {
        public TranslateExtension()
        {
            LocalizationSourceName = MauiBoilerplateConsts.LocalizationSourceName;

        }
        public string Text { get; set; }

        public object ProvideValue(IServiceProvider serviceProvider)
        {
            if (Text == null)
                return "";
            var translation = L(Text);          
            return translation;
        }



    }

在MauiBoilerplateLocalization.cs配置好SourceFiles 

    public static void Configure(ILocalizationConfiguration localizationConfiguration)
        {
            localizationConfiguration.Sources.Add(
                new DictionaryBasedLocalizationSource(MauiBoilerplateConsts.LocalizationSourceName,
                    new XmlEmbeddedFileLocalizationDictionaryProvider(
                        typeof(LocalizationConfigurer).GetAssembly(),
                        "MauiBoilerplate.Core.Localization.SourceFiles"
                    )
                )
            );
        }

编写ViewModelBase

为实现Mvvm设计模式,页面需要绑定一个继承于ViewModelBase的类型

在ViewModelBase中,需要实现INotifyPropertyChanged以处理绑定成员变化时候的通知消息;

ViewModelBase集成于AbpServiceBase以方便ViewModel代码编写者使用常用的功能,比如字符串的本地化,配置,AutoMapper对象等。

    public abstract class ViewModelBase : AbpServiceBase, ISingletonDependency, INotifyPropertyChanged
    {
        public ViewModelBase()
        {
            LocalizationSourceName = MauiBoilerplateConsts.LocalizationSourceName;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected PropertyChangedEventHandler PropertyChangedHandler { get; }

        public void VerifyPropertyName(string propertyName)
        {
            Type type = GetType();
            if (!string.IsNullOrEmpty(propertyName) && type.GetTypeInfo().GetDeclaredProperty(propertyName) == null)
                throw new ArgumentException("找不到属性", propertyName);
        }

        public virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler propertyChanged = PropertyChanged;
            if (propertyChanged == null)
                return;
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public virtual void RaisePropertyChanged<T>(Expression> propertyExpression)
        {
            if (PropertyChanged == null)
                return;
            string propertyName = GetPropertyName(propertyExpression);
            if (string.IsNullOrEmpty(propertyName))
                return;
            RaisePropertyChanged(propertyName);
        }

        protected static string GetPropertyName<T>(Expression> propertyExpression)
        {
            if (propertyExpression == null)
                throw new ArgumentNullException(nameof(propertyExpression));
            MemberExpression body = propertyExpression.Body as MemberExpression;
            if (body == null)
                throw new ArgumentException("参数不合法", nameof(propertyExpression));
            PropertyInfo member = body.Member as PropertyInfo;
            if (member == null)
                throw new ArgumentException("找不到属性", nameof(propertyExpression));
            return member.Name;
        }

    }

至此,我们完成了数据库的配置,内容页基类与 ViewModel基类的编写,接下来可以制作我们的页面了。请看下一章

 项目地址

jevonsflash/maui-abp-sample (github.com)

?