Host Application¶
Open existing GridLab.PSSX.ModuleName.abpsln
solution in order to add host application:
Select MVC UI
for hosting user interface and application module.
-
Configure
.csproj
according to project needs.<Project Sdk="Microsoft.NET.Sdk.Web"> <!-- Import common properties for projects --> <Import Project="..\..\common.props" /> <PropertyGroup> <TargetFramework>net9.0</TargetFramework> <Nullable>enable</Nullable> <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel> <RootNamespace>GridLab.PSSX.ModuleName</RootNamespace> <AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType> <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> <MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish> <PreserveCompilationReferences>true</PreserveCompilationReferences> </PropertyGroup> <!-- Add Logging support --> <ItemGroup> <PackageReference Include="Serilog.AspNetCore" Version="4.0.0" /> <PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" /> </ItemGroup> <ItemGroup> <PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="9.0.5" /> <PackageReference Include="Volo.Abp.Autofac" Version="9.0.5" /> <PackageReference Include="Volo.Abp.AspNetCore.Serilog" Version="9.0.5" /> <PackageReference Include="Volo.Abp.Swashbuckle" Version="9.0.5" /> <PackageReference Include="Volo.Abp.EntityFrameworkCore.SqlServer" VersionOverride="9.0.5" /> <!-- Database migration related tools must available --> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.4"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> </ItemGroup> <ItemGroup> <ProjectReference Include="..\..\src\GridLab.PSSX.ModuleName.Application\GridLab.PSSX.ModuleName.Application.csproj" /> <ProjectReference Include="..\..\src\GridLab.PSSX.ModuleName.HttpApi\GridLab.PSSX.ModuleName.HttpApi.csproj" /> <ProjectReference Include="..\..\src\GridLab.PSSX.ModuleName.Web\GridLab.PSSX.ModuleName.Web.csproj" /> <ProjectReference Include="..\..\src\GridLab.PSSX.ModuleName.EntityFrameworkCore\GridLab.PSSX.ModuleName.EntityFrameworkCore.csproj" /> </ItemGroup> <ItemGroup> <!-- Add project related framework packages --> <!-- .... --> <PackageReference Include="Volo.Abp.Account.Application" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.Account.HttpApi" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.Account.Web.OpenIddict" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.OpenIddict.EntityFrameworkCore" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.TenantManagement.HttpApi" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.TenantManagement.Web" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.TenantManagement.Application" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.TenantManagement.EntityFrameworkCore" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.SettingManagement.Application" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.SettingManagement.EntityFrameworkCore" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.AuditLogging.EntityFrameworkCore" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.PermissionManagement.Domain.Identity" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.PermissionManagement.Application" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.PermissionManagement.EntityFrameworkCore" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.FeatureManagement.HttpApi" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.FeatureManagement.Web" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.FeatureManagement.Application" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.FeatureManagement.EntityFrameworkCore" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.BlobStoring.Database.EntityFrameworkCore" VersionOverride="9.0.5" /> <PackageReference Include="Volo.Abp.BackgroundJobs.EntityFrameworkCore" VersionOverride="9.0.5" /> </ItemGroup> <!-- Add MVC UI Theme --> <ItemGroup> <PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic" VersionOverride="9.0.5" /> </ItemGroup> <ItemGroup> <Compile Remove="Logs\**" /> <Content Remove="Logs\**" /> <EmbeddedResource Remove="Logs\**" /> <None Remove="Logs\**" /> </ItemGroup> <ItemGroup> <Folder Include="Migrations\" /> </ItemGroup> <!-- Resolve symbols files for debugging automatically --> <Target Name="_ResolveCopyLocalNuGetPackagePdbs" Condition="$(CopyLocalLockFileAssemblies) == true" AfterTargets="ResolveReferences"> <ItemGroup> <ReferenceCopyLocalPaths Include="@(ReferenceCopyLocalPaths->'%(RootDir)%(Directory)%(Filename).pdb')" Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' != '' and Exists('%(RootDir)%(Directory)%(Filename).pdb')" /> </ItemGroup> </Target> </Project>
Replace version numbers with latest available.
-
Create
<ModuleName>HostDbContext
class to configure and manage database interactions for the application.- Define a new class that inherits from
AbpDbContext<<ModuleName>HostDbContext>
. - Add a constructor that accepts DbContextOptions
and passes it to the base class. - Override the OnModelCreating method to configure the database schema using the ModelBuilder. Add any necessary configurations for features like audit logging, permission management, et
Example:
public class IdentityHostDbContext : AbpDbContext<IdentityHostDbContext> { public IdentityHostDbContext(DbContextOptions<IdentityHostDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ConfigureAuditLogging(); modelBuilder.ConfigurePermissionManagement(); modelBuilder.ConfigureSettingManagement(); modelBuilder.ConfigureIdentity(); modelBuilder.ConfigureBlobStoring(); modelBuilder.ConfigureTenantManagement(); modelBuilder.ConfigureOpenIddict(); modelBuilder.ConfigureBackgroundJobs(); modelBuilder.ConfigureFeatureManagement(); } }
- Define a new class that inherits from
-
Create
<ModuleName>HostDbContextFactory
to create an instance of the<ModuleName>HostDbContext
at design time which is need by tools like EF Core migrations.- Define a new class that implements IDesignTimeDbContextFactory<
HostDbContext>. - Implement the CreateDbContext method to configure the DbContextOptions and return an instance of
HostDbContext. - Use the ConfigurationBuilder to load the connection string from the appsettings.json file.
Example:
public class IdentityHostDbContextFactory : IDesignTimeDbContextFactory<IdentityHostDbContext> { public IdentityHostDbContext CreateDbContext(string[] args) { var configuration = BuildConfiguration(); var builder = new DbContextOptionsBuilder<IdentityHostDbContext>() .UseSqlServer(configuration.GetConnectionString("Default")); return new IdentityHostDbContext(builder.Options); } private static IConfigurationRoot BuildConfiguration() { var builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false); return builder.Build(); } }
- Define a new class that implements IDesignTimeDbContextFactory<
-
Add a Default connection string in the
appsettings.json
file.{ "ConnectionStrings": { "Default": "Server=(LocalDB)\\MSSQLLocalDB;Database=ModuleNameHost_Main;Trusted_Connection=True;TrustServerCertificate=True" } }
-
Create dotnet ef tools scripts for adding migration and updating database.
.NET CLI manifest should available for tools that are installed as local. Check project root for
.config
folder.
Add Migration:
```powershell
dotnet tool restore
$migrationName = "Initial"
Write-Host "Adding migration '$migrationName'"
dotnet ef migrations add $migrationName
"Added migration."
Write-Host "Press enter to update the database or CTRL-C to exit ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
dotnet ef database update
"Database update completed."
pause
```
Update Database:
```powershell
dotnet tool restore
"Updating the database..."
dotnet ef database update
"The database update completed."
Pause
```
- The versions of npm packages defined in
package.json
should be checked, where extra npm packages to be used in mvc ui should be defined.
{
"version": "1.0.0",
"name": "my-app",
"private": true,
"dependencies": {
"@abp/aspnetcore.mvc.ui.theme.basic": "^9.0.5"
}
}
Add extra packages if necessary
{
"version": "0.1.0",
"name": "my-app-authserver",
"private": true,
"dependencies": {
"@abp/aspnetcore.mvc.ui.theme.basic": "~9.0.5",
"ace-builds": "^1.4.12",
"bootstrap-markdown-editor-4": "^3.0.0",
"jquery-datetimepicker": "^2.5.21",
"moment": "^2.29.1"
}
}
Replace version numbers with latest available.
In order to run abp install-libs
automation scripts, a definition must be made in abp.resourcemapping.js
.
module.exports = {
aliases: {
"@node_modules": "./node_modules",
"@libs": "./wwwroot/libs"
},
clean: [
"@libs",
"!@libs/**/foo.txt"
],
mappings: {
"@node_modules/bootstrap-markdown-editor-4/dist/css/bootstrap-markdown-editor.min.css": "@libs/bootstrap-markdown-editor-4/css/",
"@node_modules/bootstrap-markdown-editor-4/dist/js/bootstrap-markdown-editor.min.js": "@libs/bootstrap-markdown-editor-4/js/",
"@node_modules/ace-builds/src-noconflict/ace.js": "@libs/ace/",
"@node_modules/ace-builds/src-noconflict/theme-tomorrow.js": "@libs/ace/",
"@node_modules/ace-builds/src-noconflict/mode-markdown.js": "@libs/ace/",
"@node_modules/ace-builds/src-noconflict/ext-language_tools.js": "@libs/ace/",
"@node_modules/moment/moment.js": "@libs/moment/",
"@node_modules/jquery-datetimepicker/jquery.datetimepicker.js": "@libs/jquery-datetimepicker/",
"@node_modules/jquery-datetimepicker/jquery.datetimepicker.css": "@libs/jquery-datetimepicker/",
}
};
Clean wwwroot/libs
and node_modules
folders for clean installation. This is required action for abp install-libs
script.
ABP CLI's abp install-libs command copies resources from node_modules to wwwroot/libs folder. Each standard package (see the @ABP NPM Packages section) defines the mapping for its own files. So, most of the time, you only configure dependencies.
Configure Services¶
ConfigureServices
method is used to register services and configure the application's behavior. Meanwhile PreConfigureServices
method is executed before the ConfigureServices
method and is used to set up configurations that need to be applied early in the application's lifecycle.
- Configure
OpenIdDict
library.
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();
....
....
PreConfigure<OpenIddictBuilder>(builder =>
{
builder.AddValidation(options =>
{
options.AddAudiences("Identity");
options.UseLocalServer();
options.UseAspNetCore();
});
});
PreConfigure<AbpOpenIddictAspNetCoreOptions>(options =>
{
options.AddDevelopmentEncryptionAndSigningCertificate = true;
});
}
Configure related Authentication
services
public override void ConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();
ConfigureAuthentication(context, configuration);
....
}
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
if (!configuration.GetValue<bool>("App:DisablePII"))
{
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true; // Enables logging of Personally Identifiable Information (PII) if the App:DisablePII configuration is set to false.
Microsoft.IdentityModel.Logging.IdentityModelEventSource.LogCompleteSecurityArtifact = true;
}
if (!configuration.GetValue<bool>("AuthServer:RequireHttpsMetadata"))
{
Configure<OpenIddictServerAspNetCoreOptions>(options =>
{
options.DisableTransportSecurityRequirement = true; // Disables the HTTPS metadata requirement for OpenIddict if AuthServer:RequireHttpsMetadata is set to false.
});
Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedProto; // Configures ForwardedHeadersOptions to handle X-Forwarded-Proto headers, which is useful when the app is behind a reverse proxy.
});
}
context.Services.ForwardIdentityAuthenticationForBearer(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
options.IsDynamicClaimsEnabled = true; // Configures identity authentication for bearer tokens and enables dynamic claims.
});
}
Add a AuthServer:RequireHttpsMetadata and App:DisablePII configuration to the appsettings.json
file.
{
"App": {
....,
"DisablePII": "false"
},
"AuthServer": {
....,
"Authority": "https://localhost:44334",
"RequireHttpsMetadata": true
}
}
- Configure Databases ORM provider.
public override void ConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();
ConfigureDatabaseConnection(context, configuration);
....
}
private void ConfigureDatabaseConnection(ServiceConfigurationContext context, IConfiguration configuration)
{
Configure<AbpDbConnectionOptions>(options =>
{
options.ConnectionStrings.Default = configuration.GetConnectionString("Default");
});
Configure<AbpDbContextOptions>(options =>
{
options.UseSqlServer();
});
}
- Configure virtual file system for development purposes.
public override void ConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();
ConfigureVirtualFileSystem(context, configuration);
....
}
Example:
private void ConfigureVirtualFileSystem(IWebHostEnvironment hostingEnvironment)
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<IdentityWebHostModule>();
if (hostingEnvironment.IsDevelopment())
{
options.FileSets.ReplaceEmbeddedByPhysical<IdentityDomainSharedModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}GridLab.PSSX.Identity.Domain.Shared", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<IdentityDomainModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}GridLab.PSSX.Identity.Domain", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<IdentityWebModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}GridLab.PSSX.Identity.Web", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<IdentityApplicationModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}GridLab.PSSX.Identity.Application", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<IdentityApplicationContractsModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}GridLab.PSSX.Identity.Application.Contracts", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<IdentityHttpApiModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}GridLab.PSSX.Identity.HttpApi", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<IdentityWebHostModule>(hostingEnvironment.ContentRootPath);
}
});
}
- Configure MVC root url.
public override void ConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();
ConfigureUrls(configuration);
....
}
private void ConfigureUrls(IConfiguration configuration)
{
Configure<AppUrlOptions>(options =>
{
options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
});
}
Add a App:SelfUrl configuration to the appsettings.json
file.
{
"App": {
....,
"SelfUrl": "https://localhost:44372", // Update port according to project needs
}
}
- Enable API versioning.
Refer to Api Versioning.
- Configure
Swagger
by usingIConfigureOptions<SwaggerGenOptions>
interface, in order to do that create new folder namedSwagger
and then add new classConfigureSwaggerOptions.cs
atGridLab.PSSX.<ModuleName>
project.
Refer to Configure Swagger section at Api Versioning.
- Configure Localization options.
public override void ConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();
ConfigureLocalization();
....
}
private void ConfigureLocalization()
{
Configure<AbpLocalizationOptions>(options =>
{
options.Languages.Add(new LanguageInfo("de-DE", "de-DE", "Deutsch"));
options.Languages.Add(new LanguageInfo("en", "en", "English"));
options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe"));
});
}
Pages¶
- Add
<ModuleName>PageModel
as base class.
Example:
public abstract class IdentityPageModel : AbpPageModel
{
protected IdentityPageModel()
{
LocalizationResourceType = typeof(IdentityResource);
}
}
- Update
IndexModel
.
Example:
public class IndexModel : IdentityPageModel
{
public void OnGet()
{
}
}
- Update
Index.cshtml
Example:
@page
@model GridLab.PSSX.Identity.Pages.IndexModel
@using Volo.Abp.Users
@inject ICurrentUser CurrentUser
<abp-card>
<abp-card-header>Welcome to the Identity Management Application</abp-card-header>
<abp-card-body>
@if (!CurrentUser.IsAuthenticated)
{
<form method="POST">
<input type="submit" asp-page-handler="Login" value="LOGIN" class="btn btn-primary" />
</form>
}
else
{
<strong>Claims</strong><br />
@Html.Raw(CurrentUser.GetAllClaims().Select(c => $"{c.Type}={c.Value}").OrderBy(x => x).JoinAsString(" <br /> "))
}
<hr />
<p class="text-end"><a href="https://www.gridlabx.io" target="_blank">gridlabx.io</a></p>
</abp-card-body>
</abp-card>