Browse Source

Merge branch 'dev' into auto-merge/prerel-9-0/3101

pull/21132/head
maliming 1 year ago
committed by GitHub
parent
commit
a26537c5ff
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 3
      Directory.Packages.props
  2. 4
      common.props
  3. 4
      docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/How to use Aspire with ABP framework.md
  4. 63
      docs/en/Community-Articles/2024-10-09-Cookies-vs-Local-Storage/Post.md
  5. BIN
      docs/en/Community-Articles/2024-10-09-Cookies-vs-Local-Storage/cover.png
  6. 96
      docs/en/Community-Articles/2024-10-09-NET9-Performance-Improvements/Post.md
  7. BIN
      docs/en/Community-Articles/2024-10-09-NET9-Performance-Improvements/cited-from-microsoft-blog-post.png
  8. BIN
      docs/en/Community-Articles/2024-10-09-NET9-Performance-Improvements/cover.png
  9. 138
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/POST.md
  10. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-overall-diagram.png
  11. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-add-existing-package.png
  12. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-add-new-microservice.png
  13. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-solution-runner.png
  14. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-vs-dotnet-aspire-comparison-table.png
  15. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/cover.png
  16. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/dotnet-aspire-dashboard.png
  17. 6
      docs/en/framework/architecture/domain-driven-design/specifications.md
  18. 3
      framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj
  19. 26
      framework/src/Volo.Abp.Core/Volo/Abp/Threading/SemaphoreSlimExtensions.cs
  20. 2
      modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/Properties/launchSettings.json
  21. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/Properties/launchSettings.json
  22. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Properties/launchSettings.json
  23. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/Properties/launchSettings.json
  24. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/Properties/launchSettings.json
  25. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered/Properties/launchSettings.json
  26. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp/Properties/launchSettings.json
  27. 2
      templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Properties/launchSettings.json
  28. 2
      test/AbpPerfTest/AbpPerfTest.WithAbp/Properties/launchSettings.json
  29. 2
      test/AbpPerfTest/AbpPerfTest.WithoutAbp/Properties/launchSettings.json

3
Directory.Packages.props

@ -6,7 +6,7 @@
<PackageVersion Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="3.0.0" />
<PackageVersion Include="aliyun-net-sdk-sts" Version="3.1.2" />
<PackageVersion Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
<PackageVersion Include="AsyncKeyedLock" Version="7.0.1" />
<PackageVersion Include="AsyncKeyedLock" Version="7.0.2" />
<PackageVersion Include="Autofac" Version="8.1.0" />
<PackageVersion Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
<PackageVersion Include="Autofac.Extras.DynamicProxy" Version="7.1.0" />
@ -166,6 +166,7 @@
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="System.Text.Encodings.Web" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="System.Text.Json" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.1.0" />
<PackageVersion Include="TimeZoneConverter" Version="6.1.0" />
<PackageVersion Include="Unidecode.NET" Version="2.1.0" />

4
common.props

@ -1,8 +1,8 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>9.0.0-rc.1</Version>
<LeptonXVersion>4.0.0-rc.1</LeptonXVersion>
<Version>9.1.0-preview</Version>
<LeptonXVersion>4.1.0-preview</LeptonXVersion>
<NoWarn>$(NoWarn);CS1591;CS0436</NoWarn>
<PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl>
<PackageProjectUrl>https://abp.io/</PackageProjectUrl>

4
docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/How to use Aspire with ABP framework.md

