将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> Song { get; set; }
}

 新建WithDbContextHelper.cs

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

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

                contextAction(context);

                uow.Complete();
            }
        }
    }

}

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

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

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

    <span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-keyword">static <span class="hljs-keyword">void <span class="hljs-title">SeedHostDb(<span class="hljs-params">MauiBoilerplateDbContext context)
    {
        context.SuppressAutoSetTenantId = <span class="hljs-literal">true;

        <span class="hljs-comment">// Host seed
        <span class="hljs-keyword">new InitialDbBuilder(context).Create();
    }

}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>

 

编写MauiBoilerplateEntityFrameworkCoreModule.cs

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

    <span class="hljs-keyword">public <span class="hljs-built_in">bool SkipDbSeed { <span class="hljs-keyword">get; <span class="hljs-keyword">set; }

    <span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-keyword">override <span class="hljs-keyword">void <span class="hljs-title">PreInitialize()
    {
        <span class="hljs-keyword">if (!SkipDbContextRegistration)
        {
            Configuration.Modules.AbpEfCore().AddDbContext&lt;MauiBoilerplateDbContext&gt;(options =&gt;
            {
                <span class="hljs-keyword">if (options.ExistingConnection != <span class="hljs-literal">null)
                {
                    DbContextOptionsConfigurer.Configure(options.DbContextOptions, options.ExistingConnection);
                }
                <span class="hljs-keyword">else
                {
                    DbContextOptionsConfigurer.Configure(options.DbContextOptions, options.ConnectionString);
                }
            });
        }
    }
    <span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-keyword">override <span class="hljs-keyword">void <span class="hljs-title">Initialize()
    {

        IocManager.RegisterAssemblyByConvention(<span class="hljs-keyword">typeof(MauiBoilerplateEntityFrameworkCoreModule).GetAssembly());
        
    }

    <span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-keyword">override <span class="hljs-keyword">void <span class="hljs-title">PostInitialize()
    {
        Helper.WithDbContextHelper.WithDbContext&lt;MauiBoilerplateDbContext&gt;(IocManager, RunMigrate);
        <span class="hljs-keyword">if (!SkipDbSeed)
        {
            SeedHelper.SeedHostDb(IocManager);
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-keyword">static <span class="hljs-keyword">void <span class="hljs-title">RunMigrate(<span class="hljs-params">MauiBoilerplateDbContext dbContext)
    {
        dbContext.Database.Migrate();
    }


}

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

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

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

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

编写基类(可选)

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

    /// <summary>
    /// 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.
    /// </summary>

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

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

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

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


    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;summary&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// Reference to the setting manager.
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;/summary&gt;
    <span class="hljs-keyword">public ISettingManager SettingManager { <span class="hljs-keyword">get; <span class="hljs-keyword">set; }


    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;summary&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// Reference to the localization manager.
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;/summary&gt;
    <span class="hljs-keyword">public ILocalizationManager LocalizationManager { <span class="hljs-keyword">get; <span class="hljs-keyword">set; }

    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;summary&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// Gets/sets name of the localization source that is used in this application service.
    <span class="hljs-comment"><span class="hljs-doctag">/// It must be set in order to use <span class="hljs-doctag">&lt;see cref="L(string)"/&gt; and <span class="hljs-doctag">&lt;see cref="L(string,CultureInfo)"/&gt; methods.
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;/summary&gt;
    <span class="hljs-keyword">protected <span class="hljs-built_in">string LocalizationSourceName { <span class="hljs-keyword">get; <span class="hljs-keyword">set; }

    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;summary&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// Gets localization source.
    <span class="hljs-comment"><span class="hljs-doctag">/// It's valid if <span class="hljs-doctag">&lt;see cref="LocalizationSourceName"/&gt; is set.
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;/summary&gt;
    <span class="hljs-keyword">protected ILocalizationSource LocalizationSource
    {
        <span class="hljs-keyword">get
        {
            <span class="hljs-keyword">if (LocalizationSourceName == <span class="hljs-literal">null)
            {
                <span class="hljs-keyword">throw <span class="hljs-keyword">new AbpException(<span class="hljs-string">"Must set LocalizationSourceName before, in order to get LocalizationSource");
            }

            <span class="hljs-keyword">if (_localizationSource == <span class="hljs-literal">null || _localizationSource.Name != LocalizationSourceName)
            {
                _localizationSource = LocalizationManager.GetSource(LocalizationSourceName);
            }

            <span class="hljs-keyword">return _localizationSource;
        }
    }
    <span class="hljs-keyword">private ILocalizationSource _localizationSource;


    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;summary&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// Constructor.
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;/summary&gt;
    <span class="hljs-function"><span class="hljs-keyword">protected <span class="hljs-title">ContentPageBase()
    {
        LocalizationSourceName = MauiBoilerplateConsts.LocalizationSourceName;
        ObjectMapper = NullObjectMapper.Instance;
        LocalizationManager = NullLocalizationManager.Instance;
    }

    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;summary&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// Gets localized string for given key name and current language.
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;/summary&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;param name="name"&gt;Key name<span class="hljs-doctag">&lt;/param&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;returns&gt;Localized string<span class="hljs-doctag">&lt;/returns&gt;
    <span class="hljs-function"><span class="hljs-keyword">protected <span class="hljs-keyword">virtual <span class="hljs-built_in">string <span class="hljs-title">L(<span class="hljs-params"><span class="hljs-built_in">string name)
    {
        <span class="hljs-keyword">return LocalizationSource.GetString(name);
    }

    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;summary&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// Gets localized string for given key name and current language with formatting strings.
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;/summary&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;param name="name"&gt;Key name<span class="hljs-doctag">&lt;/param&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;param name="args"&gt;Format arguments<span class="hljs-doctag">&lt;/param&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;returns&gt;Localized string<span class="hljs-doctag">&lt;/returns&gt;
    <span class="hljs-function"><span class="hljs-keyword">protected <span class="hljs-keyword">virtual <span class="hljs-built_in">string <span class="hljs-title">L(<span class="hljs-params"><span class="hljs-built_in">string name, <span class="hljs-keyword">params <span class="hljs-built_in">object[] args)
    {
        <span class="hljs-keyword">return LocalizationSource.GetString(name, args);
    }

    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;summary&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// Gets localized string for given key name and specified culture information.
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;/summary&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;param name="name"&gt;Key name<span class="hljs-doctag">&lt;/param&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;param name="culture"&gt;culture information<span class="hljs-doctag">&lt;/param&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;returns&gt;Localized string<span class="hljs-doctag">&lt;/returns&gt;
    <span class="hljs-function"><span class="hljs-keyword">protected <span class="hljs-keyword">virtual <span class="hljs-built_in">string <span class="hljs-title">L(<span class="hljs-params"><span class="hljs-built_in">string name, CultureInfo culture)
    {
        <span class="hljs-keyword">return LocalizationSource.GetString(name, culture);
    }

    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;summary&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// Gets localized string for given key name and current language with formatting strings.
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;/summary&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;param name="name"&gt;Key name<span class="hljs-doctag">&lt;/param&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;param name="culture"&gt;culture information<span class="hljs-doctag">&lt;/param&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;param name="args"&gt;Format arguments<span class="hljs-doctag">&lt;/param&gt;
    <span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag">&lt;returns&gt;Localized string<span class="hljs-doctag">&lt;/returns&gt;
    <span class="hljs-function"><span class="hljs-keyword">protected <span class="hljs-keyword">virtual <span class="hljs-built_in">string <span class="hljs-title">L(<span class="hljs-params"><span class="hljs-built_in">string name, CultureInfo culture, <span class="hljs-keyword">params <span class="hljs-built_in">object[] args)
    {
        <span class="hljs-keyword">return LocalizationSource.GetString(name, culture, args);
    }
}

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

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

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

 本地化配置

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

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

    }
    <span class="hljs-keyword">public <span class="hljs-built_in">string Text { <span class="hljs-keyword">get; <span class="hljs-keyword">set; }

    <span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-built_in">object <span class="hljs-title">ProvideValue(<span class="hljs-params">IServiceProvider serviceProvider)
    {
        <span class="hljs-keyword">if (Text == <span class="hljs-literal">null)
            <span class="hljs-keyword">return <span class="hljs-string">"";
        <span class="hljs-keyword">var translation = L(Text);          
        <span class="hljs-keyword">return translation;
    }



}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>

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

    <span class="hljs-keyword">public <span class="hljs-keyword">event PropertyChangedEventHandler PropertyChanged;

    <span class="hljs-keyword">protected PropertyChangedEventHandler PropertyChangedHandler { <span class="hljs-keyword">get; }

    <span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-keyword">void <span class="hljs-title">VerifyPropertyName(<span class="hljs-params"><span class="hljs-built_in">string propertyName)
    {
        Type type = GetType();
        <span class="hljs-keyword">if (!<span class="hljs-built_in">string.IsNullOrEmpty(propertyName) &amp;&amp; type.GetTypeInfo().GetDeclaredProperty(propertyName) == <span class="hljs-literal">null)
            <span class="hljs-keyword">throw <span class="hljs-keyword">new ArgumentException(<span class="hljs-string">"找不到属性", propertyName);
    }

    <span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-keyword">virtual <span class="hljs-keyword">void <span class="hljs-title">RaisePropertyChanged(<span class="hljs-params">[CallerMemberName] <span class="hljs-built_in">string propertyName = <span class="hljs-literal">null)
    {
        PropertyChangedEventHandler propertyChanged = PropertyChanged;
        <span class="hljs-keyword">if (propertyChanged == <span class="hljs-literal">null)
            <span class="hljs-keyword">return;
        propertyChanged(<span class="hljs-keyword">this, <span class="hljs-keyword">new PropertyChangedEventArgs(propertyName));
    }

    <span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-keyword">virtual <span class="hljs-keyword">void <span class="hljs-title">RaisePropertyChanged&lt;<span class="hljs-title">T&gt;(<span class="hljs-params">Expression&lt;Func&lt;T&gt;&gt; propertyExpression)
    {
        <span class="hljs-keyword">if (PropertyChanged == <span class="hljs-literal">null)
            <span class="hljs-keyword">return;
        <span class="hljs-built_in">string propertyName = GetPropertyName(propertyExpression);
        <span class="hljs-keyword">if (<span class="hljs-built_in">string.IsNullOrEmpty(propertyName))
            <span class="hljs-keyword">return;
        RaisePropertyChanged(propertyName);
    }

    <span class="hljs-function"><span class="hljs-keyword">protected <span class="hljs-keyword">static <span class="hljs-built_in">string <span class="hljs-title">GetPropertyName&lt;<span class="hljs-title">T&gt;(<span class="hljs-params">Expression&lt;Func&lt;T&gt;&gt; propertyExpression)
    {
        <span class="hljs-keyword">if (propertyExpression == <span class="hljs-literal">null)
            <span class="hljs-keyword">throw <span class="hljs-keyword">new ArgumentNullException(<span class="hljs-keyword">nameof(propertyExpression));
        MemberExpression body = propertyExpression.Body <span class="hljs-keyword">as MemberExpression;
        <span class="hljs-keyword">if (body == <span class="hljs-literal">null)
            <span class="hljs-keyword">throw <span class="hljs-keyword">new ArgumentException(<span class="hljs-string">"参数不合法", <span class="hljs-keyword">nameof(propertyExpression));
        PropertyInfo member = body.Member <span class="hljs-keyword">as PropertyInfo;
        <span class="hljs-keyword">if (member == <span class="hljs-literal">null)
            <span class="hljs-keyword">throw <span class="hljs-keyword">new ArgumentException(<span class="hljs-string">"找不到属性", <span class="hljs-keyword">nameof(propertyExpression));
        <span class="hljs-keyword">return member.Name;
    }

}

至此,我们完成了数据库的配置,内容页基类与 ViewModel基类的编写,接下来可以制作我们的页面了。请看下一章将Abp移植进.NET MAUI项目(三):构建UI层 - 林晓lx - 博客园 (cnblogs.com)

 项目地址

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

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

https://blog.matoapp.net/posts/a3b1360d/

作者

林晓lx

发布于

2022-05-25

更新于

2024-09-11

许可协议

评论