diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json index 82aabed272e..ed7781b4766 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json @@ -251,6 +251,7 @@ "VideoCourses": "Essential Videos", "DoYouAgreePrivacyPolicy": "By clicking Subscribe button you agree to the Terms & Conditions and Privacy Policy.", "AbpConferenceDescription": "ABP Conference is a virtual event for .NET developers to learn and connect with the community.", - "Mobile": "Mobile" + "Mobile": "Mobile", + "MetaTwitterCard": "summary_large_image" } } \ No newline at end of file diff --git a/docs/en/Community-Articles/2024-10-01-SignalR-9-New-Features/Post.md b/docs/en/Community-Articles/2024-10-01-SignalR-9-New-Features/Post.md new file mode 100644 index 00000000000..c004d45eba8 --- /dev/null +++ b/docs/en/Community-Articles/2024-10-01-SignalR-9-New-Features/Post.md @@ -0,0 +1,99 @@ +### ASP.NET Core SignalR New Features — Summary + +In this article, I’ll highlight the latest .**NET 9 SignalR updates** for ASP.NET Core 9.0. + +![Cover](cover.png) + + + +### SignalR Hub Accepts Base Classes + +SignalR `Hub` class can now get a base class of a polymorphic class. As you see in the example below, I can send `Animal` to `Process` method. Before .NET 9, we could only pass the derived classes: `Cat` and `Dog`. + +```csharp +/*** My Base Class is Animal ***/ +[JsonPolymorphic] +[JsonDerivedType(typeof(Cat), nameof(Cat))] +[JsonDerivedType(typeof(Dog), nameof(Dog))] +private class Animal +{ + public string Name { get; set; } +} + +/*** CAT derived from Animal ***/ +private class Cat : Animal +{ + public CatTypes CatType { get; set; } +} + +/*** DOG derived from Animal ***/ +private class Dog : Animal +{ + public DogTypes DogType { get; set; } +} + + +public class MyHub : Hub +{ + /*** We can use the base type Animal here ***/ + public void Process(Animal animal) + { + if (animal is Cat) { ... } + else if (animal is Dog) { ... } + } +} + +``` + + + +### Better Diagnostics and Telemetry + +Microsoft focuses mainly on .NET Aspire nowadays. That’s why SignalR now integrates more deeply with the .NET Activity API, which is commonly used for distributed tracing. The enhancement is implemented for better monitoring in [.NET Aspire Dashboard](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview?tabs=bash#using-the-dashboard-with-net-aspire-projects). To support this feature: + +1- Add these packages to your`csproj`: + +```xml + + + +``` + +2- Add the following startup code to your host project: + +```csharp +builder.Services.AddSignalR(); +/* After AddSignalR use AddOpenTelemetry() */ +builder + .Services + .AddOpenTelemetry() + .WithTracing(tracing => + { + if (builder.Environment.IsDevelopment()) + { + tracing.SetSampler(new AlwaysOnSampler()); //for dev env monitor all traces + } + + tracing.AddAspNetCoreInstrumentation(); + tracing.AddSource("Microsoft.AspNetCore.SignalR.Server"); + }); + +builder.Services.ConfigureOpenTelemetryTracerProvider(tracing => tracing.AddOtlpExporter()); +``` + +Finally, you’ll see the **SignalR Hub** events on the [Aspire Dashboard](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview): + +![.NET Aspire Activity Dashboard](signalr-activity-dashboard.png) + + + +### Trimming and Native AOT Support + +With .NET 9, **trimming** and **native** **Ahead Of Time** compilation are **supported**. This will improve our application performance. To support AOT, your SignalR object serialization needs to be JSON, and you must use the `System.Text.Json` s[ource generator](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation). Also on the server side, [you shouldn't use](https://github.com/dotnet/aspnetcore/issues/56179) `IAsyncEnumerable` and `ChannelReader` where `T` is a ValueType (`struct`) for Hub method arguments. One more limitation; [Strongly typed hubs](https://learn.microsoft.com/en-us/aspnet/core/signalr/hubs?view=aspnetcore-8.0#strongly-typed-hubs) aren't supported with Native AOT (`PublishAot`). And you should use only `Task`, `Task`, `ValueTask`, `ValueTask` for `async` return types. + + + +--- + +That's all the new features coming to SignalR in .NET 9! +Happy coding 🧑🏽‍💻 diff --git a/docs/en/Community-Articles/2024-10-01-SignalR-9-New-Features/cover.png b/docs/en/Community-Articles/2024-10-01-SignalR-9-New-Features/cover.png new file mode 100644 index 00000000000..d5e783520a5 Binary files /dev/null and b/docs/en/Community-Articles/2024-10-01-SignalR-9-New-Features/cover.png differ diff --git a/docs/en/Community-Articles/2024-10-01-SignalR-9-New-Features/signalr-activity-dashboard.png b/docs/en/Community-Articles/2024-10-01-SignalR-9-New-Features/signalr-activity-dashboard.png new file mode 100644 index 00000000000..44f167c603f Binary files /dev/null and b/docs/en/Community-Articles/2024-10-01-SignalR-9-New-Features/signalr-activity-dashboard.png differ diff --git a/docs/en/modules/docs.md b/docs/en/modules/docs.md index 6ab4f566c03..dc04339e78c 100644 --- a/docs/en/modules/docs.md +++ b/docs/en/modules/docs.md @@ -367,7 +367,7 @@ You can use [ABP](https://github.com/abpframework/abp/) GitHub documents to conf For `SQL` databases, you can use the below `T-SQL` command to insert the specified sample into your `DocsProjects` table: ```mssql -INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName], [ConcurrencyStamp]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs"}', N'/', NULL, N'', N'12f21123e08e4f15bedbae0b2d939659') +INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName], [ConcurrencyStamp]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP (GitHub)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'GitHub', N'{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs","GitHubAccessToken":"","GitHubUserAgent":""}', N'/', N'dev', N'', N'12f21123e08e4f15bedbae0b2d939659') ``` Be aware that `GitHubAccessToken` is masked. It's a private token and you must get your own token and replace the `***` string. @@ -407,7 +407,7 @@ You can use [ABP](https://github.com/abpframework/abp/) GitHub documents to conf For `SQL` databases, you can use the below `T-SQL` command to insert the specified sample into your `DocsProjects` table: ```mssql -INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs"}', N'/', NULL, N'') +INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName], [ConcurrencyStamp]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs"}', N'/', NULL, N'', N'12f21123e08e4f15bedbae0b2d939659') ``` Add one of the sample projects above and run the application. In the menu you will see `Documents` link, click the menu link to open the documents page. diff --git a/docs/en/release-info/migration-guides/abp-8-2.md b/docs/en/release-info/migration-guides/abp-8-2.md index cd904f052eb..15de922d4f0 100644 --- a/docs/en/release-info/migration-guides/abp-8-2.md +++ b/docs/en/release-info/migration-guides/abp-8-2.md @@ -16,9 +16,6 @@ This document is a guide for upgrading ABP v8.x solutions to ABP v8.2. There are Before this version, all of the projects above were targeting multiple frameworks (**netstandard2.0**, **netstandard2.1** and **net8.0**), with this version, we started to only target **net8.0** for these template projects. Note that, all other shared libraries still target multiple frameworks. > This change should not affect your pre-existing solutions and you don't need to make any changes in your application. See the PR for more info: https://github.com/abpframework/abp/pull/19565 -## Upgraded AutoMapper to 13.0.1 - -In this version, **AutoMapper** library version upgraded to 13.0.1. See [the release notes of AutoMapper v13.0.1](https://github.com/AutoMapper/AutoMapper/releases/tag/v13.0.1) for more information. ## Added default padding to `.tab-content` class for Basic Theme @@ -60,4 +57,62 @@ In this version, the Angular UI has been updated to use the Angular version 17.3 The **Session Management** feature allows you to prevent concurrent login and manage user sessions. -In this version, a new entity called `IdentitySession` has been added to the framework and you should create a new migration and apply it to your database. \ No newline at end of file +In this version, a new entity called `IdentitySession` has been added to the framework and you should create a new migration and apply it to your database. + +## Upgraded NuGet Dependencies + +You can see the following list of NuGet libraries that have been upgraded with this release, if you are using one of these packages explicitly, you may consider upgrading them in your solution: + +| Package | Old Version | New Version | +| ---------------------------------------------------------- | ----------- | ----------- | +| AutoMapper | 12.0.1 | 13.0.1 | +| Blazorise | 1.4.1 | 1.5.2 | +| Blazorise.Bootstrap5 | 1.4.1 | 1.5.2 | +| Blazorise.Icons.FontAwesome | 1.4.1 | 1.5.2 | +| Blazorise.Components | 1.4.1 | 1.5.2 | +| Blazorise.DataGrid | 1.4.1 | 1.5.2 | +| Blazorise.Snackbar | 1.4.1 | 1.5.2 | +| Hangfire.AspNetCore | 1.8.6 | 1.8.14 | +| Hangfire.SqlServer | 1.8.6 | 1.8.14 | +| Microsoft.AspNetCore.Authentication.JwtBearer | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.Authentication.OpenIdConnect | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.Authorization | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.Components | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.Components.Authorization | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.Components.Web | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.Components.WebAssembly | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.Components.WebAssembly.Server | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.Components.WebAssembly.Authentication | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.Components.WebAssembly.DevServer | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.DataProtection.StackExchangeRedis | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.Mvc.NewtonsoftJson | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.Mvc.Testing | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.TestHost | 8.0.0 | 8.0.4 | +| Microsoft.AspNetCore.WebUtilities | 8.0.0 | 8.0.4 | +| Microsoft.Data.SqlClient | 8.0.0 | 8.0.4 | +| Microsoft.EntityFrameworkCore | 8.0.0 | 8.0.4 | +| Microsoft.EntityFrameworkCore.Design | 8.0.0 | 8.0.4 | +| Microsoft.EntityFrameworkCore.InMemory | 8.0.0 | 8.0.4 | +| Microsoft.EntityFrameworkCore.Proxies | 8.0.0 | 8.0.4 | +| Microsoft.EntityFrameworkCore.Relational | 8.0.0 | 8.0.4 | +| Microsoft.EntityFrameworkCore.Sqlite | 8.0.0 | 8.0.4 | +| Microsoft.EntityFrameworkCore.SqlServer | 8.0.0 | 8.0.4 | +| Microsoft.EntityFrameworkCore.Tools | 8.0.0 | 8.0.4 | +| Microsoft.Extensions.DependencyInjection.Abstractions | 8.0.0 | 8.0.1 | +| Microsoft.Extensions.FileProviders.Embedded | 8.0.0 | 8.0.4 | +| Microsoft.Extensions.Logging.Abstractions | 8.0.0 | 8.0.1 | +| Microsoft.Extensions.Options | 8.0.0 | 8.0.2 | +| Microsoft.IdentityModel.Protocols.OpenIdConnect | - | 7.5.1 | +| Microsoft.IdentityModel.Tokens | - | 7.5.1 | +| Microsoft.IdentityModel.JsonWebTokens | - | 7.5.1 | +| System.IdentityModel.Tokens.Jwt | - | 7.5.1 | +| OpenIddict.Abstractions | 5.1.0 | 5.5.0 | +| OpenIddict.Core | 5.1.0 | 5.5.0 | +| OpenIddict.Server.AspNetCore | 5.1.0 | 5.5.0 | +| OpenIddict.Validation.AspNetCore | 5.1.0 | 5.5.0 | +| OpenIddict.Validation.ServerIntegration | 5.1.0 | 5.5.0 | +| Oracle.EntityFrameworkCore | 8.21.121 | 8.23.40 | +| Pomelo.EntityFrameworkCore.MySql | 8.0.0 | 8.0.2 | +| SixLabors.ImageSharp | 3.0.2 | 3.1.4 | + diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ValueConverters/EFCore_DateTimeKindTests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ValueConverters/EFCore_DateTimeKindTests.cs index c6fd04949a4..9cb1c003ba2 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ValueConverters/EFCore_DateTimeKindTests.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ValueConverters/EFCore_DateTimeKindTests.cs @@ -11,7 +11,7 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters; public abstract class EFCore_DateTimeKindTests : DateTimeKind_Tests { - [Fact] + [Fact(Skip = "https://github.com/dotnet/efcore/issues/34760")] public async Task DateTime_Kind_Should_Be_Normalized_In_View_Query_Test() { var personName = "bob lee"; diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Comments/CommentPublicAppService_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Comments/CommentPublicAppService_Tests.cs index e260e3debe6..adf650c2ba3 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Comments/CommentPublicAppService_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Comments/CommentPublicAppService_Tests.cs @@ -64,7 +64,7 @@ public async Task CreateAsync() .ShouldBeTrue(); }); } - + [Theory] [InlineData("https://abp.io/features")] public async Task CreateAsync_ShouldCreateComment_If_Url_Allowed(string text) @@ -84,8 +84,8 @@ await _commentAppService.CreateAsync( } [Theory] - [InlineData("[ABP Community](https://abp.io/community/)")] - [InlineData("abp.io/docs")] + [InlineData("[ABP Community](https://community.abp.io/)")] + [InlineData("docs.abp.io")] public async Task CreateAsync_ShouldThrowUserFriendlyException_If_Url_UnAllowed(string text) { _currentUser.Id.Returns(_cmsKitTestData.User2Id); @@ -94,7 +94,7 @@ await Should.ThrowAsync(async () => await _commentAppService.CreateAsync( _cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1, - new CreateCommentInput + new CreateCommentInput { RepliedCommentId = null, Text = text, //not allowed URL @@ -104,7 +104,7 @@ await _commentAppService.CreateAsync( } [Fact] - public async Task CreateAsync_ShouldThrowUserFriendlyException_If_IdempotencyToken_Not_Unique() + public async Task CreateAsync_ShouldThrowUserFriendlyException_If_IdempotencyToken_Not_Unique() { _currentUser.Id.Returns(_cmsKitTestData.User2Id); @@ -112,10 +112,10 @@ await Should.ThrowAsync(async () => await _commentAppService.CreateAsync( _cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1, - new CreateCommentInput + new CreateCommentInput { RepliedCommentId = null, - Text = "", + Text = "", IdempotencyToken = _cmsKitTestData.IdempotencyToken_1 } )); @@ -139,7 +139,7 @@ public async Task UpdateAsync() comment.Text.ShouldBe("I'm Updated"); }); } - + [Fact] public async Task UpdateAsync_ShouldThrowUserFriendlyException_If_Url_UnAllowed() { @@ -148,9 +148,9 @@ public async Task UpdateAsync_ShouldThrowUserFriendlyException_If_Url_UnAllowed( await Should.ThrowAsync(async () => await _commentAppService.UpdateAsync( _cmsKitTestData.CommentWithChildId, - new UpdateCommentInput + new UpdateCommentInput { - Text = "[ABP Community - Update](https://abp.io/community/)", //not allowed URL + Text = "[ABP Community - Update](https://community.abp.io/)", //not allowed URL } )); } diff --git a/modules/docs/app/VoloDocs.Web/Program.cs b/modules/docs/app/VoloDocs.Web/Program.cs index 5a0860f7273..c0373525db1 100644 --- a/modules/docs/app/VoloDocs.Web/Program.cs +++ b/modules/docs/app/VoloDocs.Web/Program.cs @@ -1,6 +1,9 @@ using System; using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Serilog; using Serilog.Events; @@ -9,7 +12,7 @@ namespace VoloDocs.Web { public class Program { - public static int Main(string[] args) + public async static Task Main(string[] args) { Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() //TODO: Should be configurable! @@ -22,7 +25,14 @@ public static int Main(string[] args) try { Log.Information("Starting web host."); - CreateHostBuilder(args).Build().Run(); + var builder = WebApplication.CreateBuilder(args); + builder.Host + .UseAutofac() + .UseSerilog(); + await builder.AddApplicationAsync(); + var app = builder.Build(); + await app.InitializeApplicationAsync(); + await app.RunAsync(); return 0; } catch (Exception ex) @@ -32,17 +42,8 @@ public static int Main(string[] args) } finally { - Log.CloseAndFlush(); + await Log.CloseAndFlushAsync(); } } - - internal static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }) - .UseAutofac() - .UseSerilog(); } } diff --git a/modules/docs/app/VoloDocs.Web/Properties/launchSettings.json b/modules/docs/app/VoloDocs.Web/Properties/launchSettings.json index 08e2199ddb4..2d88b20c15b 100644 --- a/modules/docs/app/VoloDocs.Web/Properties/launchSettings.json +++ b/modules/docs/app/VoloDocs.Web/Properties/launchSettings.json @@ -3,8 +3,8 @@ "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { - "applicationUrl": "https://localhost:44333/", - "sslPort": 0 + "applicationUrl": "https://localhost:5001/", + "sslPort": 5001 } }, "profiles": { @@ -21,7 +21,7 @@ "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, - "applicationUrl": "https://localhost:44333/" + "applicationUrl": "https://localhost:5001/" } } } diff --git a/modules/docs/app/VoloDocs.Web/Startup.cs b/modules/docs/app/VoloDocs.Web/Startup.cs deleted file mode 100644 index 22d7b980c5a..00000000000 --- a/modules/docs/app/VoloDocs.Web/Startup.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Volo.Abp; - -namespace VoloDocs.Web -{ - public class Startup - { - public void ConfigureServices(IServiceCollection services) - { - services.AddApplication(); - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) - { - app.InitializeApplication(); - } - } -} diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentSource.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentSource.cs index aba271272ab..e16f81d2c9c 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentSource.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentSource.cs @@ -32,6 +32,8 @@ public async Task GetDocumentAsync(Project project, string documentNam localDirectory = documentName.Substring(0, documentName.LastIndexOf('/')); } + version = File.GetLastWriteTime(path).ToString("yyyyMMddHHmmss"); + return new Document(GuidGenerator.Create(), project.Id, documentName,