手动搭建基本的ABP框架
ABP是用于创建现代Web应用程序的完整架构和强大的基础设施! 遵循最佳实践和约定,为你提供SOLID开发经验。
创建项目
创建类库:
- Domian
- Domain.Shared
- Application
- Application.Contracts
- EntityFrameworkCore
- HttpApi
- HttpApi.Client
创建ASP.NET Core Web 应用 HttpApi.Host
,作为后端接口主机。
Domain.Shared
领域共享层,该层存放领域层的常量、枚举、值对象、本土化配置文件和其他对象,这些对象实际是领域层的一部分,但是解决方案中所有的层/项目中都会使用到。
- 该项目不依赖解决中的其他项目,其他项目直接或间接引用该项目。
需要添加的Nugget包:
Volo.Abp.Localization
Volo 本地化模块,使应用程序支持全球化
创建文件夹Localization/MyLocalization
,在该文件夹下放语言配置配置文件(如:zh-Hans.json
)。
在文件夹Localization
文件夹下新增类MyLocalizationResource.cs
,添加以下代码:
namespace Domain.Shared.Localization
{
[LocalizationResourceName("MyLocalization")]
public class MyLocalizationResource
{
}
}
在根目录下新增类DomainSharedModule.cs
,添加以下代码:
namespace Domain.Shared
{
// 添加依赖 本地化模组
[DependsOn(
typeof(AbpLocalizationModule)
)]
public class DomainSharedModule : AbpModule // 必须继承AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// 配置虚拟文件系统 配置全球化资源文件必须配置该选项
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<DomainSharedModule>();
});
// 配置全球化资源文件
Configure<AbpLocalizationOptions>(options =>
{
options.Resources.Add<MyLocalizationResource>("zh-Hans")
.AddVirtualJson("/Localization/MyLocalization");
options.DefaultResourceType = typeof(MyLocalizationResource);
});
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace("MyLocalization", typeof(MyLocalizationResource));
});
base.ConfigureServices(context);
}
}
}
Domian
领域层,在该层实现系统核心业务逻辑,该层主要包含实体、集合跟、领域服务、值类型、仓储接口和解决方案的其他领域对象
- 依赖
Domain.Shared
,项目中会用到它的一些常量、枚举、值对象和其他对象。
需要添加的Nugget包:
Volo.Abp.Ddd.Domain
领域驱动模块
添加类DomainModule.cs
,添加以下代码:
namespace Domain
{
// 依赖领域驱动模块
// 依赖领域共享模块
[DependsOn(
typeof(AbpDddDomainModule),
typeof(DomainSharedModule)
)]
public class DomainModule:AbpModule
{
}
}
Application.Contracts
应用约定层,该层存放应用服务接口、数据传输对象、应用层常量和应用层提供程序。他用于分离应用层的接口和实现。这种方式可以将接口项目做为约定包共享给客户端。
- 依赖
Domain.Shared
,因为它可能会在应用接口和DTO中使用常量、枚举和其他的共享对象。
需要添加的Nugget包:
Volo.Abp.Ddd.Application.Contracts
应用层约定模块
添加类ApplicationContractsModule.cs
,添加以下代码:
namespace Application.Contracts
{
// 依赖应用层约定模块
// 依赖领域共享模块
[DependsOn(
typeof(AbpDddApplicationContractsModule),
typeof(DomainSharedModule)
)]
public class ApplicationContractsModule:AbpModule
{
}
}
Application
应用层,该层实现系统应用业务逻辑,实现服务接口。
- 依赖
Application.Contracts
,需要实现服务接口与使用DTO。 - 依赖
Domain
需要使用领域对象(实体、仓储接口等)执行应用程序逻辑。
需要添加Nugget包:
Volo.Abp.Ddd.Application
应用层模块Volo.Abp.AutoMapper
自动映射模块
添加类ApplicationAutoMapperProfile.cs
,应用层自动映射配置类,添加以下代码:
namespace Application
{
public class ApplicationAutoMapperProfile: Profile
{
public ApplicationAutoMapperProfile()
{
// 配置自动映射
//CreateMap<T1, T2>();
}
}
}
添加类ApplicationModule.cs
,添加以下代码:
namespace Application
{
// 依赖自动配置模块
// 依赖领域驱动应用层模块
// 依赖领域模块
// 依赖应用层约定模块
[DependsOn(
typeof(AbpAutoMapperModule),
typeof(AbpDddApplicationModule),
typeof(DomainModule),
typeof(ApplicationContractsModule)
)]
public class ApplicationModule:AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
base.ConfigureServices(context);
// 配置自动映射
Configure<AbpAutoMapperOptions>(options => {
options.AddMaps<ApplicationModule>();
});
}
}
}
EntityFrameworkCore
数据库层,定义了DbContext
并实现Domain
项目中定义的仓储接口。
- 依赖
Domain
,需要引用实体和实现仓储接口。
需要添加Nugget包:
Volo.Abp.EntityFrameworkCore.SqlServer
SqlServer数据库模块
添加类EntityFrameworkCoreModule.cs
,添加以下代码
namespace EntityFrameworkCore
{
// 依赖SqlServer数据库模块
[DependsOn(
typeof(AbpEntityFrameworkCoreSqlServerModule)
)]
public class EntityFrameworkCoreModule:AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
base.ConfigureServices(context);
// 配置使用 SqlServer
Configure<AbpDbContextOptions>(options =>
{
options.UseSqlServer();
});
}
}
}
HttpApi
用于定义API控制器。
大多数情况下,不需要手动定义API控制器,因为ABP的动态API功能会根据应用层自动创建API控制器。但是,如果你需要编写API控制器,则可以在该层中定义。
- 依赖
Application.Contracts
项目,因为它需要注入应用服务接口
需要添加Nugget包:
Volo.Abp.AspNetCore.Mvc
AspNetCore MVC模块
添加类HttpApiModule.cs
,添加以下代码
namespace HttpApi
{
// 依赖MVC模块
// 依赖应用约定模块
[DependsOn(
typeof(AbpAspNetCoreMvcModule),
typeof(ApplicationContractsModule)
)]
public class HttpApiModule:AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
ConfigureLocalization();
base.ConfigureServices(context);
}
private void ConfigureLocalization()
{
// 配置本地化资源库
Configure<AbpLocalizationOptions>(options => {
options.Resources
.Get<MyLocalizationResource>()
.AddBaseTypes(typeof(AbpUiResource));
});
}
}
}
HttpApi.Client
定义C#客户端代理,使用解决方案的HttpAPI项目。可以将该项目共享给第三方客户端,使其轻松的在DotNet应用程序中使用你的HttpAPI(其他类型应用程序可以手动或使用其平台的工具来使用你的API)。
ABP有动态C#API客户端功能,所以大多数情况下你不需要手动创建C#客户端代理。
- 依赖
Application.Contracts
,需要使用应用服务接口和DTO
需要添加Nugget包:
Volo.Abp.Http.Client
添加类HttpApiClientModule.cs
,添加以下代码
namespace HttpApi.Client
{
[DependsOn(
typeof(AbpHttpClientModule),
typeof(ApplicationContractsModule)
)]
public class HttpApiClientModule:AbpModule
{
public const string RemoteServiceName = "Default";
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddHttpClientProxies(
typeof(ApplicationContractsModule).Assembly,
RemoteServiceName
);
Configure<AbpVirtualFileSystemOptions>(options => {
options.FileSets.AddEmbedded<HttpApiClientModule>();
});
}
}
}
HttpApi.Host
HttpAPI主机层,她有自己的appsettings.json
文件(数据库链接字符串等其他配置)
- 依赖
HttpApi
由于没有使用分层模式(没有选择--tiered
选项),还同时依赖:
Application
EntityFrameworkCore
需要添加Nugget包:
Volo.Abp.Autofac
依赖注入模块Volo.Abp.Swashbuckle
添加类HttpApiHostModule.cs
,添加以下代码:
namespace HttpApi.Host
{
[DependsOn(
typeof(HttpApiModule),
typeof(AbpAutofacModule),
typeof(ApplicationModule),
typeof(EntityFrameworkCoreModule),
typeof(AbpSwashbuckleModule)
)]
public class HttpApiHostModule:AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
var hostingEnvironment = context.Services.GetHostingEnvironment();
ConfigureUrls(configuration);
ConfigureVirtualFileSystem(context);
ConfigureConventionalControllers();
ConfigureLocalization();
ConfigureCors(context, configuration);
ConfigureSwaggerServices(context, configuration);
}
/// <summary>
/// 配置URL
/// </summary>
/// <param name="configuration"></param>
private void ConfigureUrls(IConfiguration configuration)
{
Configure<AppUrlOptions>(options =>
{
options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
options.RedirectAllowedUrls.AddRange(configuration["App:RedirectAllowedUrls"].Split(','));
options.Applications["Angular"].RootUrl = configuration["App:ClientUrl"];
});
}
/// <summary>
/// 配置 虚拟文件系统
/// </summary>
/// <param name="context"></param>
private void ConfigureVirtualFileSystem(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
if (hostingEnvironment.IsDevelopment())
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.ReplaceEmbeddedByPhysical<DomainSharedModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
$"..{Path.DirectorySeparatorChar}Domain.Shared"));
options.FileSets.ReplaceEmbeddedByPhysical<DomainModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
$"..{Path.DirectorySeparatorChar}Domain"));
options.FileSets.ReplaceEmbeddedByPhysical<ApplicationContractsModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
$"..{Path.DirectorySeparatorChar}Application.Contracts"));
options.FileSets.ReplaceEmbeddedByPhysical<ApplicationModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
$"..{Path.DirectorySeparatorChar}Application"));
});
}
}
/// <summary>
/// 配置 传统的控制器
/// </summary>
private void ConfigureConventionalControllers()
{
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.Create(typeof(ApplicationModule).Assembly);
});
}
private static void ConfigureSwaggerServices(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.AddAbpSwaggerGenWithOAuth(
configuration["AuthServer:Authority"],
new Dictionary<string, string>
{
{"StudyAcme", "StudyAcme API"}
},
options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "StudyAcme API", Version = "v1" });
options.DocInclusionPredicate((docName, description) => true);
options.CustomSchemaIds(type => type.FullName);
});
}
/// <summary>
/// 配置本地化
/// </summary>
private void ConfigureLocalization()
{
Configure<AbpLocalizationOptions>(options =>
{
//options.Languages.Add(new LanguageInfo("ar", "ar", "العربية"));
//options.Languages.Add(new LanguageInfo("cs", "cs", "Čeština"));
//options.Languages.Add(new LanguageInfo("en", "en", "English"));
//options.Languages.Add(new LanguageInfo("en-GB", "en-GB", "English (UK)"));
//options.Languages.Add(new LanguageInfo("fi", "fi", "Finnish"));
//options.Languages.Add(new LanguageInfo("fr", "fr", "Français"));
//options.Languages.Add(new LanguageInfo("hi", "hi", "Hindi", "in"));
//options.Languages.Add(new LanguageInfo("is", "is", "Icelandic", "is"));
//options.Languages.Add(new LanguageInfo("it", "it", "Italiano", "it"));
//options.Languages.Add(new LanguageInfo("hu", "hu", "Magyar"));
//options.Languages.Add(new LanguageInfo("pt-BR", "pt-BR", "Português"));
//options.Languages.Add(new LanguageInfo("ro-RO", "ro-RO", "Română"));
//options.Languages.Add(new LanguageInfo("ru", "ru", "Русский"));
//options.Languages.Add(new LanguageInfo("sk", "sk", "Slovak"));
//options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe"));
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
//options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "繁體中文"));
//options.Languages.Add(new LanguageInfo("de-DE", "de-DE", "Deutsch", "de"));
//options.Languages.Add(new LanguageInfo("es", "es", "Español", "es"));
//options.Languages.Add(new LanguageInfo("el", "el", "Ελληνικά"));
});
}
/// <summary>
/// 配置Cors
/// <para>
/// 配置跨域请求
/// </para>
/// </summary>
/// <param name="context"></param>
/// <param name="configuration"></param>
private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder
.WithOrigins(
configuration["App:CorsOrigins"]
.Split(",", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.RemovePostFix("/"))
.ToArray()
)
.WithAbpExposedHeaders()
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
}
public override void OnApplicationInitialization(Volo.Abp.ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAbpRequestLocalization();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseUnitOfWork();
app.UseAuthorization();
app.UseSwagger();
app.UseAbpSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "StudyAcme API");
var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>();
c.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);
c.OAuthScopes("StudyAcme");
});
app.UseAuditing();
app.UseConfiguredEndpoints();
}
}
}
在Program.cs
类中添加代码:
await builder.AddApplicationAsync<HttpApiHostModule>();
添加测试服务
在Application
项目中添加类ApplicationAppService
,并添加以下代码
/// <summary>
/// 应用层服务基类
/// </summary>
public abstract class ApplicationAppService:ApplicationService
{
protected ApplicationAppService()
{
// 配置本地资源
LocalizationResource = typeof(MyLocalizationResource);
}
}
在Application
项目中添加类TestService
,并添加以下代码
public class TestService: ApplicationAppService
{
private IStringLocalizer<MyLocalizationResource> _l;
public TestService( IStringLocalizer<MyLocalizationResource> l) {
_l = l;
}
public string GetTest()
{
return "test service";
}
public string GetWellCome()
{
return _l["LongWelcomeMessage"].Value;
}
}
运行HttpApi.Host
可见以下API:
语言选择
使用/Abp/Languages/Switch?culture=zh-Hans&uiCulture=zh-Hans&returnUrl=/
接口进行语言切换,该接口会在Cookie中添加或更新 lpx_lang=ZH; .AspNetCore.Culture=c=zh-Hans|uic=zh-Hans