Skip to content

Commit

Permalink
Merge branch 'dev' into issue-datatableLoadingIndicator
Browse files Browse the repository at this point in the history
  • Loading branch information
oykuermann committed Oct 4, 2024
2 parents fb7f8ac + 22ee4f2 commit ce67141
Show file tree
Hide file tree
Showing 18 changed files with 213 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@
"VideoCourses": "Essential Videos",
"DoYouAgreePrivacyPolicy": "By clicking <b>Subscribe</b> button you agree to the <a href=\"https://account.abp.io/Account/TermsConditions\">Terms & Conditions</a> and <a href=\"https://account.abp.io/Account/Privacy\">Privacy Policy</a>.",
"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"
}
}
Original file line number Diff line number Diff line change
@@ -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
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
```

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<T>` and `ChannelReader<T>` 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<T>`, `ValueTask`, `ValueTask<T>` for `async` return types.



---

That's all the new features coming to SignalR in .NET 9!
Happy coding 🧑🏽‍💻
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions docs/en/modules/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ protected virtual async Task OnDataGridReadAsync(DataGridReadDataEventArgs<TList
{
CurrentSorting = e.Columns
.Where(c => c.SortDirection != SortDirection.Default)
.OrderBy(c => c.SortIndex)
.Select(c => c.SortField + (c.SortDirection == SortDirection.Descending ? " DESC" : ""))
.JoinAsString(",");
CurrentPage = e.Page;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ public CmdHelper(IOptionsSnapshot<AbpCliOptions> cliOptions)

public void Open(string pathOrUrl)
{
//directory might contain 'space' character
pathOrUrl = pathOrUrl.EnsureStartsWith('"');
pathOrUrl = pathOrUrl.EnsureEndsWith('"');

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
pathOrUrl = pathOrUrl.Replace("&", "^&");
Process.Start(new ProcessStartInfo("cmd", $"/c start {pathOrUrl}") { CreateNoWindow = true });
Process.Start(new ProcessStartInfo("cmd", $"/c start \"\" {pathOrUrl}") { CreateNoWindow = true });
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters;

public abstract class EFCore_DateTimeKindTests : DateTimeKind_Tests<AbpEntityFrameworkCoreTestModule>
{
[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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -84,8 +84,8 @@ await _commentAppService.CreateAsync(
}

[Theory]
[InlineData("[ABP Community](https://abp.io/community/)")]
[InlineData("<a href='https://abp.io/docs/latest'>abp.io/docs</a>")]
[InlineData("[ABP Community](https://community.abp.io/)")]
[InlineData("<a href='https://docs.abp.io/en/abp/latest'>docs.abp.io</a>")]
public async Task CreateAsync_ShouldThrowUserFriendlyException_If_Url_UnAllowed(string text)
{
_currentUser.Id.Returns(_cmsKitTestData.User2Id);
Expand All @@ -94,7 +94,7 @@ await Should.ThrowAsync<UserFriendlyException>(async () =>
await _commentAppService.CreateAsync(
_cmsKitTestData.EntityType1,
_cmsKitTestData.EntityId1,
new CreateCommentInput
new CreateCommentInput
{
RepliedCommentId = null,
Text = text, //not allowed URL
Expand All @@ -104,18 +104,18 @@ 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);

await Should.ThrowAsync<UserFriendlyException>(async () =>
await _commentAppService.CreateAsync(
_cmsKitTestData.EntityType1,
_cmsKitTestData.EntityId1,
new CreateCommentInput
new CreateCommentInput
{
RepliedCommentId = null,
Text = "<text>",
Text = "<text>",
IdempotencyToken = _cmsKitTestData.IdempotencyToken_1
}
));
Expand All @@ -139,7 +139,7 @@ public async Task UpdateAsync()
comment.Text.ShouldBe("I'm Updated");
});
}

[Fact]
public async Task UpdateAsync_ShouldThrowUserFriendlyException_If_Url_UnAllowed()
{
Expand All @@ -148,9 +148,9 @@ public async Task UpdateAsync_ShouldThrowUserFriendlyException_If_Url_UnAllowed(
await Should.ThrowAsync<UserFriendlyException>(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
}
));
}
Expand Down
25 changes: 13 additions & 12 deletions modules/docs/app/VoloDocs.Web/Program.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -9,7 +12,7 @@ namespace VoloDocs.Web
{
public class Program
{
public static int Main(string[] args)
public async static Task<int> Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug() //TODO: Should be configurable!
Expand All @@ -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<VoloDocsWebModule>();
var app = builder.Build();
await app.InitializeApplicationAsync();
await app.RunAsync();
return 0;
}
catch (Exception ex)
Expand All @@ -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<Startup>();
})
.UseAutofac()
.UseSerilog();
}
}
6 changes: 3 additions & 3 deletions modules/docs/app/VoloDocs.Web/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "https://localhost:44333/",
"sslPort": 0
"applicationUrl": "https://localhost:5001/",
"sslPort": 5001
}
},
"profiles": {
Expand All @@ -21,7 +21,7 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:44333/"
"applicationUrl": "https://localhost:5001/"
}
}
}
22 changes: 0 additions & 22 deletions modules/docs/app/VoloDocs.Web/Startup.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public async Task<Document> 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,
Expand Down
Loading

0 comments on commit ce67141

Please sign in to comment.