将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<MauiBoilerplateDbContext>(options =>
{
<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<MauiBoilerplateDbContext>(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"><summary>
<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"></summary>
<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"><summary>
<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"></summary>
<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"><summary>
<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"><see cref="L(string)"/> and <span class="hljs-doctag"><see cref="L(string,CultureInfo)"/> methods.
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"></summary>
<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"><summary>
<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"><see cref="LocalizationSourceName"/> is set.
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"></summary>
<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"><summary>
<span class="hljs-comment"><span class="hljs-doctag">/// Constructor.
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"></summary>
<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"><summary>
<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"></summary>
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"><param name="name">Key name<span class="hljs-doctag"></param>
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"><returns>Localized string<span class="hljs-doctag"></returns>
<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"><summary>
<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"></summary>
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"><param name="name">Key name<span class="hljs-doctag"></param>
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"><param name="args">Format arguments<span class="hljs-doctag"></param>
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"><returns>Localized string<span class="hljs-doctag"></returns>
<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"><summary>
<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"></summary>
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"><param name="name">Key name<span class="hljs-doctag"></param>
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"><param name="culture">culture information<span class="hljs-doctag"></param>
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"><returns>Localized string<span class="hljs-doctag"></returns>
<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"><summary>
<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"></summary>
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"><param name="name">Key name<span class="hljs-doctag"></param>
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"><param name="culture">culture information<span class="hljs-doctag"></param>
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"><param name="args">Format arguments<span class="hljs-doctag"></param>
<span class="hljs-comment"><span class="hljs-doctag">/// <span class="hljs-doctag"><returns>Localized string<span class="hljs-doctag"></returns>
<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) && 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<<span class="hljs-title">T>(<span class="hljs-params">Expression<Func<T>> 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<<span class="hljs-title">T>(<span class="hljs-params">Expression<Func<T>> 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项目(二):配置与基类编写