將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);
}
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<MauiBoilerplateDbContext>(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<MauiBoilerplateDbContext>(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的註釋裡描述的那樣:
/// <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; }
/// <summary>
/// Reference to the setting manager.
/// </summary>
public ISettingManager SettingManager { get; set; }
/// <summary>
/// Reference to the localization manager.
/// </summary>
public ILocalizationManager LocalizationManager { get; set; }
/// <summary>
/// Gets/sets name of the localization source that is used in this application service.
/// It must be set in order to use <see cref="L(string)"/> and <see cref="L(string,CultureInfo)"/> methods.
/// </summary>
protected string LocalizationSourceName { get; set; }
/// <summary>
/// Gets localization source.
/// It's valid if <see cref="LocalizationSourceName"/> is set.
/// </summary>
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;
/// <summary>
/// Constructor.
/// </summary>
protected ContentPageBase()
{
LocalizationSourceName = MauiBoilerplateConsts.LocalizationSourceName;
ObjectMapper = NullObjectMapper.Instance;
LocalizationManager = NullLocalizationManager.Instance;
}
/// <summary>
/// Gets localized string for given key name and current language.
/// </summary>
/// <param name="name">Key name</param>
/// <returns>Localized string</returns>
protected virtual string L(string name)
{
return LocalizationSource.GetString(name);
}
/// <summary>
/// Gets localized string for given key name and current language with formatting strings.
/// </summary>
/// <param name="name">Key name</param>
/// <param name="args">Format arguments</param>
/// <returns>Localized string</returns>
protected virtual string L(string name, params object[] args)
{
return LocalizationSource.GetString(name, args);
}
/// <summary>
/// Gets localized string for given key name and specified culture information.
/// </summary>
/// <param name="name">Key name</param>
/// <param name="culture">culture information</param>
/// <returns>Localized string</returns>
protected virtual string L(string name, CultureInfo culture)
{
return LocalizationSource.GetString(name, culture);
}
/// <summary>
/// Gets localized string for given key name and current language with formatting strings.
/// </summary>
/// <param name="name">Key name</param>
/// <param name="culture">culture information</param>
/// <param name="args">Format arguments</param>
/// <returns>Localized string</returns>
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<Func<T>> propertyExpression)
{
if (PropertyChanged == null)
return;
string propertyName = GetPropertyName(propertyExpression);
if (string.IsNullOrEmpty(propertyName))
return;
RaisePropertyChanged(propertyName);
}
protected static string GetPropertyName<T>(Expression<Func<T>> 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基類的編寫,接下來可以製作我們的頁面了。請看下一章將Abp移植進.NET MAUI專案(三):構建UI層 - 林曉lx - 部落格園 (cnblogs.com)
專案地址