diff --git a/docs/en/Previews.md b/docs/en/Previews.md index 5d52a4ad69..61cf1c9226 100644 --- a/docs/en/Previews.md +++ b/docs/en/Previews.md @@ -1,6 +1,6 @@ # Preview Releases -The preview versions are released **~2 weeks before** releasing a major or feature version of the ABP Framework. They are released for developers to try and provide feedback to have more stable versions. +The preview versions are released **~4 weeks before** releasing a major or feature version of the ABP Framework. They are released for developers to try and provide feedback to have more stable versions. Versioning of a preview release is like that: @@ -37,4 +37,4 @@ abp switch-to-stable ## Providing Feedback -You can open an issue on the [GitHub repository](https://github.com/abpframework/abp/issues/new), if you find a bug or want to provide any kind of feedback. \ No newline at end of file +You can open an issue on the [GitHub repository](https://github.com/abpframework/abp/issues/new), if you find a bug or want to provide any kind of feedback. diff --git a/docs/en/Tutorials/Part-1.md b/docs/en/Tutorials/Part-1.md index 93bf3d4a0b..ef1c58346a 100644 --- a/docs/en/Tutorials/Part-1.md +++ b/docs/en/Tutorials/Part-1.md @@ -202,7 +202,7 @@ This will add a new migration class to the project: ![bookstore-efcore-migration](./images/bookstore-efcore-migration.png) -> If you are using Visual Studio, you may want to use the `Add-Migration Created_Book_Entity -c BookStoreMigrationsDbContext` and `Update-Database -c BookStoreMigrationsDbContext` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} is the startup project and `Acme.BookStore.EntityFrameworkCore` is the *Default Project* in PMC. +> If you are using Visual Studio, you may want to use the `Add-Migration Created_Book_Entity -c BookStoreDbContext` and `Update-Database -ContextBookStoreDbContext` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} is the startup project and `Acme.BookStore.EntityFrameworkCore` is the *Default Project* in PMC. {{end}} diff --git a/docs/en/Tutorials/Part-10.md b/docs/en/Tutorials/Part-10.md index f0c182b661..2525a7918c 100644 --- a/docs/en/Tutorials/Part-10.md +++ b/docs/en/Tutorials/Part-10.md @@ -126,7 +126,7 @@ migrationBuilder.AddForeignKey( * Creates an index on the `AuthorId` field. * Declares the foreign key to the `AppAuthors` table. -> If you are using Visual Studio, you may want to use `Add-Migration Added_AuthorId_To_Book -c BookStoreMigrationsDbContext` and `Update-Database -c BookStoreMigrationsDbContext` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} is the startup project and `Acme.BookStore.EntityFrameworkCore` is the *Default Project* in PMC. +> If you are using Visual Studio, you may want to use `Add-Migration Added_AuthorId_To_Book -c BookStoreDbContext` and `Update-Database -ContextBookStoreDbContext` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} is the startup project and `Acme.BookStore.EntityFrameworkCore` is the *Default Project* in PMC. {{end}} diff --git a/docs/en/Tutorials/Part-7.md b/docs/en/Tutorials/Part-7.md index 3284ae98d4..06f06e3f72 100644 --- a/docs/en/Tutorials/Part-7.md +++ b/docs/en/Tutorials/Part-7.md @@ -93,7 +93,7 @@ You can apply changes to the database using the following command, in the same c dotnet ef database update ```` -> If you are using Visual Studio, you may want to use `Add-Migration Added_Authors -c BookStoreMigrationsDbContext` and `Update-Database -c BookStoreMigrationsDbContext` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} is the startup project and `Acme.BookStore.EntityFrameworkCore` is the *Default Project* in PMC. +> If you are using Visual Studio, you may want to use `Add-Migration Added_Authors -c BookStoreDbContext` and `Update-Database -ContextBookStoreDbContext` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} is the startup project and `Acme.BookStore.EntityFrameworkCore` is the *Default Project* in PMC. {{else if DB=="Mongo"}} diff --git a/docs/zh-Hans/Emailing.md b/docs/zh-Hans/Emailing.md index d285e5bde2..22edc50301 100644 --- a/docs/zh-Hans/Emailing.md +++ b/docs/zh-Hans/Emailing.md @@ -1,3 +1,256 @@ -# Emailing +# 邮件发送系统 -待添加 \ No newline at end of file +ABP 框架为发送电子邮件提供各种服务、设置和集成; + +* 提供用于发送电子邮件的`IEmailSender`服务. +* 定义 [settings](Settings.md)来配置电子邮件发送. +* 集成到[后台作业系统](Background-Jobs.md)以通过后台作业发送电子邮件. +* 提供[MailKit 集成](MailKit.md)包. + +## 安装 + +> 如果你使用的是[应用程序启动模板](Startup-Templates/Application.md),则该软件包已安装。 +> +建议使用 [ABP CLI](CLI.md) 安装此包。在项目文件夹(.csproj 文件)中打开命令行窗口并键入以下命令: + +````bash +abp add-package Volo.Abp.Emailing +```` +如果你还没有做到这一点,你首先需要安装 ABP CLI。有关其他安装选项,请参阅 [包描述页面](https://abp.io/package-detail/Volo.Abp.Emailing)。 + +## 发送电子邮件 + +### IEmailSender + +[Inject](Dependency-Injection.md) 将 `IEmailSender` 注入任何服务并使用 `SendAsync` 方法发送电子邮件。 +**Example** + +````csharp +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Emailing; + +namespace MyProject +{ + public class MyService : ITransientDependency + { + private readonly IEmailSender _emailSender; + + public MyService(IEmailSender emailSender) + { + _emailSender = emailSender; + } + + public async Task DoItAsync() + { + await _emailSender.SendAsync( + "target@domain.com", // target email address + "Email subject", // subject + "This is email body..." // email body + ); + } + } +} +```` + +`SendAsync` 方法具有重载以提供更多参数,例如; + +* **from**: 你可以将其设置为设置发件人电子邮件地址。如果未提供,则使用默认发件人地址(请参阅下面的电子邮件设置) +* **isBodyHtml**: 表示邮件正文是否可以包含HTML标签。**默认:true**。 + +> `IEmailSender` 是建议的发送邮件的方式,因为它使你的代码提供者独立。 + +#### 邮件消息 + +除了原始参数之外,你还可以传递一个**标准的 `MailMessage` 对象**([参见](https://docs.microsoft.com/en-us/dotnet/api/system.net.mail.mailmessage) ) 到 `SendAsync` 方法以设置更多选项,例如添加附件。 + +### ISmtpEmailSender + +默认情况下,发送电子邮件由标准的 `SmtpClient` 类([参见](https://docs.microsoft.com/en-us/dotnet/api/system.net.mail.smtpclient))实现。实现类是`SmtpEmailSender`。此类还公开了 `ISmtpEmailSender` 服务(除了 `IEmailSender`)。 + +大多数时候你想直接使用`IEmailSender`来让你的代码提供者独立。但是,如果要创建具有相同电子邮件设置的 `SmtpClient` 对象,可以注入 `ISmtpEmailSender` 并使用其 `BuildClientAsync` 方法获取 `SmtpClient` 对象并自己发送电子邮件。 + +## 发送邮件任务队列/后台作业 + +`IEmailSender`有一个`QueueAsync`方法,可以用来将邮件添加到后台作业队列中,在后台线程中发送。通过这种方式,你不会因为等待发送邮件而占用用户的时间。`QueueAsync`方法得到的参数与`SendAsync`方法相同。 + +发送邮件任务队列可以容忍错误,因为后台作业系统具有重试机制来克服临时网络/服务器问题。 + +有关后台作业系统的更多信息,请参阅[后台作业文档](Background-Jobs.md)。 + +## 电子邮件设置 + +电子邮件发送使用 [设置系统](Settings.md) 来定义设置并在运行时获取这些设置的值。 `Volo.Abp.Emailing.EmailSettingNames` 定义了设置名称的常量,如下所示: + +* **Abp.Mailing.DefaultFromAddress**: 当你在发送电子邮件时未指定发件人时,用作发件人的电子邮件地址(就像上面的示例一样). +* **Abp.Mailing.DefaultFromDisplayName**: 当你在发送电子邮件时未指定发件人时,用作发件人的显示名称(就像在上面的示例中一样). +* **Abp.Mailing.Smtp.Host**: SMTP 服务器的 IP/域(默认值:127.0.0.1)。 +* **Abp.Mailing.Smtp.Port**: SMTP 服务器的端口(默认值:25). +* **Abp.Mailing.Smtp.UserName**: 用户名,如果 SMTP 服务器需要身份验证需要。 +* **Abp.Mailing.Smtp.Password**: 密码,如果 SMTP 服务器需要身份验证需要。 **此值已加密**(请参阅下面的部分). +* **Abp.Mailing.Smtp.Domain**: 账号域,如果 SMTP 服务器需要身份验证需要. +* **Abp.Mailing.Smtp.EnableSsl**: 指示 SMTP 服务器是否使用 SSL 的值(“true”或“false”。默认值:“false”). +* **Abp.Mailing.Smtp.UseDefaultCredentials**:如果为 true,则使用默认凭据,而不是提供的用户名和密码(“true”或“false”。默认值:“true”)。. + +可以从[设置管理](Modules/Setting-Management.md)模块的*设置页面*管理电子邮件设置: + +![email-settings](images/email-settings.png) + +>如果你已从 ABP 启动模板创建解决方案,则已安装设置管理模块。 + +如果你不使用设置管理模块,你可以简单地在 `appsettings.json` 文件中定义设置: + +````json +"Settings": { + "Abp.Mailing.Smtp.Host": "127.0.0.1", + "Abp.Mailing.Smtp.Port": "25", + "Abp.Mailing.Smtp.UserName": "", + "Abp.Mailing.Smtp.Password": "", + "Abp.Mailing.Smtp.Domain": "", + "Abp.Mailing.Smtp.EnableSsl": "false", + "Abp.Mailing.Smtp.UseDefaultCredentials": "true", + "Abp.Mailing.DefaultFromAddress": "noreply@abp.io", + "Abp.Mailing.DefaultFromDisplayName": "ABP application" +} +```` + +You can set/change these settings programmatically using the `ISettingManager` and store values in a database. See the [setting system document](Settings.md) to understand the setting system better. +你可以使用 `ISettingManager` 以编程方式设置/更改这些设置,并将值存储在数据库中。请参阅 [设置系统文档](Settings.md)更好地了解设置系统。 + +### 加密 SMTP 密码 + +*Abp.Mailing.Smtp.Password* 必须是一个**加密**值。如果你使用 `ISettingManager` 设置密码,你不必担心。它在内部加密 set 上的值并在 get 上解密。 + +如果使用 `appsettings.json` 存储密码,则应手动注入 `ISettingEncryptionService` 并使用其 `Encrypt` 方法获取加密值。这可以通过在你的应用程序中创建一个简单的代码来完成。然后你可以删除代码。更好的是,你可以在应用程序中创建一个 UI 来配置电子邮件设置。在这种情况下,你可以直接使用 `ISettingManager` 而不用担心加密。 + +### ISmtpEmailSenderConfiguration + +如果你不想使用设置系统来存储电子邮件发送配置,你可以将 `ISmtpEmailSenderConfiguration` 服务替换为你自己的实现,以从任何其他来源获取配置。 `ISmtpEmailSenderConfiguration` 默认由 `SmtpEmailSenderConfiguration` 实现,如上所述,它从设置系统中获取配置。 + +## 文本模板集成 + +ABP 框架提供了一个强大而灵活的[文本模板系统](Text-Templating.md)。你可以使用文本模板系统来创建动态电子邮件内容。注入 `ITemplateRenderer` 并使用 `RenderAsync` 渲染模板。然后将结果用作电子邮件正文。 + +虽然你可以定义和使用自己的文本模板,但电子邮件发送系统提供了两个简单的内置文本模板。 + +**示例:使用标准和简单的消息模板发送电子邮件** + +````csharp +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Emailing; +using Volo.Abp.Emailing.Templates; +using Volo.Abp.TextTemplating; + +namespace Acme.BookStore.Web +{ + public class MyService : ITransientDependency + { + private readonly IEmailSender _emailSender; + private readonly ITemplateRenderer _templateRenderer; + + public MyService( + IEmailSender emailSender, + ITemplateRenderer templateRenderer) + { + _emailSender = emailSender; + _templateRenderer = templateRenderer; + } + + public async Task DoItAsync() + { + var body = await _templateRenderer.RenderAsync( + StandardEmailTemplates.Message, + new + { + message = "This is email body..." + } + ); + + await _emailSender.SendAsync( + "target-address@domain.com", + "Email subject", + body + ); + } + } +} +```` + +生成的电子邮件正文将如下所示: + +````html + + + + + + + This is email body... + + +```` + +电子邮件系统定义了具有给定名称的内置文本模板: + +"**Abp.StandardEmailTemplates.Message**" 是最简单的带有文本消息的模板: + +````html +{%{{{model.message}}}%} +```` + +此模板使用“Abp.StandardEmailTemplates.Layout”作为其布局. + +"**Abp.StandardEmailTemplates.Layout**" 是一个提供 HTML 文档布局的简单模板: + +````html + + + + + + + {%{{{content}}}%} + + +```` + +最终呈现的消息如上所示。 + +> 这些模板名称是在 `Volo.Abp.Emailing.Templates.StandardEmailTemplates` 类中定义的。 + +### 覆盖/替换标准模板 + +You typically want to replace the standard templates with your own ones, so you can prepare a branded email messages. To do that, you can use the power of the [virtual file system](Virtual-File-System.md) (VFS) or replace them in your own template definition provider. +你希望用自己的模板替换标准模板,这样你就可以准备电子邮件模板文件。你可以使用 [虚拟文件系统](Virtual-File-System.md) (VFS),或在你自己的模板定义提供程序中替换它们。 + +虚拟文件系统中模板的路径如下图所示: + +* `/Volo/Abp/Emailing/Templates/Layout.tpl` +* `/Volo/Abp/Emailing/Templates/Message.tpl` + +如果你将文件添加到虚拟文件系统中的相同位置,你的文件将覆盖它们。 + +模板是内联本地化的,这意味着你可以利用 [本地化系统](Localization.md) 的强大功能使你的模板具有多元文化。 + +详见[文本模板系统](Text-Templating.md) 文档。 + +> 请注意,你可以为应用程序定义和使用自己的模板,而不是使用标准的简单模板。这些标准模板主要用于可重用的模块,它们不定义自己的模板,而是依赖内置的模板。只需覆盖标准的电子邮件布局模板,就可以轻松自定义使用的模块发送的电子邮件。 + +## NullEmailSender + +`NullEmailSender` 是实现 `IEmailSender` 的内置类,但将电子邮件内容写入 [标准日志系统](Logging.md),而不是实际发送电子邮件。 + +这个类特别有用,尤其是在你开发是不想发送真实电子邮件。 [应用启动模板](Startup-Templates/Application.md)已经在**DEBUG模式**中使用了这个类,在领域层配置如下: + +````csharp +#if DEBUG + context.Services.Replace(ServiceDescriptor.Singleton()); +#endif +```` + +因此,你在 DEBUG 模式下不会收到电子邮件。电子邮件将在生产时按预期发送(RELEASE 模式)。如果你也想在 DEBUG 上发送电子邮件,请删除这些行。 + +## 其他 + +* [用于发送电子邮件的MailKit集成](MailKit.md) diff --git a/docs/zh-Hans/Tutorials/Part-1.md b/docs/zh-Hans/Tutorials/Part-1.md index 927463e100..b06643c7c0 100644 --- a/docs/zh-Hans/Tutorials/Part-1.md +++ b/docs/zh-Hans/Tutorials/Part-1.md @@ -202,7 +202,7 @@ dotnet ef migrations add Created_Book_Entity ![bookstore-efcore-migration](./images/bookstore-efcore-migration.png) -> 如果你使用Visual Studio, 你也许想要在*包管理控制台(PMC)*中使用 `Add-Migration Created_Book_Entity -c BookStoreMigrationsDbContext` 和 `Update-Database -c BookStoreMigrationsDbContext` 命令. 确保 {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} 是启动项目并且 `Acme.BookStore.EntityFrameworkCore.DbMigrations` 是 PMC 的*默认项目*. +> 如果你使用Visual Studio, 你也许想要在*包管理控制台(PMC)*中使用 `Add-Migration Created_Book_Entity -c BookStoreDbContext` 和 `Update-Database -Context BookStoreDbContext` 命令. 确保 {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} 是启动项目并且 `Acme.BookStore.EntityFrameworkCore.DbMigrations` 是 PMC 的*默认项目*. {{end}} @@ -290,7 +290,7 @@ namespace Acme.BookStore using System; using Volo.Abp.Application.Dtos; -namespace Acme.BookStore +namespace Acme.BookStore.Books { public class BookDto : AuditedEntityDto { diff --git a/docs/zh-Hans/Tutorials/Part-7.md b/docs/zh-Hans/Tutorials/Part-7.md index 95b016e451..d799b9ab4f 100644 --- a/docs/zh-Hans/Tutorials/Part-7.md +++ b/docs/zh-Hans/Tutorials/Part-7.md @@ -93,7 +93,7 @@ dotnet ef migrations add Added_Authors dotnet ef database update ```` -> 如果你使用 Visual Studio, 可能希望在 *Package Manager Console (PMC)* 使用 `Add-Migration Added_Authors -c BookStoreMigrationsDbContext` 和 `Update-Database -c BookStoreMigrationsDbContext` 命令. 如果这样, 保证 {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} 是启动项目并且在PMC中 `Acme.BookStore.EntityFrameworkCore` 是 *默认项目* . +> 如果你使用 Visual Studio, 可能希望在 *Package Manager Console (PMC)* 使用 `Add-Migration Added_Authors -c BookStoreDbContext` 和 `Update-Database -Context BookStoreDbContext` 命令. 如果这样, 保证 {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} 是启动项目并且在PMC中 `Acme.BookStore.EntityFrameworkCore` 是 *默认项目* . {{else if DB=="Mongo"}} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs index 10fbc3bfb7..f38f433fa3 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars; using Volo.Abp.BlazoriseUI; +using System.Linq; +using System.Collections.ObjectModel; namespace Volo.Abp.AspNetCore.Components.Web.Theming.Layout; @@ -30,8 +32,8 @@ public partial class PageHeader : ComponentBase [Parameter] // TODO: Consider removing this property in future and use only PageLayout. public List BreadcrumbItems { - get => PageLayout.BreadcrumbItems; - set => PageLayout.BreadcrumbItems = value; + get => PageLayout.BreadcrumbItems.ToList(); + set => PageLayout.BreadcrumbItems = new ObservableCollection(value); } [Parameter] @@ -53,7 +55,10 @@ public partial class PageHeader : ComponentBase if (!Options.Value.RenderToolbar) { PageLayout.ToolbarItems.Clear(); - PageLayout.ToolbarItems.AddRange(toolbarItems); + foreach (var item in toolbarItems) + { + PageLayout.ToolbarItems.Add(item); + } return; } diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageLayout.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageLayout.cs index 9c0d89f70a..618445bd83 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageLayout.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageLayout.cs @@ -1,16 +1,29 @@ -using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; using Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars; using Volo.Abp.BlazoriseUI; using Volo.Abp.DependencyInjection; namespace Volo.Abp.AspNetCore.Components.Web.Theming.Layout; -public class PageLayout : IScopedDependency +public class PageLayout : IScopedDependency, INotifyPropertyChanged { + private string title; + // TODO: Consider using this property for setting Page Title too. - public virtual string Title { get; set; } + public virtual string Title + { + get => title; + set + { + title = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title))); + } + } + + public virtual ObservableCollection BreadcrumbItems { get; set; } = new(); - public virtual List BreadcrumbItems { get; set; } = new(); + public virtual ObservableCollection ToolbarItems { get; set; } = new(); - public virtual List ToolbarItems { get; set; } = new(); + public event PropertyChangedEventHandler PropertyChanged; } \ No newline at end of file diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml index 0c73d85bb3..1ffdf2595e 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml @@ -5,7 +5,7 @@ var elementId = string.IsNullOrEmpty(menuItem.ElementId) ? string.Empty : $"id=\"{menuItem.ElementId}\""; var cssClass = string.IsNullOrEmpty(menuItem.CssClass) ? string.Empty : menuItem.CssClass; var disabled = menuItem.IsDisabled ? "disabled" : string.Empty; - var url = string.IsNullOrEmpty(menuItem.Url) ? "#" : Url.Content(menuItem.Url); + var url = string.IsNullOrEmpty(menuItem.Url) ? "#" : Url.IsLocalUrl(menuItem.Url) ? Url.Content(menuItem.Url.EnsureStartsWith('~')) : menuItem.Url; if (menuItem.IsLeaf) { if (menuItem.Url != null) diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/_MenuItem.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/_MenuItem.cshtml index 8e9de286e5..2dc72b8e58 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/_MenuItem.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/_MenuItem.cshtml @@ -4,7 +4,7 @@ var elementId = string.IsNullOrEmpty(Model.ElementId) ? string.Empty : $"id=\"{Model.ElementId}\""; var cssClass = string.IsNullOrEmpty(Model.CssClass) ? string.Empty : Model.CssClass; var disabled = Model.IsDisabled ? "disabled" : string.Empty; - var url = string.IsNullOrEmpty(Model.Url) ? "#" : Url.Content(Model.Url); + var url = string.IsNullOrEmpty(Model.Url) ? "#" : Url.IsLocalUrl(Model.Url) ? Url.Content(Model.Url.EnsureStartsWith('~')) : Model.Url; } @if (Model.IsLeaf) { diff --git a/npm/ng-packs/packages/theme-basic/src/lib/tests/lazy-style.handler.spec.ts b/npm/ng-packs/packages/theme-basic/src/lib/tests/lazy-style.handler.spec.ts index dec4744a6c..dd0591f9fd 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/tests/lazy-style.handler.spec.ts +++ b/npm/ng-packs/packages/theme-basic/src/lib/tests/lazy-style.handler.spec.ts @@ -4,7 +4,7 @@ import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest'; import { of } from 'rxjs'; import { BOOTSTRAP, createLazyStyleHref, LazyStyleHandler } from '../handlers'; -const languageChange$ = of({ payload: 'en' }); +const currentLang$ = of({ payload: 'en' }); describe('LazyStyleHandler', () => { let spectator: SpectatorService; @@ -17,7 +17,7 @@ describe('LazyStyleHandler', () => { DocumentDirHandlerService, { provide: LocalizationService, - useValue: { currentLang: 'en', languageChange$ }, + useValue: { currentLang: 'en', currentLang$ }, }, ], });