mirror of https://github.com/abpframework/abp.git
committed by
GitHub
32 changed files with 380 additions and 50 deletions
@ -0,0 +1,94 @@ |
|||
# ABP.IO Platform 5.1 RC.1 Has Been Released |
|||
|
|||
Today, we are releasing the [ABP Framework](https://abp.io/) and the [ABP Commercial](https://commercial.abp.io/) version **5.1 RC** (Release Candidate). This blog post introduces the new features and important changes in this new version. |
|||
|
|||
> **The planned release date for the [5.1 stable](https://github.com/abpframework/abp/milestone/64) version is February 8, 2022**. |
|||
|
|||
Please try this version and provide feedback for a more stable ABP version 5.1! Thank you all. |
|||
|
|||
## Get Started with the 5.1 RC |
|||
|
|||
follow the steps below to try the version 5.1 RC today; |
|||
|
|||
1) **Upgrade** the ABP CLI to the version `5.1.0-rc.1` using a command line terminal: |
|||
|
|||
````bash |
|||
dotnet tool update Volo.Abp.Cli -g --version 5.1.0-rc.1 |
|||
```` |
|||
|
|||
**or install** if you haven't installed before: |
|||
|
|||
````bash |
|||
dotnet tool install Volo.Abp.Cli -g --version 5.1.0-rc.1 |
|||
```` |
|||
|
|||
2) Create a **new application** with the `--preview` option: |
|||
|
|||
````bash |
|||
abp new BookStore --preview |
|||
```` |
|||
|
|||
See the [ABP CLI documentation](https://docs.abp.io/en/abp/latest/CLI) for all the available options. |
|||
|
|||
> You can also use the *Direct Download* tab on the [Get Started](https://abp.io/get-started) page by selecting the **Preview checkbox**. |
|||
|
|||
You can use any IDE that supports .NET 6.0 development (e.g. [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/)). |
|||
|
|||
### Migration Notes & Breaking Changes |
|||
|
|||
TODO: Startup template changes |
|||
|
|||
## What's new with 5.1? |
|||
|
|||
In this section, I will introduce some major features released with this version. |
|||
|
|||
### DRAFT list of things done |
|||
|
|||
#### ABP Framework |
|||
|
|||
* Use new hosting model for the app template. [#10928](https://github.com/abpframework/abp/pull/10928) - what to do for existing solutions? |
|||
* Async application initialization methods on the AbpModule class [#6828](https://github.com/abpframework/abp/issues/6828) |
|||
* Angular 13? |
|||
* [#10552](https://github.com/abpframework/abp/pull/10696) Used file scoped namespaces :) |
|||
* Support markdown in CMS-Kit comments [#10792](https://github.com/abpframework/abp/pull/10792) |
|||
* eShopOnAbp is getting mature |
|||
* Nightly builds are working again |
|||
* Coming: New ABP.IO design! |
|||
|
|||
All issues & PRs in [5.1 milesone](https://github.com/abpframework/abp/milestone/60?closed=1). |
|||
|
|||
#### ABP Commercial |
|||
|
|||
* CMS Kit Pro: URL forwarding |
|||
* LeptonX is coming for ABP Blazor and MVC UI too (share the sample dashboard) |
|||
|
|||
### Header 1 |
|||
|
|||
TODO |
|||
|
|||
## Community News |
|||
|
|||
### ABP Community Talks 2021.1 |
|||
|
|||
 |
|||
|
|||
This is the second episode of the ABP Community Talks and we are talking about microservice development with the ABP Framework, based on the [eShopOnAbp](https://github.com/abpframework/eShopOnAbp) reference solution. This live meeting will be at **January 20, 2022, 17:00 (UTC)** on YouTube. |
|||
|
|||
**Join this event on the Kommunity platform: https://kommunity.com/volosoft/events/abp-community-talks-20221-microservice-development-acd0f44b** |
|||
|
|||
You can also [subscribe to the Volosoft channel](https://www.youtube.com/channel/UCO3XKlpvq8CA5MQNVS6b3dQ) for reminders for further ABP events and videos. |
|||
|
|||
### New ABP Community posts |
|||
|
|||
Here, some of the recent posts added to the [ABP community](https://community.abp.io/): |
|||
|
|||
* [Minimal API development with the ABP Framework](https://community.abp.io/articles/minimal-api-with-abp-hello-world-part-1-sg5i44p8) by [@antosubash](https://github.com/antosubash) (three parts, video tutorial). |
|||
* [Integrating the Syncfusion MVC Components to the ABP MVC UI](https://community.abp.io/articles/integrating-the-syncfusion-mvc-components-to-the-abp-mvc-ui-0gpkr1if) by [@EngincanV](https://github.com/EngincanV). |
|||
* [Add Tailwind CSS to your ABP Blazor UI](https://community.abp.io/articles/add-tailwindcss-to-your-abp-blazor-ui-vidiwzcy) by [@antosubash](https://github.com/antosubash) (video tutorial). |
|||
* [Import external users into the users Table from an ABP Framework application](https://community.abp.io/articles/import-external-users-into-the-users-table-from-an-abp-framework-application-7lnyw415) by [@bartvanhoey](https://github.com/bartvanhoey). |
|||
|
|||
Thanks to the ABP Community for all the contents they have published. You can also [post your ABP and .NET related (text or video) contents](https://community.abp.io/articles/submit) to the ABP Community. |
|||
|
|||
## Conclusion |
|||
|
|||
In this blog post, I summarized the news about that new version and the ABP Community. Please try it and provide feedback by opening issues on [the GitHub repository](https://github.com/abpframework/abp). Thank you all! |
|||
|
After Width: | Height: | Size: 559 KiB |
@ -0,0 +1,52 @@ |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
|
|||
namespace Volo.Abp.EventBus; |
|||
|
|||
public class EventHandlerInvoker : IEventHandlerInvoker, ISingletonDependency |
|||
{ |
|||
private readonly ConcurrentDictionary<string, EventHandlerInvokerCacheItem> _cache; |
|||
|
|||
public EventHandlerInvoker() |
|||
{ |
|||
_cache = new ConcurrentDictionary<string, EventHandlerInvokerCacheItem>(); |
|||
} |
|||
|
|||
public async Task InvokeAsync(IEventHandler eventHandler, object eventData, Type eventType) |
|||
{ |
|||
var cacheItem = _cache.GetOrAdd($"{eventHandler.GetType().FullName}-{eventType.FullName}", _ => |
|||
{ |
|||
var item = new EventHandlerInvokerCacheItem(); |
|||
|
|||
if (typeof(ILocalEventHandler<>).MakeGenericType(eventType).IsInstanceOfType(eventHandler)) |
|||
{ |
|||
item.Local = (IEventHandlerMethodExecutor)Activator.CreateInstance(typeof(LocalEventHandlerMethodExecutor<>).MakeGenericType(eventType)); |
|||
} |
|||
|
|||
if (typeof(IDistributedEventHandler<>).MakeGenericType(eventType).IsInstanceOfType(eventHandler)) |
|||
{ |
|||
item.Distributed = (IEventHandlerMethodExecutor)Activator.CreateInstance(typeof(DistributedEventHandlerMethodExecutor<>).MakeGenericType(eventType)); |
|||
} |
|||
|
|||
return item; |
|||
}); |
|||
|
|||
if (cacheItem.Local != null) |
|||
{ |
|||
await cacheItem.Local.ExecutorAsync(eventHandler, eventData); |
|||
} |
|||
|
|||
if (cacheItem.Distributed != null) |
|||
{ |
|||
await cacheItem.Distributed.ExecutorAsync(eventHandler, eventData); |
|||
} |
|||
|
|||
if (cacheItem.Local == null && cacheItem.Distributed == null) |
|||
{ |
|||
throw new AbpException("The object instance is not an event handler. Object type: " + eventHandler.GetType().AssemblyQualifiedName); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
namespace Volo.Abp.EventBus; |
|||
|
|||
public class EventHandlerInvokerCacheItem |
|||
{ |
|||
public IEventHandlerMethodExecutor Local { get; set; } |
|||
|
|||
public IEventHandlerMethodExecutor Distributed { get; set; } |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
|
|||
namespace Volo.Abp.EventBus; |
|||
|
|||
public delegate Task EventHandlerMethodExecutorAsync(IEventHandler target, object parameter); |
|||
|
|||
public interface IEventHandlerMethodExecutor |
|||
{ |
|||
EventHandlerMethodExecutorAsync ExecutorAsync { get; } |
|||
} |
|||
|
|||
public class LocalEventHandlerMethodExecutor<TEvent> : IEventHandlerMethodExecutor |
|||
where TEvent : class |
|||
{ |
|||
public EventHandlerMethodExecutorAsync ExecutorAsync => (target, parameter) => target.As<ILocalEventHandler<TEvent>>().HandleEventAsync(parameter.As<TEvent>()); |
|||
|
|||
public Task ExecuteAsync(IEventHandler target, TEvent parameters) |
|||
{ |
|||
return ExecutorAsync(target, parameters); |
|||
} |
|||
} |
|||
|
|||
public class DistributedEventHandlerMethodExecutor<TEvent> : IEventHandlerMethodExecutor |
|||
where TEvent : class |
|||
{ |
|||
public EventHandlerMethodExecutorAsync ExecutorAsync => (target, parameter) => target.As<IDistributedEventHandler<TEvent>>().HandleEventAsync(parameter.As<TEvent>()); |
|||
|
|||
public Task ExecuteAsync(IEventHandler target, TEvent parameters) |
|||
{ |
|||
return ExecutorAsync(target, parameters); |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.EventBus; |
|||
|
|||
public interface IEventHandlerInvoker |
|||
{ |
|||
Task InvokeAsync(IEventHandler eventHandler, object eventData, Type eventType); |
|||
} |
|||
@ -0,0 +1,128 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Shouldly; |
|||
using Volo.Abp.Domain.Entities; |
|||
using Volo.Abp.Domain.Entities.Events; |
|||
using Volo.Abp.Domain.Entities.Events.Distributed; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
using Volo.Abp.EventBus.Local; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.EventBus; |
|||
|
|||
public class EventHandlerInvoker_Tests : EventBusTestBase |
|||
{ |
|||
private readonly IEventHandlerInvoker _eventHandlerInvoker; |
|||
|
|||
public EventHandlerInvoker_Tests() |
|||
{ |
|||
_eventHandlerInvoker = GetRequiredService<IEventHandlerInvoker>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_Invoke_LocalEventHandler_With_MyEventData() |
|||
{ |
|||
var localHandler = new MyLocalEventHandler(); |
|||
var eventData = new MyEventData(); |
|||
|
|||
await _eventHandlerInvoker.InvokeAsync(localHandler, eventData, eventData.GetType()); |
|||
|
|||
localHandler.MyEventDataCount.ShouldBe(2); |
|||
localHandler.EntityChangedEventDataCount.ShouldBe(0); |
|||
localHandler.EntityChangedEventDataCount.ShouldBe(0); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_Invoke_LocalEventHandler_Created_And_Changed_Once() |
|||
{ |
|||
var localHandler = new MyLocalEventHandler(); |
|||
var eventData = new EntityCreatedEventData<MyEntity>(new MyEntity()); |
|||
|
|||
await _eventHandlerInvoker.InvokeAsync(localHandler, eventData, eventData.GetType()); |
|||
await _eventHandlerInvoker.InvokeAsync(localHandler, eventData, typeof(EntityChangedEventData<MyEntity>)); |
|||
|
|||
localHandler.MyEventDataCount.ShouldBe(0); |
|||
localHandler.EntityChangedEventDataCount.ShouldBe(1); |
|||
localHandler.EntityChangedEventDataCount.ShouldBe(1); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_Invoke_DistributedEventHandler_With_MyEventData() |
|||
{ |
|||
var localHandler = new MyDistributedEventHandler(); |
|||
var eventData = new MyEventData(); |
|||
|
|||
await _eventHandlerInvoker.InvokeAsync(localHandler, eventData, eventData.GetType()); |
|||
|
|||
localHandler.MyEventDataCount.ShouldBe(1); |
|||
localHandler.EntityCreatedCount.ShouldBe(0); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_Invoke_DistributedEventHandler_With_EntityCreatedEto() |
|||
{ |
|||
var localHandler = new MyDistributedEventHandler(); |
|||
var eventData = new EntityCreatedEto<MyEntity>(new MyEntity()); |
|||
|
|||
await _eventHandlerInvoker.InvokeAsync(localHandler, eventData, eventData.GetType()); |
|||
|
|||
localHandler.MyEventDataCount.ShouldBe(0); |
|||
localHandler.EntityCreatedCount.ShouldBe(1); |
|||
} |
|||
|
|||
public class MyEventData |
|||
{ |
|||
} |
|||
|
|||
public class MyEntity : Entity<Guid> |
|||
{ |
|||
|
|||
} |
|||
|
|||
public class MyDistributedEventHandler : IDistributedEventHandler<MyEventData>, |
|||
IDistributedEventHandler<EntityCreatedEto<MyEntity>> |
|||
{ |
|||
public int MyEventDataCount { get; set; } |
|||
public int EntityCreatedCount { get; set; } |
|||
|
|||
public Task HandleEventAsync(MyEventData eventData) |
|||
{ |
|||
MyEventDataCount++; |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
public Task HandleEventAsync(EntityCreatedEto<MyEntity> eventData) |
|||
{ |
|||
EntityCreatedCount++; |
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
|
|||
public class MyLocalEventHandler : ILocalEventHandler<MyEventData>, |
|||
IDistributedEventHandler<MyEventData>, |
|||
IDistributedEventHandler<EntityCreatedEventData<MyEntity>>, |
|||
IDistributedEventHandler<EntityChangedEventData<MyEntity>> |
|||
{ |
|||
public int MyEventDataCount { get; set; } |
|||
public int EntityCreatedEventDataCount { get; set; } |
|||
public int EntityChangedEventDataCount { get; set; } |
|||
|
|||
public Task HandleEventAsync(MyEventData eventData) |
|||
{ |
|||
MyEventDataCount++; |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
public Task HandleEventAsync(EntityCreatedEventData<MyEntity> eventData) |
|||
{ |
|||
EntityCreatedEventDataCount++; |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
public Task HandleEventAsync(EntityChangedEventData<MyEntity> eventData) |
|||
{ |
|||
EntityChangedEventDataCount++; |
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue