I send you the code, however, I checked the source coce of the original module and found the issue:
@if (Model.OtherLanguages.Count > 1)
{
<div class="dropdown">
<a class="btn dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="current-language-name">@Model.CurrentLanguage.DisplayName</span>
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="dropdownMenuLink">
@foreach (var language in Model.OtherLanguages)
{
<a class="dropdown-item" href="~/Abp/Languages/Switch?culture=@(language.CultureName)&uiCulture=@(language.UiCultureName)&returnUrl=@(System.Net.WebUtility.UrlEncode(Context.Request.GetEncodedPathAndQuery()))">
<span class="me-2"></span>
@language.DisplayName
</a>
}
</div>
</div>
}
I have two langauges. This is why OtherLanguages is 1 Correct code should be:
@if (Model.OtherLanguages.Count > 0)
{
<div class="dropdown">
<a class="btn dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="current-language-name">@Model.CurrentLanguage.DisplayName</span>
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="dropdownMenuLink">
@foreach (var language in Model.OtherLanguages)
{
<a class="dropdown-item" href="~/Abp/Languages/Switch?culture=@(language.CultureName)&uiCulture=@(language.UiCultureName)&returnUrl=@(System.Net.WebUtility.UrlEncode(Context.Request.GetEncodedPathAndQuery()))">
<span class="me-2"></span>
@language.DisplayName
</a>
}
</div>
</div>
}
Maybe you can fix this in the next release.
No, I did not overwrite the existing toolbar. Here is my module class:
using System.IO;
using Azure.Monitor.OpenTelemetry.AspNetCore;
using Entrafin.Web.Bundling;
using Hangfire;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using MyappDb.EMail;
using MyappDb.EntityFrameworkCore;
using MyappDb.Jobs;
using MyappDb.Localization;
using MyappDb.Permissions;
using MyappDb.Web.Bundling.Kendo;
using MyappDb.Web.Components.Kendo;
using MyappDb.Web.Components.Myapp;
using MyappDb.Web.Filters;
using MyappDb.Web.Menus;
using OpenIddict.Validation.AspNetCore;
using Volo.Abp;
using Volo.Abp.Account.Admin.Web;
using Volo.Abp.Account.Public.Web;
using Volo.Abp.Account.Web;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Auditing;
using Volo.Abp.AuditLogging.Web;
using Volo.Abp.Autofac;
using Volo.Abp.AutoMapper;
using Volo.Abp.BackgroundWorkers;
using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.BlobStoring;
using Volo.Abp.Hangfire;
using Volo.Abp.Identity;
using Volo.Abp.Identity.Web;
using Volo.Abp.LanguageManagement;
using Volo.Abp.LeptonTheme.Management;
using Volo.Abp.Modularity;
using Volo.Abp.OpenIddict.Pro.Web;
using Volo.Abp.PermissionManagement.Identity;
using Volo.Abp.Swashbuckle;
using Volo.Abp.TextTemplateManagement.Web;
using Volo.Abp.UI.Navigation;
using Volo.Abp.UI.Navigation.Urls;
using Volo.Abp.VirtualFileSystem;
using Volo.Saas.Host;
using Volo.Abp.BlobStoring.Azure;
using Volo.Abp.Ui.LayoutHooks;
using MyappDb.ShopIntegration;
using NUglify.JavaScript.Syntax;
using Volo.Abp.Emailing;
using Volo.Abp.Localization;
using Volo.Abp.Uow;
namespace MyappDb.Web;
[DependsOn(
typeof(MyappDbHttpApiModule),
typeof(MyappDbApplicationModule),
typeof(MyappDbEntityFrameworkCoreModule),
typeof(AbpAutofacModule),
typeof(AbpIdentityWebModule),
typeof(AbpPermissionManagementDomainIdentityModule),
typeof(AbpAccountPublicWebOpenIddictModule),
typeof(AbpOpenIddictProWebModule),
typeof(AbpAuditLoggingWebModule),
typeof(LeptonThemeManagementWebModule),
typeof(SaasHostWebModule),
typeof(AbpAccountAdminWebModule),
typeof(LanguageManagementWebModule),
typeof(AbpAspNetCoreMvcUiLeptonThemeModule),
typeof(TextTemplateManagementWebModule),
typeof(AbpSwashbuckleModule),
typeof(AbpAspNetCoreSerilogModule),
typeof(AbpBackgroundWorkersHangfireModule)
)]
[DependsOn(typeof(AbpBlobStoringAzureModule))]
public class MyappDbWebModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
{
options.AddAssemblyResource(
typeof(MyappDbResource),
typeof(MyappDbDomainModule).Assembly,
typeof(MyappDbDomainSharedModule).Assembly,
typeof(MyappDbApplicationModule).Assembly,
typeof(MyappDbApplicationContractsModule).Assembly,
typeof(MyappDbWebModule).Assembly
);
});
PreConfigure<OpenIddictBuilder>(builder =>
{
builder.AddValidation(options =>
{
options.AddAudiences("MyappDb"); // Replace with your application name
options.UseLocalServer();
options.UseAspNetCore();
});
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();
Configure<AbpUnitOfWorkDefaultOptions>(options =>
{
options.Timeout = DatabaseConst.CommandTimeout;
});
ConfigureUrls(configuration);
ConfigurePages(configuration);
ConfigureAuthentication(context, configuration);
ConfigureImpersonation(context, configuration);
ConfigureAutoMapper();
ConfigureVirtualFileSystem(hostingEnvironment);
ConfigureNavigationServices();
ConfigureAutoApiControllers();
ConfigureSwaggerServices(context.Services);
// ConfigureHealthChecks(context);
ConfigureHangfire(context, configuration);
ConfigurePasswortResetToken(context);
ConfigureAuditLogging();
if (hostingEnvironment.IsDevelopment())
{
ConfigureExceptionHandling(context);
}
//Replace mail sender
context.Services.Replace(ServiceDescriptor.Singleton<IEmailSender, MyappEMailSender>());
ConfigureAddApplicationInsightsTelemetry(context, configuration);
}
private void ConfigureAddApplicationInsightsTelemetry(ServiceConfigurationContext context, IConfiguration configuration)
{
if (System.Diagnostics.Debugger.IsAttached)
{
return;
}
context.Services.AddOpenTelemetry().UseAzureMonitor();
}
/// <summary>
/// Set Token for Registration & Password reset
/// </summary>
/// <param name="context"></param>
private void ConfigurePasswortResetToken(ServiceConfigurationContext context)
{
context.Services.Configure<DataProtectionTokenProviderOptions>(options =>
options.TokenLifespan = TimeSpan.FromDays(5));
}
private void ConfigureAuditLogging()
{
bool isEnabled = true;
// #if DEBUG
// isEnabled = false;
// #endif
Configure<AbpAuditingOptions>(options =>
{
options.IsEnabled = isEnabled;
options.IsEnabledForGetRequests = false;
options.EntityHistorySelectors.AddAllEntities();
});
}
private void ConfigurePages(IConfiguration configuration)
{
Configure<RazorPagesOptions>(options =>
{
options.Conventions.AuthorizePage("/HostDashboard", MyappDbPermissions.Dashboard.Host);
options.Conventions.AuthorizePage("/TenantDashboard", MyappDbPermissions.Dashboard.Tenant);
});
}
private void ConfigureUrls(IConfiguration configuration)
{
Configure<AppUrlOptions>(options => { options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"]; });
}
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.ForwardIdentityAuthenticationForBearer(OpenIddictValidationAspNetCoreDefaults
.AuthenticationScheme);
}
private void ConfigureImpersonation(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.Configure<AbpSaasHostWebOptions>(options => { options.EnableTenantImpersonation = false; });
context.Services.Configure<AbpIdentityWebOptions>(options => { options.EnableUserImpersonation = true; });
context.Services.Configure<AbpAccountOptions>(options =>
{
options.TenantAdminUserName = "admin";
options.ImpersonationTenantPermission = SaasHostPermissions.Tenants.Impersonation;
options.ImpersonationUserPermission = IdentityPermissions.Users.Impersonation;
});
}
private void ConfigureAutoMapper()
{
Configure<AbpAutoMapperOptions>(options => { options.AddMaps<MyappDbWebModule>(); });
}
private void ConfigureVirtualFileSystem(IWebHostEnvironment hostingEnvironment)
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<MyappDbWebModule>();
if (hostingEnvironment.IsDevelopment())
{
options.FileSets.ReplaceEmbeddedByPhysical<MyappDbDomainSharedModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
string.Format("..{0}MyappDb.Domain.Shared", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<MyappDbDomainModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
string.Format("..{0}MyappDb.Domain", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<MyappDbApplicationContractsModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
string.Format("..{0}MyappDb.Application.Contracts", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<MyappDbApplicationModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
string.Format("..{0}MyappDb.Application", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<MyappDbHttpApiModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
string.Format("..{0}..{0}src{0}MyappDb.HttpApi", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<MyappDbWebModule>(hostingEnvironment.ContentRootPath);
}
});
}
private void ConfigureNavigationServices()
{
Configure<AbpNavigationOptions>(options => { options.MenuContributors.Add(new MyappDbMenuContributor()); });
;
}
private void ConfigureAutoApiControllers()
{
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.Create(typeof(MyappDbApplicationModule).Assembly);
});
}
private void ConfigureSwaggerServices(IServiceCollection services)
{
services.AddAbpSwaggerGen(
options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "MyappDb API",
Version = "v1"
});
options.DocInclusionPredicate((docName, description) => true);
options.CustomSchemaIds(type => type.FullName);
options.DocumentFilter<CustomSwaggerFilter>(); //add new document filter
options.HideAbpEndpoints();
}
);
}
private void ConfigureExceptionHandling(ServiceConfigurationContext context)
{
context.Services.Configure<AbpExceptionHandlingOptions>(options =>
{
options.SendExceptionsDetailsToClients = true;
});
}
private void ConfigureHangfire(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.AddHangfire(config =>
{
config.UseSqlServerStorage(configuration.GetConnectionString("Default"));
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAbpRequestLocalization();
if (!env.IsDevelopment())
{
app.UseErrorPage();
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseCorrelationId();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
//if (MultiTenancyConsts.IsEnabled)
//{
// app.UseMultiTenancy();
//}
app.UseUnitOfWork();
app.UseAuthorization();
app.UseSwagger();
app.UseAbpSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "MyappDb API");
options.EnableFilter();
//add a new document filteroptions.DocumentFilter<CustomSwaggerFilter>();
});
if (!System.Diagnostics.Debugger.IsAttached)
{
app.UseAuditing();
}
app.UseAbpSerilogEnrichers();
app.UseConfiguredEndpoints();
//Configure User Access Permission requirements for hangfire
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
AsyncAuthorization = new[]
{
new AbpHangfireAuthorizationFilter(requiredPermissionName: "AbpAccount.SettingManagement")
}
});
}
}
Hi, I miss the language switch in the UI to change the language. I currently have 2 languages activated and have not made any changes to the theme. How can I switch the language switcher back on? Enclosed the source code, here should actually be the code for the language changer:
In the article you describe: < In this version, ABP Framework provides base classes and events to migrate the database schema and seed the database on application startup. This system works compatibly with multi-tenancy and whenever a new tenant is created or a tenant's database connection string has been updated, it checks and applies database migrations for the new tenant state.
This system is especially useful to migrate databases for microservices. In this way, when you deploy a new version of a microservice, you don't need to manually migrate its database.
You need to take the following actions to use the database migration system:
Create a class that derives from EfCoreRuntimeDatabaseMigratorBase class, override and implement its SeedAsync method. And lastly, execute the CheckAndApplyDatabaseMigrationsAsync method of your class in the OnPostApplicationInitializationAsync method of your module class. Create a class that derives from DatabaseMigrationEventHandlerBase class, override and implement its SeedAsync method. Then, whenever a new tenant is created or a tenant's connection string is changed then the SeedAsync method will be executed. >
I like to see a practcal implementation how to implement the described steps in a MVC application.
I know, however, in the post mentioned above you describe the new feature "In this version, ABP Framework provides base classes and events to migrate the database schema and seed the database on application startup. This system works compatibly with multi-tenancy and whenever a new tenant is created or a tenant's database connection string has been updated, it checks and applies database migrations for the new tenant state."
I like to have an practical example here how to implement it :)
You describe the new database migration system here: https://blog.abp.io/abp/ABP.IO-Platform-7-4-RC-Has-Been-Published I like to auto migrate my application on startup, however, the description is not total clear for me. Can you please bring an example how to implement it in a normal MVC application?
When running the "Update all ABP packages" I see that you install jquery from a version of 2018. This versions have a lot of known vulnerabilities. Could you please ensure that the latest javascript frontends are used?
Hi,
ok, bit of a shame that I have to rewrite all the tests now.
2 more questions:
Hi, Thanks this works for me. However, for my real project, I have a lot of seed methods. Is there any other way than adding the if condition to every insert statement now? In addition: In my project I have tests like following which fail with the same error. What should I do here?
[Fact]
public async Task CreateAsync()
{
// Arrange
var input = new CustomerCreateDto
{
Name = "bf64c99897834",
Street = "30b28c8ff57b464d9bc2f5618f15be1c75930a933aa140cb80f614f124bb3f0461f45",
Postcode = "aa2e0879154b4a2bbf78597283eb7e57",
City = "5f4242b5aa61476a97c3e5af411cf498521949a2ad2c47edbbbe",
Country = "c83c88797e63411f882bdd48759e99e87679b076e154472482c6e885b56830cf82abbd257b894cd0a8588a73ad277e3c7c6d",
VATNo = "d6d31592918a4f0f96ee23ad51a87e0ab5b0f1b49ccb41acbf85136106af9ba445de4a676ed14b4db27c63267679c6d8def4",
Status = default,
State = "76d47ce8de444b898aa5565717a4f154c746171559174f87a9fff21f832690097571c7457c7544b3a3041662529c371a881e"
};
// Act
var serviceResult = await _customersAppService.CreateAsync(input);
// Assert
var result = await _customerRepository.FindAsync(c => c.Id == serviceResult.Id);
result.ShouldNotBe(null);
result.Name.ShouldBe("bf64c99897834");
result.Street.ShouldBe("30b28c8ff57b464d9bc2f5618f15be1c75930a933aa140cb80f614f124bb3f0461f45");
result.Postcode.ShouldBe("aa2e0879154b4a2bbf78597283eb7e57");
result.City.ShouldBe("5f4242b5aa61476a97c3e5af411cf498521949a2ad2c47edbbbe");
result.Country.ShouldBe("c83c88797e63411f882bdd48759e99e87679b076e154472482c6e885b56830cf82abbd257b894cd0a8588a73ad277e3c7c6d");
result.VATNo.ShouldBe("d6d31592918a4f0f96ee23ad51a87e0ab5b0f1b49ccb41acbf85136106af9ba445de4a676ed14b4db27c63267679c6d8def4");
result.Status.ShouldBe(default);
result.State.ShouldBe("76d47ce8de444b898aa5565717a4f154c746171559174f87a9fff21f832690097571c7457c7544b3a3041662529c371a881e");
}