The blazor project of Abp Vnext uses Blazorise , but after trial, it is found that multiple tags are not supported. So I want to replace it with BootstrapBlazor.
The process is complicated. I have written the module and just need to replace it.
demo is also in the source code
Create an Abp module
Download from the official website
Q: Why not choose an application?
Because the module contains the ssr of Blazor and the host of wasm. It can be used directly. When creating an application, you can only choose one from the host of ssr or wasm. Although you can create it twice and then copy and merge the host, it's too troublesome.
Reduced module
Delete the following useless directories:
- Angular (front end)
- Host / demoapp.web.host (MVC use)
- Host / demoapp.web.unified (MVC use)
- Host / demoapp.web (used by MVC)
Project structure and how to start the project
- IdentityServer application is an authentication server used by other applications. It has its own appsettings.json, including database connection string and other configurations. It needs to initialize the database
- HTTP API of HttpApi.Host managed module. It has its own appsettings.json, including database connection string and other configurations
Start the project first - The startup program of razor.hostrazor webassembly mode has its own appsettings.json (located in wwwroot), including HTTP API server address, IdentityServer and other configurations. The front and back ends are separated. The first two programs need to be started before they can be used normally
- The startup program of razor.server.hostrazor server mode has its own appsettings.json, including database connection string and other configurations, but it integrates IdentityServer and HttpApi.Host module by default, which is equivalent to that the front and rear ends are not separated, so it can be used directly.
Start project (WebAssembly mode)
Because the default database of the project is MSSQLLocalDB, there is no need to modify the configuration. You can initialize the database directly.
First, switch to the directory where the DemoApp.IdentityServer project is located in the console and execute
dotnet ef database update
Open the following items in order:
- DemoApp.IdentityServer
- DemoApp.HttpApi.Host
- DemoApp.Blazor.Host
open https://localhost:44307/ Load the wasm page normally, and click the login in the upper right corner to jump to the identityServer authentication center( https://localhost:44364/ ), enter the user name admin password 1q2w3E * after login, jump back to wasm
Start project (Server mode)
Because Server.Host integrates IdentityServer and HttpApi by default (it needs to be modified, which will be described later)
Initialize database
First, switch to the directory where the DemoApp.Blazor.Server.Host project is located in the console and execute
dotnet ef database update
Open after direct start https://localhost:44313/ that will do
You can see that it's the same when you log in https://localhost:44313/ , unlike wasm, it will jump to the identity server (because it is integrated by itself).
Replace module theme
DemoApp.Blazor
This is the Blazor public project of the module. Generally, relevant pages and components are written here
- Remove the dependency Volo.Abp.AspNetCore.Components.Web.Theming and replace with abp.aspnetcore.razor.theme.bootstrap.
- Open DemoAppBlazorModule
2.1 change the dependent module name abpaspnetcomponentswebthemingmodule in DependsOn to abpaspnetcoreblazerthemebootstrapmodule
2.2 reference the Abp.AspNetCore.Blazor.Theme.Bootstrap Abp.AspNetCore.Blazor.Theme namespace - Open_ Imports.razor, delete @ using Volo.Abp.BlazoriseUI @using Blazorise @using Blazorise.DataGrid, and add @ using BootstrapBlazor.Components @using Abp.AspNetCore.Blazor.Theme
DemoApp.Blazor.Server
This is the class library referenced by the module in the ssr mode. This is simple. You only need to replace the dependency.
- Remove the dependency volo.abp.aspnetcore.components.server.theme and replace it with abp.aspnetcore.razor.theme.bootstrap.server
- Open the DemoAppBlazorServerModule
2.1 change the dependent module name abpaspnetcomponentsserverthemgmodule in DependsOn to abpaspnetcoreblazor themebootstrapservermodule
2.2 reference the abp.aspnetcore.razor.theme.bootstrap namespace
DemoApp.Blazor.WebAssembly
This is the class library referenced in the wasm mode of the module, which is provided by the.
- Remove the dependency volo.abp.aspnetcore.components.webassembly.theme and replace it with abp.aspnetcore.razor.theme.bootstrap.webassembly
- Open DemoAppBlazorWebAssemblyModule
2.1 change the dependent module name in DependsOn from abpaspnetcorecomponentswebassembly themingmodule to AbpAspNetCoreBlazorThemeBootstrapWebAssemblyModule
2.2 reference the abp.aspnetcore.razor.theme.bootstrap namespace
Replace Host theme
Blazor.Host
First, we replace the topic of WebAssembly Host, which is a little simpler than Server integration
Remove dependency
Since the built-in UI modules such as user management, permission management and tenant management all rely on Blazorise, these items need to be removed from the project dependency:
- Volo.Abp.Identity.Blazor.WebAssembly
- Volo.Abp.TenantManagement.Blazor.WebAssembly
- Volo.Abp.SettingManagement.Blazor.WebAssembly
- Volo.abp.aspnetcore.components.webassembly.basictheme (topic)
- Blazorise.Bootstrap
- Blazorise.Icons.FontAwesome
Modify DemoAppBlazorHostModule
using System; using System.Net.Http; using Abp.AspNetCore.Blazor.Theme; using Abp.AspNetCore.Blazor.Theme.Bootstrap; using DemoApp.Blazor.WebAssembly; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Account; using Volo.Abp.Autofac.WebAssembly; using Volo.Abp.AutoMapper; using Volo.Abp.Modularity; using Volo.Abp.UI.Navigation; namespace DemoApp.Blazor.Host { [DependsOn( typeof(AbpAutofacWebAssemblyModule), typeof(AbpAccountApplicationContractsModule), typeof(DemoAppBlazorWebAssemblyModule) )] public class DemoAppBlazorHostModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { var environment = context.Services.GetSingletonInstance<IWebAssemblyHostEnvironment>(); var builder = context.Services.GetSingletonInstance<WebAssemblyHostBuilder>(); ConfigureAuthentication(builder); ConfigureHttpClient(context, environment); ConfigureRouter(context); ConfigureUI(builder); ConfigureMenu(context); ConfigureAutoMapper(context); } private void ConfigureRouter(ServiceConfigurationContext context) { Configure<AbpRouterOptions>(options => { //options.AppAssembly = typeof(DemoAppBlazorHostModule).Assembly; Note it out here options.AdditionalAssemblies.Add(this.GetType().Assembly); }); } private void ConfigureMenu(ServiceConfigurationContext context) { Configure<AbpNavigationOptions>(options => { options.MenuContributors.Add(new DemoAppHostMenuContributor(context.Services.GetConfiguration())); }); } private static void ConfigureAuthentication(WebAssemblyHostBuilder builder) { builder.Services.AddOidcAuthentication(options => { builder.Configuration.Bind("AuthServer", options.ProviderOptions); options.ProviderOptions.DefaultScopes.Add("DemoApp"); }); } private static void ConfigureUI(WebAssemblyHostBuilder builder) { builder.RootComponents.Add<App>("#ApplicationContainer"); } private static void ConfigureHttpClient(ServiceConfigurationContext context, IWebAssemblyHostEnvironment environment) { context.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(environment.BaseAddress) }); } private void ConfigureAutoMapper(ServiceConfigurationContext context) { Configure<AbpAutoMapperOptions>(options => { options.AddMaps<DemoAppBlazorHostModule>(); }); } } }
Modification_ Imports.razor
delete
@using Blazorise @using Blazorise.DataGrid
add to
@using BootstrapBlazor.Components @using Abp.AspNetCore.Blazor.Theme
Regenerate style
The bundle needs to be re created because the theme has been modified
Mr. Zhang becomes the DemoApp.Blazor.Host project, and then transfers to the directory of DemoApp.Blazor.Host on the console
Execution:
abp bundle
If abp is not displayed, you need to install it abp-cli
Display after login:
Blazor.Server.Host
1. Remove and replace dependencies
Remove the following packages
- Blazorise.Bootstrap
- Blazorise.Icons.FontAwesome
- Microsoft.EntityFrameworkCore.Tools
- Volo.Abp.EntityFrameworkCore.SqlServer
- Volo.Abp.AspNetCore.Authentication.JwtBearer
- Volo.Abp.AspNetCore.Components.Server.BasicTheme
- Volo.Abp.AuditLogging.EntityFrameworkCore
- Volo.Abp.Account.Web.IdentityServer
- Volo.Abp.Account.Application
- Volo.Abp.FeatureManagement.EntityFrameworkCore
- Volo.Abp.FeatureManagement.Application
- Volo.Abp.Identity.Blazor.Server
- Volo.Abp.Identity.EntityFrameworkCore
- Volo.Abp.Identity.Application
- Volo.Abp.TenantManagement.Blazor.Server
- Volo.Abp.TenantManagement.EntityFrameworkCore
- Volo.Abp.TenantManagement.Application
- Volo.Abp.SettingManagement.Blazor.Server
- Volo.Abp.SettingManagement.EntityFrameworkCore
- Volo.Abp.SettingManagement.Application
- Volo.Abp.PermissionManagement.Application
- Volo.Abp.PermissionManagement.EntityFrameworkCore
- DemoApp.EntityFrameworkCore\DemoApp.EntityFrameworkCore
- DemoApp.HttpApi
Add the following packages
- Volo.Abp.AspNetCore.Authentication.OpenIdConnect
- Volo.Abp.AspNetCore.Mvc.Client
- Volo.Abp.AspNetCore.Authentication.OAuth
- Volo.Abp.Http.Client.IdentityModel.Web
- Volo.Abp.PermissionManagement.HttpApi.Client
- Volo.Abp.Identity.HttpApi.Client
- Volo.Abp.TenantManagement.HttpApi.Client
- Volo.Abp.FeatureManagement.HttpApi.Client
- DemoApp.HttpApi.Client
2. Modify Module.cs
1. Delete the removed module in DependsOn
Also delete
-
DemoAppEntityFrameworkCoreModule (because you don't need to read the database directly)
-
DemoAppApplicationModule
-
DemoAppHttpApiModule
Add the following modules -
AbpAspNetCoreMvcClientModule
-
AbpAspNetCoreAuthenticationOAuthModule
-
AbpAspNetCoreAuthenticationOpenIdConnectModule
-
AbpHttpClientIdentityModelWebModule
-
AbpAspNetCoreMvcUiBasicThemeModule
-
AbpAspNetCoreSerilogModule
-
AbpIdentityHttpApiClientModule
-
AbpFeatureManagementHttpApiClientModule
-
AbpTenantManagementHttpApiClientModule
-
AbpPermissionManagementHttpApiClientModule
2.ConfigureServices
public override void ConfigureServices(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); var configuration = context.Services.GetConfiguration(); Configure<AbpBundlingOptions>(options => { // MVC UI options.StyleBundles.Configure( BasicThemeBundles.Styles.Global, bundle => { bundle.AddFiles("/global-styles.css"); } ); //BLAZOR UI options.StyleBundles.Configure( BlazorBootstrapThemeBundles.Styles.Global, bundle => { bundle.AddFiles("/blazor-global-styles.css"); //You can remove the following line if you don't use Blazor CSS isolation for components bundle.AddFiles("/DemoApp.Blazor.Server.Host.styles.css"); } ); }); context.Services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies", options => { options.ExpireTimeSpan = TimeSpan.FromDays(365); }) .AddAbpOpenIdConnect("oidc", options => { options.Authority = configuration["AuthServer:Authority"]; options.ClientId = configuration["AuthServer:ClientId"]; options.ClientSecret = configuration["AuthServer:ClientSecret"]; options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]); options.ResponseType = OpenIdConnectResponseType.CodeIdToken; options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; options.Scope.Add("role"); options.Scope.Add("email"); options.Scope.Add("phone"); options.Scope.Add("DemoApp"); }); if(hostingEnvironment.IsDevelopment()) { Configure<AbpVirtualFileSystemOptions>(options => { options.FileSets.ReplaceEmbeddedByPhysical<DemoAppDomainSharedModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}DemoApp.Domain.Shared", Path.DirectorySeparatorChar))); options.FileSets.ReplaceEmbeddedByPhysical<DemoAppDomainModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}DemoApp.Domain", Path.DirectorySeparatorChar))); options.FileSets.ReplaceEmbeddedByPhysical<DemoAppApplicationContractsModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}DemoApp.Application.Contracts", Path.DirectorySeparatorChar))); options.FileSets.ReplaceEmbeddedByPhysical<DemoAppApplicationModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}DemoApp.Application", Path.DirectorySeparatorChar))); options.FileSets.ReplaceEmbeddedByPhysical<DemoAppBlazorHostModule>(hostingEnvironment.ContentRootPath); }); } context.Services.AddAbpSwaggerGen( options => { options.SwaggerDoc("v1", new OpenApiInfo { Title = "DemoApp API", Version = "v1" }); options.DocInclusionPredicate((docName, description) => true); options.CustomSchemaIds(type => type.FullName); }); Configure<AbpLocalizationOptions>(options => { 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("it", "it", "Italian", "it")); options.Languages.Add(new LanguageInfo("hu", "hu", "Magyar")); options.Languages.Add(new LanguageInfo("pt-BR", "pt-BR", "Português (Brasil)")); 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", "Simplified Chinese")); options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "Traditional Chinese")); }); Configure<AbpMultiTenancyOptions>(options => { options.IsEnabled = MultiTenancyConsts.IsEnabled; }); context.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri("/") }); Configure<AbpNavigationOptions>(options => { options.MenuContributors.Add(new DemoAppMenuContributor()); }); // Configure<AbpRouterOptions>(options => { options.AppAssembly = typeof(DemoAppBlazorHostModule).Assembly; }); Configure<AbpRouterOptions>(options => { options.AdditionalAssemblies .Add(typeof(DemoAppBlazorHostModule).Assembly); });//Change it to this }
3.OnApplicationInitialization
public override void OnApplicationInitialization(ApplicationInitializationContext context) { var env = context.GetEnvironment(); var app = context.GetApplicationBuilder(); app.UseAbpRequestLocalization(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseCorrelationId(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); //app.UseJwtTokenMiddleware(); if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } // app.UseUnitOfWork(); //app.UseIdentityServer(); app.UseAuthorization(); app.UseSwagger(); app.UseAbpSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", "DemoApp API"); }); app.UseConfiguredEndpoints(); using (var scope = context.ServiceProvider.CreateScope()) { AsyncHelper.RunSync(async () => { await scope.ServiceProvider .GetRequiredService<IDataSeeder>() .SeedAsync(); }); } }
3. Modification_ Imports.razor
delete
@using Blazorise @using Blazorise.DataGrid @using Volo.Abp.BlazoriseUI @using Volo.Abp.BlazoriseUI.Components
add to
@using BootstrapBlazor.Components @using Abp.AspNetCore.Blazor.Theme
4. Delete the EntityFrameworkCore and Migrations directories
Because we directly call httpApi to obtain data, we do not need host to read the database, so we delete these two directories
5._Host.cshtml
@page "/" @namespace DemoApp.Blazor.Server.Host.Pages @using System.Globalization @using Abp.AspNetCore.Blazor.Theme.Bootstrap @using Abp.AspNetCore.Blazor.Theme.Server @using Volo.Abp.Localization @{ Layout = null; var rtl = CultureHelper.IsRtl ? "rtl" : string.Empty; } <!DOCTYPE html> <html lang="@CultureInfo.CurrentCulture.Name" dir="@rtl"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>DemoApp.Blazor.Server</title> <base href="~/" /> <abp-style-bundle name="@BlazorBootstrapThemeBundles.Styles.Global" /> </head> <body class="abp-application-layout bg-light @rtl"> <component type="typeof(App)" render-mode="Server" /> <div id="blazor-error-ui"> <environment include="Staging,Production"> An error has occurred. This application may no longer respond until reloaded. </environment> <environment include="Development"> An unhandled exception has occurred. See browser dev tools for details. </environment> <a href="" class="reload">Reload</a> <a class="dismiss">🗙</a> </div> <abp-script-bundle name="@BlazorBootstrapThemeBundles.Scripts.Global" /> </body> </html>
6.DemoAppMenuContributor
Comment on the ConfigureMainMenuAsync method body, because we don't have those modules
7. Modify appsettings.json configuration
Delete ConnectionStrings node
Modify AuthServer to:
"AuthServer": { "Authority": "https://localhost:44364", "RequireHttpsMetadata": "true", "ClientId": "DemoApp_Blazor_Server", "ClientSecret": "1q2w3e*" }
The Authority configuration item is the URI of IdentityServer, and the ClientID needs to be remembered, which will be used later
add to:
"RemoteServices": { "Default": { "BaseUrl": "https://localhost:44396/" } }
The uri of the HTTP API is configured here
5. Add login controller
Create the Controllers directory and add the AccountController
public class AccountController : ChallengeAccountController { }
6. Add identityServer configuration
Open the DemoApp.IdentityServer project
1. Modify appsettings.json
Add in Clients of identity server
"DemoApp_Blazor_Server": { "ClientId": "DemoApp_Blazor_Server", "RootUrl": "https://localhost:44313/" "ClientSecret": "1q2w3e*", }
Navigate to IdentityServer/IdentityServerDataSeedContributor.cs and add the IdentityServer configuration.
Modify the CreateClientsAsync method and add
var blazorServerTieredClientId = configurationSection["DemoApp_Blazor_Server:ClientId"]; if (!blazorServerTieredClientId.IsNullOrWhiteSpace()) { var blazorServerTieredClientRootUrl = configurationSection["DemoApp_Blazor_Server:RootUrl"].EnsureEndsWith('/'); /* Admin_BlazorServerTiered client is only needed if you created a tiered blazor server * solution. Otherwise, you can delete this client. */ await CreateClientAsync( name: blazorServerTieredClientId, scopes: commonScopes, grantTypes: new[] { "hybrid" }, secret: (configurationSection["DemoApp_Blazor_Server:ClientSecret"] ?? "1q2w3e*").Sha256(), redirectUri: $"{blazorServerTieredClientRootUrl}signin-oidc", postLogoutRedirectUri: $"{blazorServerTieredClientRootUrl}signout-callback-oidc", frontChannelLogoutUri: $"{blazorServerTieredClientRootUrl}Account/FrontChannelLogout", corsOrigins: new[] { blazorServerTieredClientRootUrl.RemovePostFix("/") } ); }
After modification, you need to reopen the identity server configuration to take effect.
7. Modify menu
Navigate to menus > demoappmenucontributor.cs
using System.Threading.Tasks; using DemoApp.MultiTenancy; using Volo.Abp.UI.Navigation; namespace DemoApp.Blazor.Server.Host.Menus { public class DemoAppMenuContributor : IMenuContributor { public async Task ConfigureMenuAsync(MenuConfigurationContext context) { if (context.Menu.Name == StandardMenus.Main) { await ConfigureMainMenuAsync(context); } } private Task ConfigureMainMenuAsync(MenuConfigurationContext context) { var administration = context.Menu.GetAdministration(); context.Menu.Items.Insert(0, new ApplicationMenuItem("Index", displayName: "Index", "/", icon: "fa fa-home")); // if (MultiTenancyConsts.IsEnabled) // { // administration.SetSubItemOrder(TenantManagementMenuNames.GroupName, 1); // } // else // { // administration.TryRemoveMenuItem(TenantManagementMenuNames.GroupName); // } // // administration.SetSubItemOrder(IdentityMenuNames.GroupName, 2); // administration.SetSubItemOrder(SettingManagementMenus.GroupName, 3); return Task.CompletedTask; } } }
Incomplete
Because several page modules in abp have been removed, you need to rewrite user management, role management, tenant management and other pages. I will release these modules after I improve them. Also, the login page of identity server should be rewritten.