@ -300,3 +300,7 @@ After making all our changes, we can run the `AspirationalAbp.AppHost` project.
## Conclusion
Combining .NET Aspire with the ABP framework creates a powerful setup for building robust, observable, and feature-rich applications. By integrating Aspire's observability and cloud capabilities with ABP's approach of focusing on your business without repeating yourself, you can develop feature-rich, scalable applications with enhanced monitoring and seamless cloud integration. This guide provides a clear path to set up and configure these technologies, ensuring your applications are well-structured, maintainable, and ready for modern cloud environments.
## See Also
* [.NET Aspire vs ABP Studio: Side by Side](https://abp.io/community/articles/.net-aspire-vs-abp-studio-side-by-side-t1c73d1l)

63
docs/en/Community-Articles/2024-10-09-Cookies-vs-Local-Storage/Post.md

@ -0,0 +1,63 @@
# When to Use Cookies, When to Use Local Storage?
![cover](cover.png)
## Cookies vs Local Storage
When you want to save client-side data on browsers, you can use `Cookies` or `Local Storage` of the browser. While these methods look similar, they have different behaviors. You need to decide based on the specific use-case, security concerns and the data size being stored. I'll clarify the differences between these methods.
## When to use Cookies 🍪?
1. **Server Communication (e.g: Authentication Tokens):** Cookies are ideal when you need to send data automatically with HTTP requests to the server, such as authentication tokens (JWTs) or session IDs. Cookies can be configured to be sent only to specific domains or paths, making them useful for session management.
2. **Cross-Domain Communication:** Cookies can be shared across subdomains, which is useful when working with multiple subdomains under the same parent domain for microservice architecture.
3. **Expiration Control:** Cookies come with built-in expiration times. You don’t need to manually remove them after a certain period that should expire.
4. **Security:** Cookies can be marked as `HttpOnly` which makes them accessible **only via the server**, not via JavaScript! Also, when you set a cookie attribute, `Secure` it can be sent only over HTTPS, which forces enhanced security for sensitive data.
### Considerations for Cookies
- **Size Limitation:** Cookies are generally limited to around 4KB of data.
- **Security Risks:** Cookies are susceptible to cross-site scripting (XSS) attacks unless marked `HttpOnly`.
---
## When to use Local Storage🗄️?
1. **Client-Side Data Storage:** Local storage is ideal for storing large amounts of data (up to 5–10 MB) that doesn’t need to be sent to the server with every request. For example; *user preferences*, *settings*, or *cached data*.
2. **Persistence:** Data in local storage persists even after the browser is restarted. This behavior makes it useful for long-term storage needs.
3. **No Automatic Server Transmission:** Local storage data is never automatically sent to the server, which can be a security advantage if you don’t want certain data to be exposed to the server or included in the requests.
### Considerations for Local Storage
- **Security Risks:** Local storage is accessible via JavaScript, making it vulnerable to XSS attacks. Sensitive data should not be stored in local storage unless adequately encrypted.
- **No Expiration Mechanism:** Local storage does not have a built-in expiration mechanism. You must manually remove the data when it’s no longer needed.
---
## Summary
### Use Cookies
- For data that needs to be sent to the server with HTTP requests, particularly for session management or authentication purposes.
### Use Local Storage
- For storing large amounts of client-side data that doesn’t need to be automatically sent to the server and for data that should persist across browser sessions.
In many cases, you might use both cookies and local storage, depending on the specific requirements of different parts of your application. There are also other places where you can store the client-side data. You can check out [this article](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage) for more information.
Happy coding 🧑🏽‍💻

BIN
docs/en/Community-Articles/2024-10-09-Cookies-vs-Local-Storage/cover.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 KiB

96
docs/en/Community-Articles/2024-10-09-NET9-Performance-Improvements/Post.md

@ -0,0 +1,96 @@
# .NET 9 Performance Improvements Summary
With every release, .NET becomes faster & faster! You get these improvements for free by just updating your project to the latest .NET!
![Cover Image](cover.png)
It’s very interesting that **20% of these improvements** are implemented by **open-source volunteers** rather than Microsoft employees. These improvements mostly focus on cloud-native and high-throughput applications. I’ll briefly list them below.
![From Microsoft Blog Post](cited-from-microsoft-blog-post.png)
## 1. Dynamic PGO with JIT Compiler
* ### What is dynamic PGO?
With “Profile Guided Optimization” the compiler optimizes the code, based on the flow and the way the code executes. It is predicated on the idea that every potential behavior of the code will always transpire.
* ### What’s Improved?
The tiered compilation, inlining, and dynamic PGO are three ways that .NET 9 optimizes the JIT compiler. This enhances runtime performance and speeds up the time for apps to launch.
* ### Performance Gains
CPU use is lower during execution; therefore, **startup times are about 15% faster**.
* ### As a Developer
Faster, smoother deployments with reduced warm-up times... These enhancements reduce latency for applications with complex workflows, particularly in microservices and high-throughput environments.
* ### How to activate Dynamic PGO?
Add the following to your `csproj` file, or if you have several `csproj` files, you can add it once in `Directory.Build.props` file. Check out [this link](https://learn.microsoft.com/en-us/dotnet/core/runtime-config/compilation#profile-guided-optimization) to understand PGO.
```xml
<PropertyGroup>
<TieredPGO>true</TieredPGO>
</PropertyGroup>
```
## 2. Library Improvements
* ### What’s Improved?
LINQ and JSON serialization, collections and libraries are significantly improved with .NET 9.
* ### Performance Gains
**JSON serialization** performance **increases by about 35%**. This helps with heavy data parsing and API requests. Less memory is allocated to `Span` operations as well, and LINQ techniques such as `Where` and `Select` are now faster.
* ### As a Developer
This means that apps will be faster, especially those that handle data primarily in JSON or manipulate data with LINQ.
## 3. ASP.NET Core
* ### What’s Improved?
Kestrel server has undergone significant modifications, mostly in processing the HTTP/2 and HTTP/3 protocols.
* ### Performance Gains
Now, **Kestrel handles requests up to 20% faster** and **has a 25% reduction in average latency**. Improved connection management and SSL processing also result in overall efficiency gains.
* ### As a Developer
These modifications result in less resource use, quicker response times for web applications, and more seamless scaling in high-traffic situations.
## 4. Garbage Collection & Memory Management
* ### What’s Improved?
NET 9’s garbage collection (GC) is more effective, especially for apps with high allocation rates.
* ### Performance Gains
Applications experience smoother **garbage collection cycles with 8–12% less memory overhead**, which lowers latency and delays.
* ### As a Developer
The performance will be more reliable and predictable for developers as there will be fewer memory-related bottlenecks, particularly in applications that involve frequent object allocations.
## 5. Native AOT Compilation
* ### What’s Improved?
Native AOT (Ahead-of-Time) compilation is now more efficient by lowering memory footprint and cold-start times. This leads to better support for cloud-native applications.
* ### Performance Gains
Native AOT apps now have faster cold launches and use **30–40% less memory**. This improvement focuses on containerized applications.
---
**References:**
* [Microsoft .NET blog post](https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-9/).
* [What’s new in the .NET 9 runtime?](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-9/runtime#performance-improvements)

BIN
docs/en/Community-Articles/2024-10-09-NET9-Performance-Improvements/cited-from-microsoft-blog-post.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

BIN
docs/en/Community-Articles/2024-10-09-NET9-Performance-Improvements/cover.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 KiB

138
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/POST.md

@ -0,0 +1,138 @@
# .NET Aspire vs ABP Studio: Side by Side
In this article, I will compare [.NET Aspire](https://learn.microsoft.com/en-us/dotnet/aspire/) by [ABP Studio](https://abp.io/docs/latest/studio) by explaining their similarities and differences.
![cover](cover.png)
## Introduction
While .NET Aspire and ABP Studio are tools for different purpose with different scope and they have different approaches to solve the problems, many developers still may confuse since they also have some similar functionalities and solves some common problems.
In this article, I will clarify all, and you will have a clear understanding of what are the similarities and differences of them. Let's start by briefly define what are .NET Aspire and ABP Studio.
### What is .NET Aspire?
**[.NET Aspire](https://learn.microsoft.com/en-us/dotnet/aspire/)** is a **cloud-ready framework** designed to simplify building distributed, observable, and production-ready applications. It provides a set of opinionated tools and NuGet packages tailored for cloud-native concerns like **orchestration**, **service integration** (e.g., Redis, PostgreSQL), and **telemetry**. Aspire focuses on the **local development experience**, making it easier to manage complex, multi-service apps by **abstracting away configuration details**.
Here, a screenshot from [.NET Aspire dashboard](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview) that is used for application monitoring and inspection:
![dotnet-aspire-dashboard](dotnet-aspire-dashboard.png)
### What is ABP Studio?
**[ABP Studio](https://abp.io/docs/latest/studio)** is a cross-platform **desktop application** designed to **simplify development** on the ABP Framework by **automating various tasks** and offering a streamlined, **integrated development environment**. It allows developers to **build**, **run**, **test**, **monitor**, and **deploy applications** more efficiently. With features like Kubernetes integration and support for complex multi-application systems, ABP Studio **enhances productivity**, especially in **microservice or modular monolith architectures**.
Here, a screenshot from the ABP Studio [Solution Runner panel](https://abp.io/docs/latest/studio/running-applications) that is used to run, browse, monitor and inspect applications:
![abp-studio-solution-runner](abp-studio-solution-runner.png)
## A Brief Comparison
Before deep diving details, I want to show a **table of features** to compare ABP Studio and .NET Aspire side by side:
![abp-studio-vs-net-aspire-comparison-table](abp-studio-vs-dotnet-aspire-comparison-table.png)
## Comparing the Features
In the next sections, I will go through each feature and explain differences and similarities.
### Integration Packages
ABP Framework has tens of integration packages to 3rd-party libraries and services. .NET Aspire also has some library integrations. But these integrations have different purposes:
* **ABP Framework**'s integrations (like [MongoDB](https://abp.io/docs/latest/framework/data/mongodb), [RabbitMQ](https://abp.io/docs/latest/framework/infrastructure/background-jobs/rabbitmq), [Dapr](https://abp.io/docs/latest/framework/dapr), etc) are integrations for its abstractions and aimed to be **used directly by your application code**. They are complete and sophisticated integrations with the ABP Framework and your codebase.
* **.NET Aspire**'s integrations (like [MongoDB](https://learn.microsoft.com/en-us/dotnet/aspire/database/mongodb-integration), [RabbitMQ](https://learn.microsoft.com/en-us/dotnet/aspire/messaging/rabbitmq-integration), [Dapr](https://learn.microsoft.com/en-us/dotnet/aspire/frameworks/dapr), etc), on the other hand, for simplifying configuration, service discovery, orchestration and monitoring of these tools within .NET Aspire host. Basically, these are mostly for **integrating to .NET Aspire**, not for integrating to your application.
For example, ABP's [MongoDB](https://abp.io/docs/latest/framework/data/mongodb) integration allows you to use MongoDB over [repository services](https://abp.io/docs/latest/framework/architecture/domain-driven-design/repositories), automatically handles database transactions, [audit logs](https://abp.io/docs/latest/framework/infrastructure/audit-logging), [event publishing](https://abp.io/docs/latest/framework/infrastructure/event-bus/distributed) on data saves, dynamic [connection string](https://abp.io/docs/latest/framework/fundamentals/connection-strings) management, [multi-tenancy](https://abp.io/docs/latest/framework/architecture/multi-tenancy) integration and so on.
On the other hand, .NET Aspire's [MongoDB](https://learn.microsoft.com/en-us/dotnet/aspire/database/mongodb-integration) integration basically adds [MongoDB driver library](https://www.nuget.org/packages/MongoDB.Driver/) to your .NET Aspire host application and configures it so you can discover MongoDB server on runtime, use a MongoDB Docker container and see its health status, logs and traces on .NET Aspire dashboard.
### Starter Templates
Both of ABP Studio and .NET Aspire provide **startup solution templates for new applications**. However, there are huge differences between these startup solution templates and their purpose are completely different.
* ABP Studio provides **production-ready** and [advanced solution templates](https://abp.io/docs/latest/solution-templates) for **layered**, **modular** or **microservice** solution development. They are well configured for **local development** and deploying to **Kubernetes** and other **production environments**. They provide different **UI and database options**, many optional modules and configuration. For example, you can check the [microservice solution template](https://abp.io/docs/latest/solution-templates/microservice/overview) to see how **sophisticated** it is.
* .NET Aspire's [project templates](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/setup-tooling?tabs=windows&pivots=visual-studio#net-aspire-project-templates)' main purpose is to provide a minimal application structure that is **pre-integrated to .NET Aspire** libraries and configured for **local development** environment.
So, when you start with .NET Aspire project template, you will need to deal with a lot of work to make your solution production and enterprise ready. On the other hand, ABP Studio's solution templates are ready to lunch your system from the first day and they provide you a perfect starting point for your new business idea.
### Monitoring & Application Running
Monitoring applications and services is an important requirement for building **complex distributed systems**. Both of ABP Studio and .NET Aspire provide **excellent tools** for that purpose.
* ABP Studio's [Solution Runner panel](https://abp.io/docs/latest/studio/running-applications) provides a powerful UI to run and monitor application and services. You can see all HTTP requests, distributed events, exceptions and detailed application logs, trace and find problems in your system. You can use its fully functional built-in browser to navigate application UIs easily. You can also create multiple profiles to group and configure the applications for different teams.
* .NET Aspire's [dashboard](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview) can be used to see the states of the running applications and containers, explore their console output, logs, traces and metrics to understand what is happing in your distributed system.
Both tools are pretty useful for monitoring. In addition to monitoring, **ABP Studio offers an advanced UI to control the running applications**, build, start and stop individually or by a group of applications.
### Architecting / Building Solutions
One of the unique features of **ABP Studio** is that it **is an architectural tool** that helps you create the structure and architecture of your solution. You can create any kind of application, from **single-layer** simple web applications to **layered multi-application** solutions, from **monolith modular** to **microservice** systems. In the next section, I will briefly explains these architectural features.
#### Building Modular Monolith Solutions
With ABP Studio, you can create a new solution, **create modules and establish relations** (dependencies) between modules to architect your overall **modular monolith system** easily.
Here, a screenshot where we are adding an existing package reference to the Products module of a modular CRM solution:
![abp-studio-add-existing-package](abp-studio-add-existing-package.png)
You can see the [Modular Application Development tutorial](https://abp.io/docs/latest/tutorials/modular-crm) to learn how to build such an application step by step.
#### Building Microservice Solutions
ABP Studio provides a full featured [microservice startup solution template](https://abp.io/docs/latest/solution-templates/microservice) and the fundamental tooling to build **large-scale microservice systems**.
Here a screenshot that shows how to add new microservices, API gateways or web applications to a microservice solution:
![abp-studio-add-new-microservice](abp-studio-add-new-microservice.png)
.NET Aspire has no such a feature and has no such a plan to provide that kind of architectural solution building experience.
### Kubernetes Integration
Another great ABP Studio feature is [Kubernetes Integration](https://abp.io/docs/latest/studio/kubernetes). It allows you to develop your distributed / microservice solutions as integrated to [Kubernetes](https://kubernetes.io/).
Here, a few tasks you can accomplish using ABP Studio's Kubernetes integration:
* **Build docker images** of your applications and services
* **Install and uninstall Helm charts** to your Kubernetes cluster
* **Connect to internal services** of your Kubernetes cluster
* **Monitor** services and applications that are running in your Kubernetes cluster
* **Intercept traffic** of a service and redirect requests to your local machine. In that way, you can develop, test and run individual services or applications in your local computer that is **fully integrated** to other services and applications running in Kubernetes.
ABP Studio's Kubernetes Integration makes microservice development so easy and comfortable. On the other hand, .NET Aspire has no such a Kubernetes integrated development experience.
## The ABP Platform
Until now, I directly compared ABP Studio and .NET Aspire features. .NET Aspire is directly built on .NET and ASP.NET Core. However, ABP Studio is not a standalone tool that is built on .NET and ASP.NET Core. It is built on the [ABP Platform](https://abp.io/) (which is built on .NET and ASP.NET Core).
The following diagram shows ABP Platform components at a glance:
![abp-overall-diagram](abp-overall-diagram.png)
So, when you use ABP Studio, you also take full power of the [open source ABP Framework](https://github.com/abpframework/abp) and other ABP Platform features.
## ABP and .NET Aspire Integration
I have a good news to you. It is actually possible and pretty easy to make ABP Platform and .NET Aspire working together.
You can check [@berkansasmaz](https://abp.io/community/members/berkansasmaz)'s great article: **[How to use .NET Aspire with ABP framework](https://abp.io/community/articles/how-to-use-.net-aspire-with-abp-framework-h29km4kk)**.
## Licensing
ABP Studio has a Community Edition which is completely free and available to everyone. It includes many of the features I mentioned here. There is also a commercial edition that is included in [commercial ABP licenses](https://abp.io/pricing). You can [check that blog post](https://abp.io/blog/announcing-abp-studio-general-availability) which clearly explains the license differences and introduces the fundamental ABP Studio features.
On the other hand, .NET Aspire is a free tool developed and published by Microsoft. It has no commercial version.
## Conclusion
Both .NET Aspire and ABP Studio serve distinct purposes, catering to different types of development environments. While .NET Aspire excels in simplifying cloud-native application setups and observability, ABP Studio provides a comprehensive framework for modular monoliths and microservice architectures with full-fledged enterprise level production-ready startup solution templates and integrated tools.
In the previous section, it was mentioned that it is possible to [use them together](https://abp.io/community/articles/how-to-use-.net-aspire-with-abp-framework-h29km4kk). You don't have to select one of them. However, in my opinion, when you use ABP Studio, you won't need .NET Aspire since ABP Studio can do everything and much more. If you have budget, I suggest to purchase a commercial ABP Studio [license](https://abp.io/pricing) so you can fully unlock its power.
## Resources / Further Reading
* [ABP Studio documentation](https://abp.io/docs/latest/studio)
* [.NET Aspire documentation](https://learn.microsoft.com/en-us/dotnet/aspire/)
* [How to use .NET Aspire with ABP framework](https://abp.io/community/articles/how-to-use-.net-aspire-with-abp-framework-h29km4kk)

BIN
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-overall-diagram.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

BIN
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-add-existing-package.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-add-new-microservice.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-solution-runner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

BIN
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-vs-dotnet-aspire-comparison-table.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

BIN
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/cover.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB

BIN
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/dotnet-aspire-dashboard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

6
docs/en/framework/architecture/domain-driven-design/specifications.md

@ -81,7 +81,7 @@ namespace MyProject
{
public class CustomerService : ITransientDependency
{
public async Task BuyAlcohol(Customer customer)
public async Task BookRoom(Customer customer)
{
if (!new Age18PlusCustomerSpecification().IsSatisfiedBy(customer))
{
@ -120,7 +120,7 @@ namespace MyProject
_customerRepository = customerRepository;
}
public async Task<List<Customer>> GetCustomersCanBuyAlcohol()
public async Task<List<Customer>> GetCustomersCanBookRoom()
{
var queryable = await _customerRepository.GetQueryableAsync();
var query = queryable.Where(
@ -254,4 +254,4 @@ Some benefits of using specifications:
### When To Not Use?
- **Non business expressions**: Do not use specifications for non business-related expressions and operations.
- **Reporting**: If you are just creating a report, do not create specifications, but directly use `IQueryable` & LINQ expressions. You can even use plain SQL, views or another tool for reporting. DDD does not necessarily care about reporting, so the way you query the underlying data store can be important from a performance perspective.
- **Reporting**: If you are just creating a report, do not create specifications, but directly use `IQueryable` & LINQ expressions. You can even use plain SQL, views or another tool for reporting. DDD does not necessarily care about reporting, so the way you query the underlying data store can be important from a performance perspective.

3
framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj

@ -33,6 +33,9 @@
<PackageReference Include="JetBrains.Annotations" />
<PackageReference Include="Nito.AsyncEx.Context" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="System.Threading.Tasks.Extensions" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFrameworkIdentifier)' == '.NETStandard' And $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '2.1')) ">
<PackageReference Include="System.ComponentModel.Annotations" />
</ItemGroup>

26
framework/src/Volo.Abp.Core/Volo/Abp/Threading/SemaphoreSlimExtensions.cs

@ -1,4 +1,5 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
@ -6,19 +7,22 @@ namespace Volo.Abp.Threading;
public static class SemaphoreSlimExtensions
{
public async static Task<IDisposable> LockAsync(this SemaphoreSlim semaphoreSlim)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public async static ValueTask<IDisposable> LockAsync(this SemaphoreSlim semaphoreSlim)
{
await semaphoreSlim.WaitAsync();
return GetDispose(semaphoreSlim);
}
public async static Task<IDisposable> LockAsync(this SemaphoreSlim semaphoreSlim, CancellationToken cancellationToken)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public async static ValueTask<IDisposable> LockAsync(this SemaphoreSlim semaphoreSlim, CancellationToken cancellationToken)
{
await semaphoreSlim.WaitAsync(cancellationToken);
return GetDispose(semaphoreSlim);
}
public async static Task<IDisposable> LockAsync(this SemaphoreSlim semaphoreSlim, int millisecondsTimeout)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public async static ValueTask<IDisposable> LockAsync(this SemaphoreSlim semaphoreSlim, int millisecondsTimeout)
{
if (await semaphoreSlim.WaitAsync(millisecondsTimeout))
{
@ -28,7 +32,8 @@ public static class SemaphoreSlimExtensions
throw new TimeoutException();
}
public async static Task<IDisposable> LockAsync(this SemaphoreSlim semaphoreSlim, int millisecondsTimeout, CancellationToken cancellationToken)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public async static ValueTask<IDisposable> LockAsync(this SemaphoreSlim semaphoreSlim, int millisecondsTimeout, CancellationToken cancellationToken)
{
if (await semaphoreSlim.WaitAsync(millisecondsTimeout, cancellationToken))
{
@ -38,7 +43,8 @@ public static class SemaphoreSlimExtensions
throw new TimeoutException();
}
public async static Task<IDisposable> LockAsync(this SemaphoreSlim semaphoreSlim, TimeSpan timeout)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public async static ValueTask<IDisposable> LockAsync(this SemaphoreSlim semaphoreSlim, TimeSpan timeout)
{
if (await semaphoreSlim.WaitAsync(timeout))
{
@ -48,7 +54,8 @@ public static class SemaphoreSlimExtensions
throw new TimeoutException();
}
public async static Task<IDisposable> LockAsync(this SemaphoreSlim semaphoreSlim, TimeSpan timeout, CancellationToken cancellationToken)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public async static ValueTask<IDisposable> LockAsync(this SemaphoreSlim semaphoreSlim, TimeSpan timeout, CancellationToken cancellationToken)
{
if (await semaphoreSlim.WaitAsync(timeout, cancellationToken))
{
@ -58,18 +65,21 @@ public static class SemaphoreSlimExtensions
throw new TimeoutException();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IDisposable Lock(this SemaphoreSlim semaphoreSlim)
{
semaphoreSlim.Wait();
return GetDispose(semaphoreSlim);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IDisposable Lock(this SemaphoreSlim semaphoreSlim, CancellationToken cancellationToken)
{
semaphoreSlim.Wait(cancellationToken);
return GetDispose(semaphoreSlim);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IDisposable Lock(this SemaphoreSlim semaphoreSlim, int millisecondsTimeout)
{
if (semaphoreSlim.Wait(millisecondsTimeout))
@ -80,6 +90,7 @@ public static class SemaphoreSlimExtensions
throw new TimeoutException();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IDisposable Lock(this SemaphoreSlim semaphoreSlim, int millisecondsTimeout, CancellationToken cancellationToken)
{
if (semaphoreSlim.Wait(millisecondsTimeout, cancellationToken))
@ -90,6 +101,7 @@ public static class SemaphoreSlimExtensions
throw new TimeoutException();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IDisposable Lock(this SemaphoreSlim semaphoreSlim, TimeSpan timeout)
{
if (semaphoreSlim.Wait(timeout))
@ -100,6 +112,7 @@ public static class SemaphoreSlimExtensions
throw new TimeoutException();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IDisposable Lock(this SemaphoreSlim semaphoreSlim, TimeSpan timeout, CancellationToken cancellationToken)
{
if (semaphoreSlim.Wait(timeout, cancellationToken))
@ -110,6 +123,7 @@ public static class SemaphoreSlimExtensions
throw new TimeoutException();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static IDisposable GetDispose(this SemaphoreSlim semaphoreSlim)
{
return new DisposeAction<SemaphoreSlim>(static (semaphoreSlim) =>

2
modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/Properties/launchSettings.json

@ -17,7 +17,7 @@
},
"Volo.Abp.SettingManagement.DemoApp": {
"commandName": "Project",
"dotnetRunMessages": "true",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/Properties/launchSettings.json

@ -17,7 +17,7 @@
},
"MyCompanyName.MyProjectName.Blazor.Server": {
"commandName": "Project",
"dotnetRunMessages": "true",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:44300/",
"environmentVariables": {

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Properties/launchSettings.json

@ -17,7 +17,7 @@
},
"MyCompanyName.MyProjectName.Blazor.Server": {
"commandName": "Project",
"dotnetRunMessages": "true",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:44300/",
"environmentVariables": {

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/Properties/launchSettings.json

@ -17,7 +17,7 @@
},
"MyCompanyName.MyProjectName.Blazor.Server.Tiered": {
"commandName": "Project",
"dotnetRunMessages": "true",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:44309/",
"environmentVariables": {

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/Properties/launchSettings.json

@ -17,7 +17,7 @@
},
"MyCompanyName.MyProjectName.Blazor.Server": {
"commandName": "Project",
"dotnetRunMessages": "true",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:44308/",
"environmentVariables": {

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered/Properties/launchSettings.json

@ -17,7 +17,7 @@
},
"MyCompanyName.MyProjectName.Blazor.WebApp.Tiered": {
"commandName": "Project",
"dotnetRunMessages": "true",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:44309/",
"environmentVariables": {

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp/Properties/launchSettings.json

@ -17,7 +17,7 @@
},
"MyCompanyName.MyProjectName.Blazor.WebApp": {
"commandName": "Project",
"dotnetRunMessages": "true",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:44308/",
"environmentVariables": {

2
templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Properties/launchSettings.json

@ -17,7 +17,7 @@
},
"MyCompanyName.MyProjectName.Blazor.Server.Host": {
"commandName": "Project",
"dotnetRunMessages": "true",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:44304/",
"environmentVariables": {

2
test/AbpPerfTest/AbpPerfTest.WithAbp/Properties/launchSettings.json

@ -17,7 +17,7 @@
},
"AbpPerfTest.WithAbp": {
"commandName": "Project",
"dotnetRunMessages": "true",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {

2
test/AbpPerfTest/AbpPerfTest.WithoutAbp/Properties/launchSettings.json

@ -17,7 +17,7 @@
},
"AbpPerfTest.WithoutAbp": {
"commandName": "Project",
"dotnetRunMessages": "true",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:5003;http://localhost:5002",
"environmentVariables": {

Loading…
Cancel
Save