@ -0,0 +1,223 @@ |
|||
# ABP Platform 9.0 Has Been Released Based on .NET 9.0 |
|||
|
|||
 |
|||
|
|||
Today, we are happy to release the [ABP](https://abp.io/) version **9.0 RC** (Release Candidate). This blog post introduces the new features and important changes in this new version. |
|||
|
|||
Try this version and provide feedback for a more stable version of ABP v9.0! Thanks to all of you. |
|||
|
|||
## Get Started with the 9.0 RC |
|||
|
|||
You can check the [Get Started page](https://abp.io/get-started) to see how to get started with ABP. You can either download [ABP Studio](https://abp.io/get-started#abp-studio-tab) (**recommended**, if you prefer a user-friendly GUI application - desktop application) or use the [ABP CLI](https://abp.io/docs/latest/cli). |
|||
|
|||
By default, ABP Studio uses stable versions to create solutions. Therefore, if you want to create a solution with a preview version, first you need to create a solution and then switch your solution to the preview version from the ABP Studio UI: |
|||
|
|||
 |
|||
|
|||
## Migration Guide |
|||
|
|||
There are a few breaking changes in this version that may affect your application. Please read the migration guide carefully, if you are upgrading from v8.x: [ABP Version 9.0 Migration Guide](https://abp.io/docs/9.0/release-info/migration-guides/abp-9-0) |
|||
|
|||
## What's New with ABP v9.0? |
|||
|
|||
In this section, I will introduce some major features released in this version. |
|||
Here is a brief list of titles explained in the next sections: |
|||
|
|||
* Upgraded to .NET 9.0 |
|||
* Introducing the **Extension Property Policy** |
|||
* Allow wildcards for Redirect Allowed URLs |
|||
* Docs Module: Show larger images on the same page |
|||
* Google Cloud Storage BLOB Provider |
|||
* Removed React Native mobile option from free templates |
|||
* Suite: Better naming for multiple navigation properties to the same entity |
|||
* CMS Kit Pro: Feedback feature improvements |
|||
|
|||
### Upgraded to .NET 9.0 |
|||
|
|||
We've upgraded ABP to .NET 9.0, so you need to move your solutions to .NET 9.0 if you want to use ABP 9.0. You can check [Microsoft’s Migrate from ASP.NET Core 8.0 to 9.0 documentation](https://learn.microsoft.com/en-us/aspnet/core/migration/80-90), to see how to update an existing ASP.NET Core 8.0 project to ASP.NET Core 9.0. |
|||
|
|||
> **Note:** Since the stable version of .NET 9 hasn't been released yet, we upgraded ABP to .NET v9.0-rc.2. We will update the entire ABP Platform to .NET 9 stable, after Microsoft releases it on November 13-14 with the stable ABP 9.0 release. |
|||
|
|||
### Introducing the Extension Property Policy |
|||
|
|||
ABP provides a module entity extension system, which is a high level extension system that allows you to define new properties for existing entities of the depended modules. This is a powerful way to dynamically add additional properties to entities without modifying the core structure. However, managing these properties across different modules and layers can become complex, especially when different policies or validation rules are required. |
|||
|
|||
**Extension Property Policy** feature allows developers to define custom policies for these properties, such as access control, validation, and data transformation, directly within ABP. |
|||
|
|||
**Example:** |
|||
|
|||
```csharp |
|||
ObjectExtensionManager.Instance.Modules().ConfigureIdentity(identity => |
|||
{ |
|||
identity.ConfigureUser(user => |
|||
{ |
|||
user.AddOrUpdateProperty<string>( //property type: string |
|||
"SocialSecurityNumber", //property name |
|||
property => |
|||
{ |
|||
//validation rules |
|||
property.Attributes.Add(new RequiredAttribute()); |
|||
property.Attributes.Add(new StringLengthAttribute(64) {MinimumLength = 4}); |
|||
|
|||
//Global Features |
|||
property.Policy.GlobalFeatures = new ExtensionPropertyGlobalFeaturePolicyConfiguration() |
|||
{ |
|||
Features = new[] {"GlobalFeatureName1", "GlobalFeatureName2"}, |
|||
RequiresAll = true |
|||
}; |
|||
|
|||
//Features |
|||
property.Policy.Features = new ExtensionPropertyFeaturePolicyConfiguration() |
|||
{ |
|||
Features = new[] {"FeatureName1", "FeatureName2"}, |
|||
RequiresAll = false |
|||
}; |
|||
|
|||
//Permissions |
|||
property.Policy.Permissions = new ExtensionPropertyPermissionPolicyConfiguration() |
|||
{ |
|||
PermissionNames = new[] {"AbpTenantManagement.Tenants.Update", "AbpTenantManagement.Tenants.Delete"}, |
|||
RequiresAll = true |
|||
}; |
|||
} |
|||
); |
|||
}); |
|||
}); |
|||
``` |
|||
|
|||
### Allow Wildcards for RedirectAllowedURLs |
|||
|
|||
In this version, we made an improvement to the `RedirectAllowedUrls` configuration, which now allows greater flexibility in defining redirect URLs. Previously, developers faced restrictions when configuring URL redirects. Specifically, the `RedirectAllowedUrls` did not support using **wildcards (*)**, limiting how developers could specify which URLs were permissible for redirects. |
|||
|
|||
With the new changes in [#20628](https://github.com/abpframework/abp/pull/20628), the restriction has been relaxed, allowing developers to define redirect URLs that include wildcards. This makes it easier to handle scenarios where a broad range of URLs need to be allowed, without explicitly listing each one. |
|||
|
|||
```json |
|||
{ |
|||
"App": { |
|||
//... |
|||
"RedirectAllowedUrls": "http://*.domain,http://*.domain:4567" |
|||
} |
|||
``` |
|||
|
|||
### Docs Module: Show Larger Images |
|||
|
|||
As developers, we rely heavily on clear documentation to understand complex concepts and workflows. Often, an image is worth more than a thousand words, especially when explaining intricate user interfaces, workflows, or code structures. In recognition of this, we recently rolled out an improvement to the Docs Module that enables larger images to be displayed more effectively. |
|||
|
|||
 |
|||
|
|||
Before this enhancement, images embedded in documentation were often limited in size, which sometimes made it difficult to see the details in the diagrams, screenshots, or other visual contents. Now, images can be displayed at a larger size, offering better clarity and usability. |
|||
|
|||
> See [https://github.com/abpframework/abp/pull/20557](https://github.com/abpframework/abp/pull/20557) for more information. |
|||
|
|||
### Google Cloud Storage BLOB Provider |
|||
|
|||
ABP provides a BLOB Storing System, which allows you to work with BLOBs. This system is typically used to store file contents in a project and read these file contents when they are needed. Since ABP provides an abstraction to work with BLOBs, it also provides some pre-built storage providers such as [Azure](https://abp.io/docs/latest/framework/infrastructure/blob-storing/azure), [Aws](https://abp.io/docs/latest/framework/infrastructure/blob-storing/aws) and [Aliyun](https://abp.io/docs/latest/framework/infrastructure/blob-storing/aliyun). |
|||
|
|||
In this version, we have introduced a new BLOB Storage Provider for Google Cloud Storage: [`Volo.Abp.BlobStoring.Google`](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Google) |
|||
|
|||
You can [read the documentation](https://abp.io/docs/9.0/framework/infrastructure/blob-storing/google) for configurations and use Google Cloud Storage as your BLOB Storage Provider easily. |
|||
|
|||
### Removed React Native Mobile Option From Free Templates |
|||
|
|||
In this version, we removed the **React Native** mobile option from the open source templates due to maintaining reasons. We updated the related documents and the ABP CLI (both old & new CLI) for this change, and with v9.0, you will not be able to create a free template with react-native as the mobile option. |
|||
|
|||
> **Note:** Pro templates still provide the **React Native** as the mobile option and we will continue supporting it. |
|||
|
|||
If you want to access the open-source React-Native template, you can visit the abp-archive repository from [here](https://github.com/abpframework/abp-archive). |
|||
|
|||
### Suite: Better Naming For Multiple Navigation Properties |
|||
|
|||
Prior to this version, when you defined multiple (same) navigation properties to same entity, then ABP Suite was renaming them with a duplicate number. |
|||
|
|||
As an example,let's assume that you have a book with an author and coauthor, prior to this version ABP Suite was creating a DTO class as below: |
|||
|
|||
```csharp |
|||
public class BookWithNavigationPropertiesDto |
|||
{ |
|||
public BookDto Book { get; set; } |
|||
|
|||
public AuthorDto Author { get; set; } |
|||
|
|||
public AuthorDto Author1 { get; set; } |
|||
} |
|||
``` |
|||
|
|||
Notice, that since the book entity has two same navigation properties, ABP Suite renamed them with a duplicate number. In this version, ABP Suite will ask you to define a propertyName for the **navigation properties** and you'll be able to specify a meaningful name such as (*CoAuthor*, in this example): |
|||
|
|||
```csharp |
|||
public class BookWithNavigationPropertiesDto |
|||
{ |
|||
public BookDto Book { get; set; } |
|||
|
|||
public AuthorDto Author { get; set; } |
|||
|
|||
//used the specified property name |
|||
public AuthorDto CoAuthor { get; set; } |
|||
} |
|||
``` |
|||
|
|||
ABP Suite respects the specified property name for the related navigation property and generates codes regarding that (by removing the *Id* postfix for the related places): |
|||
|
|||
 |
|||
|
|||
### CMS Kit Pro: Feedback Feature Improvements |
|||
|
|||
In this version, we revised the [CMS Kit's Feedback Feature](https://abp.io/docs/9.0/modules/cms-kit-pro/page-feedback) and as a result, we made the following improvements: |
|||
|
|||
* A new **auto-handle** setting has been added to the settings page. When this feature is enabled, if feedback is submitted without a user note, the feedback is automatically marked as handled. |
|||
* You can now require users to enter a note when submitting negative feedback. This can be configured in the settings page, ensuring that users provide context when they submit critical feedback. |
|||
* We've added a feedback user ID that is saved in local storage. This allows you to track the number of unique users submitting feedback or determine if the same user is sending new feedback on updated documents. |
|||
|
|||
> For further information about the Page Feedback System, please refer to the [documentation](https://abp.io/docs/9.0/modules/cms-kit-pro/page-feedback). |
|||
|
|||
## Community News |
|||
|
|||
### Join ABP at the .NET Conf 2024! |
|||
|
|||
ABP is excited to sponsor the [14th annual .NET Conf](https://www.dotnetconf.net/)! We've proudly supported the .NET community for years and recognize the importance of this premier virtual event. Mark your calendars for November 12-14, 2024, and join us for 3 incredible days of learning, networking, and fun. |
|||
|
|||
 |
|||
|
|||
Also, don't miss out on the co-founder of [Volosoft](https://volosoft.com/) and Lead Developer of [ABP](https://abp.io/), [Halil Ibrahim Kalkan](https://x.com/hibrahimkalkan)'s talk about "Building Modular Monolith Applications with ASP.NET Core and ABP Studio" at 10:00 - 10:30 AM GMT+3 on Thursday, November 14. |
|||
|
|||
### ABP Team Attended the .NETDeveloperDays 2024 |
|||
|
|||
We are thrilled to announce that we sponsored the [.NETDevelopersDays 2024](https://developerdays.eu/warsaw/) event. It's one of the premier conferences for .NET developers with **over 1.000 attendees**, **50+ expert speakers**, and **40+ sessions and workshops**. |
|||
|
|||
 |
|||
|
|||
Core team members of the ABP Framework, [Halil Ibrahim Kalkan](https://twitter.com/hibrahimkalkan), [İsmail Çağdaş](https://x.com/ismcagdas), [Enis Necipoğlu](https://x.com/EnisNecipoglu), and [Tarık Özdemir](https://x.com/mtozdemir) attended [.NETDevelopersDays 2024](https://developerdays.eu/warsaw/) on October 22-23, 2024 at Warsaw, Poland. |
|||
|
|||
These 2 days with the team were all about chatting and having fun with amazing attendees and speakers. We met with talented and passionate software developers and introduced the [ABP](https://github.com/abpframework/abp) - web application framework built on ASP.NET Core - to them. |
|||
|
|||
Also, we made a raffle and gifted an Xbox Series S to the lucky winner at the event: |
|||
|
|||
 |
|||
|
|||
Thanks to everyone who joined the fun and visited at our booth :) |
|||
|
|||
### New ABP Community Articles |
|||
|
|||
There are exciting articles contributed by the ABP community as always. I will highlight some of them here: |
|||
|
|||
* [Alper Ebiçoğlu](https://twitter.com/alperebicoglu) has created **five** new community articles: |
|||
* [When to Use Cookies, When to Use Local Storage?](https://abp.io/community/articles/when-to-use-cookies-when-to-use-local-storage-uexsjunf) |
|||
* [.NET 9 Performance Improvements Summary](https://abp.io/community/articles/.net-9-performance-improvements-summary-gmww3gl8) |
|||
* [ASP.NET Core SignalR New Features — Summary](https://abp.io/community/articles/asp.net-core-signalr-new-features-summary-kcydtdgq) |
|||
* [Difference Between "Promise" and "Observable" in Angular](https://abp.io/community/articles/difference-between-promise-and-observable-in-angular-bxv97pkc) |
|||
* [ASP.NET Core Blazor 9.0 New Features Summary 🆕](https://abp.io/community/articles/asp.net-core-blazor-9.0-new-features-summary--x0fovych) |
|||
* [Mohammad AlMohammad AlMahmoud](https://abp.io/community/members/Mohammad97Dev) has created **two** new community articles: |
|||
* [Implementing Multi-Language Functionality With ABP Framework](https://abp.io/community/articles/implementing-multilanguage-functionality-with-abp-framework-loq7kfx4) |
|||
* [Configure Quartz.Net in Abp FrameWork](https://abp.io/community/articles/configure-quartz.net-in-abp-framework-3bveq4y1) |
|||
* [.NET Aspire vs ABP Studio: Side by Side](https://abp.io/community/articles/.net-aspire-vs-abp-studio-side-by-side-t1c73d1l) by [Halil İbrahim Kalkan](https://twitter.com/hibrahimkalkan) |
|||
* [PoC of using GrapesJS for ABPs CMS Kit](https://abp.io/community/articles/poc-of-using-grapesjs-for-abps-cms-kit-1rmv4q41) by [Jack Fistelmann](https://abp.io/community/members/jfistelmann) |
|||
* [ABP-Powered Web App with Inertia.js, React, and Vite](https://abp.io/community/articles/abppowered-web-app-with-inertia.js-react-and-vite-j7cccvad) by [Anto Subash](https://antosubash.com/) |
|||
* [Multi-Tenancy Support in Angular Apps with ABP.IO](https://abp.io/community/articles/multitenancy-support-in-angular-apps-with-abp.io-lw9l36c5) by [HeadChannel Team](https://headchannel.co.uk/) |
|||
|
|||
Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/submit) to the ABP Community. |
|||
|
|||
## Conclusion |
|||
|
|||
This version comes with some new features and a lot of enhancements to the existing features. You can see the [Road Map](https://abp.io/docs/9.0/release-info/road-map) documentation to learn about the release schedule and planned features for the next releases. Please try ABP v9.0 RC and provide feedback to help us release a more stable version. |
|||
|
|||
Thanks for being a part of this community! |
|||
|
After Width: | Height: | Size: 287 KiB |
|
After Width: | Height: | Size: 525 KiB |
|
After Width: | Height: | Size: 212 KiB |
|
After Width: | Height: | Size: 892 KiB |
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 54 KiB |
@ -0,0 +1,63 @@ |
|||
# When to Use Cookies, When to Use Local Storage? |
|||
|
|||
 |
|||
|
|||
|
|||
|
|||
## 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 🧑🏽💻 |
|||
|
After Width: | Height: | Size: 524 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 441 KiB After Width: | Height: | Size: 432 KiB |
@ -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. |
|||
|
|||
 |
|||
|
|||
## 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: |
|||
|
|||
 |
|||
|
|||
### 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: |
|||
|
|||
 |
|||
|
|||
## 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: |
|||
|
|||
 |
|||
|
|||
## 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 launch 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 applications 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: |
|||
|
|||
 |
|||
|
|||
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: |
|||
|
|||
 |
|||
|
|||
.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: |
|||
|
|||
 |
|||
|
|||
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) |
|||
|
After Width: | Height: | Size: 407 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 412 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 46 KiB |
@ -0,0 +1,147 @@ |
|||
# ABP Now Supports .NET 9 |
|||
|
|||
 |
|||
|
|||
|
|||
|
|||
**.NET 9.0.100-rc.2** has been released on **October 8, 2024**. To align with the latest .NET, we also released the ABP Platform [9.0.0-rc.1](https://github.com/abpframework/abp/releases/tag/9.0.0-rc.1) version. |
|||
**With this release, ABP now supports .NET 9.** |
|||
|
|||
The .NET 9 stable version is planned to be released on **November 12, 2024** before the [.NET Conf 2024](https://www.dotnetconf.net/) event. The ABP 9.0 stable version is planned to be released on November 19, 2024. |
|||
|
|||
--- |
|||
|
|||
- **Download the .NET 9 runtime** and SDK from the following link: |
|||
|
|||
[https://dotnet.microsoft.com/en-us/download/dotnet/9.0](https://dotnet.microsoft.com/en-us/download/dotnet/9.0) |
|||
|
|||
- There are many enhancements and bug fixes with ABP 9.0. Read the ABP 9 announcement: |
|||
|
|||
https://abp.io/blog/announcing-abp-9-0-release-candidate |
|||
|
|||
- |
|||
Read **our migration ABP 9.0 migration guide** from the following link: |
|||
|
|||
[abp.io/docs/9.0/release-info/migration-guides/abp-9-0](https://abp.io/docs/9.0/release-info/migration-guides/abp-9-0) |
|||
|
|||
- The following is the **PR is for the .NET 9 upgrade** in the ABP source code: |
|||
|
|||
[https://github.com/abpframework/abp/pull/20803](https://github.com/abpframework/abp/pull/20803) |
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## .NET 9 Releases |
|||
|
|||
In the following link, you can find **a list of all .NET 9 releases** with direct links to release notes and announcements/discussions: |
|||
|
|||
* https://github.com/dotnet/core/discussions/9234 |
|||
|
|||
|
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## ABP Supports Both .NET 8 & .NET 9 |
|||
|
|||
The ABP 9.0 version fully supports .NET 9 within our new templates and modules. For developers who want to update their ABP packages to the latest but want to keep them in .NET 8, **we support both .NET 8 and .NET 9** in ABP 9. In your host application, you can choose your target framework. |
|||
|
|||
So you can decide which version you want to use in your startup Host Application’s `<TargetFramework>` tag. |
|||
|
|||
In [this link](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp/Volo.Abp.csproj#L7) you can see that netstandard2.0/2.1 and net8/9 are supported. |
|||
|
|||
```xml |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
<TargetFrameworks> |
|||
netstandard2.0;netstandard2.1;net8.0;net9.0 |
|||
</TargetFrameworks> |
|||
</Project> |
|||
``` |
|||
|
|||
|
|||
|
|||
### New ASP.NET Core Middleware: Static Asset Delivery |
|||
|
|||
`MapStaticAssets` is a new middleware that helps optimize the delivery of static assets in any ASP.NET Core app, including Blazor apps. With this change, some `JavaScript/CSS/Images` files exist in the [Virtual File System](https://abp.io/docs/latest/framework/infrastructure/virtual-file-system?_redirected=B8ABF606AA1BDF5C629883DF1061649A), but the new ASP.NET Core 9 `MapStaticAssets` can't handle them. You need to add `StaticFileMiddleware` to serve these files. In ABP 9, we added `MapAbpStaticAssetsan `extension method to support the new `MapStaticAssets`. You can read about this new feature at [this link](https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-9.0?view=aspnetcore-8.0#static-asset-delivery-optimization). |
|||
ABP’s new extension method is available [here](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs#L129-L198). |
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## How to Upgrade from .NET 8 to .NET 9: |
|||
|
|||
Install the latest .NET 9 SDK from [this link](https://dotnet.microsoft.com/en-us/download/dotnet/9.0). |
|||
Upgrade [dotnet-ef](https://learn.microsoft.com/en-us/ef/core/cli/dotnet) tool version with the following command: |
|||
|
|||
```bash |
|||
dotnet tool uninstall --global dotnet-ef && dotnet tool install --global dotnet-ef |
|||
``` |
|||
|
|||
 |
|||
|
|||
1. Change all `TargetFramework` tags from `net8.0` to `net9.0`. |
|||
2. Upgrade all Microsoft NuGet packages to `9.0.0`. |
|||
3. If you have `global.json`, update `dotnet`version to `9.0.0` . |
|||
4. Replace`app.UseStaticFiles()` to `app.MapAbpStaticAssets()` in your module classes and startup projects. |
|||
[See the related changes in the repository.](https://github.com/abpframework/abp/commit/0f34f6dfcdbeb5d27fd63cf764f1ef13eb9cdfcd) |
|||
|
|||
|
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## What’s new with .NET 9 |
|||
|
|||
**.NET 9 Blazor New Features** |
|||
|
|||
- https://abp.io/community/articles/asp.net-core-blazor-9.0-new-features-summary--x0fovych |
|||
|
|||
**.NET 9 Performance Improvements Summary** |
|||
|
|||
- https://abp.io/community/articles/.net-9-performance-improvements-summary-gmww3gl8 |
|||
|
|||
**What’s new in .NET 9 (Microsoft’s post)** |
|||
|
|||
- https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-9/overview |
|||
|
|||
|
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## We Are Eating Our Own Dog Food |
|||
|
|||
Before we release any version of ABP, **we test our upcoming version** on our sample apps and live website https://abp.io. The ABP.io website is also built on top of the ABP Framework, and you can see that we have already started to use .NET 9-rc.2 on our live website. |
|||
|
|||
 |
|||
|
|||
|
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## Microsoft .NET Support Policy |
|||
|
|||
Lastly, I want to mention Microsoft's .NET support policy. |
|||
|
|||
- **.NET 7** support has been **finished** on **May 2024**. |
|||
- **.NET 8** will be supported until **November 2026**. |
|||
- **.NET 9** is on the standard term support, which means Microsoft will release patches until **May 2026**. |
|||
|
|||
Find detailed information about the .NET support policy at [this link.](https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core) |
|||
|
|||
 |
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## Finally |
|||
|
|||
.NET 9 is making a significant impact. It introduces features like Native AOT for faster applications, enhanced AI integration and improved tools for cloud-native and cross-platform development, all aimed at simplifying developers’ work. Whether you’re handling small projects or large-scale enterprise applications, it offers enhancements that **elevate your productivity by just upgrading your .NET version to 9.0** |
|||
@ -0,0 +1,125 @@ |
|||
# Hybrid Cache in .NET 9 |
|||
|
|||
.NET 9 introduces an exciting feature: **HybridCache**, an advanced caching mechanism that seamlessly combines multiple caching strategies to maximize performance and scalability. |
|||
|
|||
It offers a flexible caching solution that combines the best aspects of local and distributed caching. **HybridCache** is particularly useful in scenarios where quick, in-memory access is desirable but data consistency across multiple application instances is also a requirement. |
|||
|
|||
In this article, we’ll explore **HybridCache** in .NET 9 and how it integrates with ABP Framework using `AbpHybridCache`. This new feature offers a robust solution for applications that need to scale while maintaining efficient caching strategies. |
|||
|
|||
## What is HybridCache? |
|||
|
|||
**HybridCache** is designed to merge different caching layers, commonly including an in-memory cache (for high-speed access) and a distributed cache (for scalability across multiple instances). This hybrid approach allows for: |
|||
|
|||
* **Improved Performance**: Frequently accessed data is stored in-memory, reducing latency. |
|||
* **Increased Scalability**: Cached data can still be shared across distributed environments, essential for load-balanced applications. |
|||
* **Automatic Synchronization**: Changes in distributed cache automatically update the in-memory cache, ensuring data consistency. |
|||
|
|||
## Using HybridCache with ABP |
|||
|
|||
> For more information about the implementation in the ABP side, you can refer to the pull request [here](https://github.com/abpframework/abp/pull/20859). |
|||
|
|||
ABP's support for **HybridCache** is available starting from version 9.0 through the [`AbpHybridCache`](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/Hybrid/AbpHybridCache.cs) implementation. By leveraging this feature, developers using ABP can implement hybrid caching in a way that aligns with ABP’s modular and extensible architecture. |
|||
|
|||
To demonstrate how to use **HybridCache** in ABP, let's start with a simple example. |
|||
|
|||
> You can create an ABP-based application with v9.0+, and then follow the next steps for using hybrid caching in your application. |
|||
|
|||
### Configuring the `AbpHybridCacheOptions` (Optional) |
|||
|
|||
First, you can configure the hybrid cache options in your module class as below (it's optional): |
|||
|
|||
```csharp |
|||
using Microsoft.Extensions.Caching.Hybrid; |
|||
using Volo.Abp.Caching.Hybrid; |
|||
|
|||
public class YourModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
//... |
|||
|
|||
Configure<AbpHybridCacheOptions>(options => |
|||
{ |
|||
//configuring the global hybrid cache options |
|||
options.GlobalHybridCacheEntryOptions = new HybridCacheEntryOptions() |
|||
{ |
|||
Expiration = TimeSpan.FromMinutes(20), |
|||
LocalCacheExpiration = TimeSpan.FromMinutes(10) |
|||
}; |
|||
}); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
* You can configure the `AbpHybridCacheOptions` to set *keyPrefix* for your cache keys, throw or hide exceptions for the distributed cache (by default *it hides errors*), or configure cache for specific cache item keys and more... |
|||
* By setting the `GlobalHybridCacheEntryOptions`, you specify the caching options globally in your application. Thanks to that, you don't need to manually pass the related options whenever you use the `IHybridCache` service. |
|||
|
|||
### Using the `IHybridCache` Service |
|||
|
|||
After the configuration, now you can inject the `IHybridCache` and use it to set and retrieve cache values: |
|||
|
|||
```csharp |
|||
using Volo.Abp.Caching.Hybrid; |
|||
|
|||
public class BookAppService : ApplicationService, IBookAppService |
|||
{ |
|||
private readonly IHybridCache<BookCacheItem> _hybridCache; |
|||
|
|||
public BookAppService(IHybridCache<BookCacheItem> hybridCache) |
|||
{ |
|||
_hybridCache = hybridCache; |
|||
} |
|||
|
|||
public async Task<BookCacheItem> GetBookWithPageCountAsync(string name) |
|||
{ |
|||
var cacheKey = "cacheKey:book-" + name; |
|||
|
|||
// Retrieve data from hybrid cache |
|||
return await _hybridCache.GetOrCreateAsync(cacheKey, async () => |
|||
{ |
|||
// Simulating getting and returning the data if not exist in the cache |
|||
return new BookCacheItem |
|||
{ |
|||
Name = name, |
|||
PageCount = 100 |
|||
}; |
|||
}); |
|||
} |
|||
} |
|||
|
|||
public class BookCacheItem |
|||
{ |
|||
public string Name { get; set; } |
|||
|
|||
public int PageCount { get; set; } |
|||
} |
|||
``` |
|||
|
|||
* You can use the `IHybridCache<TCacheItem>` or `IHybridCache<TCacheItem, TCacheKey>` service to leverage the hybrid caching. If you use `IHybridCache<TCacheItem>`as the service, then you should pass the cache key as *string* like in the example above. |
|||
* In this example, you used the `GetOrCreateAsync` method, which first tries to get the cache item with the provided cache key, if there is no cache with the specified key, then it runs the factory method and add the returned data to the cache. |
|||
* Alternatively, you can use the `SetAsync` method to set the cache item. |
|||
|
|||
### Debugging the `IHybridCache` Service (deep-dive) |
|||
|
|||
When you debug the `IHybridCache` service, you'll notice the L1 and L2 cache stores. (L1 is in-memory cache store and L2 is the distributed cache store): |
|||
|
|||
 |
|||
|
|||
As you can see from the figure, it only set the cache item to the **LocalCache** (`MemoryCache`) and did not set the **BackendCache** (`DistributedCache`) because I did not configure the distributed cache and not running my application in multiple instances. But as you can notice, even without an `IDistributedCache` configuration, the `HybridCache` service will still provide in-process caching. |
|||
|
|||
**Note:** If you configure distributed caching options, `HybridCache` service uses the distributed cache and sets the **BackendCache**. |
|||
|
|||
## Conclusion |
|||
|
|||
The **HybridCache** library in .NET 9 provides a powerful tool for applications needing both high-speed caching and consistency in distributed environments. |
|||
|
|||
With ABP Framework’s `AbpHybridCache` support, integrating this feature into an ABP-based application becomes straightforward. This setup helps ensure that cached data remains synchronized across instances, bringing a new level of flexibility to caching in .NET 9 applications. |
|||
|
|||
> For more information, you can refer to the [Microsoft's official document](https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-9.0?view=aspnetcore-9.0#new-hybridcache-library). |
|||
|
|||
## References |
|||
|
|||
- https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-9.0?view=aspnetcore-9.0#new-hybridcache-library |
|||
- https://www.youtube.com/watch?v=TDyZc11cJfA |
|||
- https://github.com/abpframework/abp/pull/20803 |
|||
- https://github.com/abpframework/abp/pull/20859 |
|||
|
After Width: | Height: | Size: 483 KiB |
|
After Width: | Height: | Size: 144 KiB |
@ -1,22 +1,26 @@ |
|||
# Optimizing Your Application for Production Environments |
|||
|
|||
ABP and the startup solution templates are configured well to get the maximum performance on production environments. However, there are still some points you need to pay attention to in order to optimize your system in production. In this document, we will mention some of these topics. |
|||
ABP and the startup solution templates are configured well to get the maximum performance on production environments. |
|||
However, you still need to pay attention to some points to optimize your system in production. |
|||
This document will explain optimization points for the production environment. |
|||
|
|||
## Caching Static Contents |
|||
|
|||
The following items are contents that can be cached in the client side (typically in the Browser) or in a CDN server: |
|||
The following items are contents that can be cached on the client side (typically in the Browser) or in a CDN server: |
|||
|
|||
* **Static images** can always be cached. Here, you should be careful that if you change an image, use a different file name, or use a versioning query-string parameter, so the browser (or CDN) understands it's been changed. |
|||
* **CSS and JavaScript files**. ABP's [bundling & minification](../framework/ui/mvc-razor-pages/bundling-minification.md) system always uses a query-string versioning parameter and a hash value in the files names of the CSS & JavaScript files for the [MVC (Razor Pages)](../framework/ui/mvc-razor-pages/overall.md) UI. So, you can safely cache these files in the client side or in a CDN server. |
|||
* **Static images** can always be cached. Here, you should be careful that if you change an image, use a different file name, or use a versioning query-string parameter so the browser (or CDN) understands it's been changed. |
|||
* **CSS and JavaScript files**. ABP's [bundling & minification](../framework/ui/mvc-razor-pages/bundling-minification.md) system always uses a query-string versioning parameter and a hash value in the files names of the CSS & JavaScript files for the [MVC (Razor Pages)](../framework/ui/mvc-razor-pages/overall.md) UI. So you can safely cache these files on the client side or on a CDN server. |
|||
* **Application bundle files** of an [Angular UI](../framework/ui/angular/quick-start.md) application. |
|||
* **[Application Localization Endpoint](../framework/api-development/standard-apis/localization.md)** can be cached per culture (it already has a `cultureName` query string parameter) if you don't use dynamic localization on the server-side. ABP's [Language Management](https://abp.io/modules/Volo.LanguageManagement) module provides dynamic localization. If you're using it, you can't cache that endpoint forever. However, you can still cache it for a while. Applying dynamic localization text changes to the application can delay for a few minutes, even for a few hours in a real life scenario. |
|||
* **[Application Localization Endpoint](../framework/api-development/standard-apis/localization.md)** can be cached per culture (it already has a `cultureName` query string parameter) if you don't use dynamic localization on the server-side. ABP's [Language Management](https://abp.io/modules/Volo.LanguageManagement) module provides dynamic localization. If you're using it, you can't cache that endpoint forever. However, you can still cache it for a while. Applying dynamic localization text changes to the application can delay a few minutes, even a few hours, in a real-life scenario. |
|||
|
|||
There may be more ways based on your solution structure and deployment environment, but these are the essential points you should consider to client-side cache in a production environment. |
|||
There may be more ways based on your solution structure and deployment environment, but these are the essential points you should consider for client-side cache in a production environment. |
|||
|
|||
## Bundling & Minification for MVC (Razor Pages) UI |
|||
|
|||
ABP's [bundling & minification](../framework/ui/mvc-razor-pages/bundling-minification.md) system automatically bundles, minifies and versions your CSS and JavaScript files in production environment. Normally, you don't need to do anything, if you haven't disabled it yourself in your application code. It is important to follow the [bundling & minification](../framework/ui/mvc-razor-pages/bundling-minification.md) document and truly use the system to get the maximum optimization. |
|||
ABP's [bundling & minification](../framework/ui/mvc-razor-pages/bundling-minification.md) system automatically bundles, minifies and versions your CSS and JavaScript files in the production environment. |
|||
Normally, you don't need to do anything if you have not disabled it yourself in your application code. |
|||
It is important to follow the [bundling & minification](../framework/ui/mvc-razor-pages/bundling-minification.md) document and truly use the system to get the maximum optimization. |
|||
|
|||
## Background Jobs |
|||
|
|||
ABP's [Background Jobs](../framework/infrastructure/background-jobs) system provides an abstraction with a basic implementation to enqueue jobs and execute them in a background thread. ABP's Default Background Job Manager may not be enough if you are adding too many jobs to the queue and want them to be executed in parallel by multiple servers with a high performance. If you need these, you should consider to configure a dedicated background job software, like [Hangfire](https://www.hangfire.io/). ABP has a pre-built [Hangfire integration](../framework/infrastructure/background-jobs/hangfire.md), so you can switch to Hangfire without changing your application code. |
|||
ABP's [Background Jobs](../framework/infrastructure/background-jobs) system provides an abstraction with a basic implementation to enqueue jobs and execute them in a background thread. ABP's Default Background Job Manager may not be enough if you are adding too many jobs to the queue and want them to be executed in parallel by multiple servers with a high performance. If you need these, you should consider configuring a dedicated background job software, like [Hangfire](https://www.hangfire.io/). ABP has a pre-built [Hangfire integration](../framework/infrastructure/background-jobs/hangfire.md), so you can switch to Hangfire without changing your application code. |
|||
|
|||
|
After Width: | Height: | Size: 218 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 103 KiB |
@ -0,0 +1,100 @@ |
|||
# ABP Version 9.0 Migration Guide |
|||
|
|||
This document is a guide for upgrading ABP v8.x solutions to ABP v9.0. There are some changes in this version that may affect your applications, please read it carefully and apply the necessary changes to your application. |
|||
|
|||
> ABP upgraded to .NET 9.0, so you need to move your solutions to .NET 9.0 if you want to use the ABP 9.0. You can check the [Migrate from ASP.NET Core 8.0 to 9.0](https://learn.microsoft.com/en-us/aspnet/core/migration/80-90) documentation. |
|||
|
|||
## Open-Source (Framework) |
|||
|
|||
### Upgraded to .NET 9.0 |
|||
|
|||
We've upgraded ABP to .NET 9.0, so you need to move your solutions to .NET 9.0 if you want to use ABP 9.0. You can check Microsoft’s [Migrate from ASP.NET Core 8.0 to 9.0](https://learn.microsoft.com/en-us/aspnet/core/migration/80-90) documentation, to see how to update an existing ASP.NET Core 8.0 project to ASP.NET Core 9.0. |
|||
|
|||
After updating your solution to .NET 9.0, you should apply the following steps: |
|||
|
|||
* Change the `app.UseStaticFiles()` to `app.MapAbpStaticAssets()` in the module classes of your host applications. |
|||
* Some JavaScript/CSS/Images files exist in the Virtual File System, but ASP NET Core 9's `MapStaticAssets` can't handle them. This is why we created the **MapAbpStaticAssets**. |
|||
* Upgrade the Microsoft packages (also other packages) for .NET 9.0. You can check the [Directory.Packages.props](https://github.com/abpframework/abp/blob/rel-9.0/Directory.Packages.props) file for package versions and update the necessary ones. |
|||
|
|||
### Made the IdentitySession Entity Extensible & Updated the MaxIpAddressesLength |
|||
|
|||
In this version, we made the `IdentitySession` entity extensible and as a result of that, you should be aware of the changes explained below: |
|||
|
|||
* `IdentitySession` entity inherits from **AggregateRoot** instead of **BasicAggregateRoot**. Here is the PR for the related change: [#20771](https://github.com/abpframework/abp/pull/20771) |
|||
* `IdentitySession` entity's **MaxIpAddress** property now allows up to 2048 characters. You can check the related PR, [here](https://github.com/abpframework/abp/pull/20819). |
|||
|
|||
You should create a new migration and apply it to your database for the changes explained above. |
|||
|
|||
### Removed Auditing Properties From the `OpenIddictAuthorization` and `OpenIddictToken` Entities |
|||
|
|||
In this version, we removed the auditing properties from the `OpenIddictAuthorization` and `OpenIddictToken` entities. Now, these entities are inherited from `AggregateRoot` instead of `FullAuditedAggregateRoot`. |
|||
|
|||
> See the PR, if you need further information: https://github.com/abpframework/abp/pull/20671 |
|||
|
|||
Since the auditing properties are removed, you should create a new migration and apply it to your database. |
|||
|
|||
### Updated Method Signature of `AbpCrudPageBase` |
|||
|
|||
The method signature of [framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs) has been changed as follows: |
|||
|
|||
```diff |
|||
- IEnumerable<TableColumn> GetExtensionTableColumns(string moduleName, string entityType) |
|||
+ Task<List<TableColumn>> GetExtensionTableColumnsAsync(string moduleName, string entityType) |
|||
``` |
|||
|
|||
### Removed React Native Mobile Option From Open Source Templates |
|||
|
|||
In this version, we removed the **React Native** mobile option from the open source templates due to maintaining reasons. We updated the related documents and the ABP CLI (both old & new CLI) for this change, and with v9.0, you will not be able to create a free template with react-native as the mobile option. |
|||
|
|||
> **Note:** Pro templates still provide the **React Native** as the mobile option and we will continue supporting it. |
|||
|
|||
If you want to access the open-source React-Native template, you can visit the **abp-archive** repository: https://github.com/abpframework/abp-archive |
|||
|
|||
## PRO |
|||
|
|||
> Please check the **Open-Source (Framework)** section before reading this section. The listed topics might affect your application and you might need to take care of them. |
|||
|
|||
If you are a paid-license owner and using the ABP's paid version, then please follow the following sections to get informed about the breaking changes and apply the necessary ones: |
|||
|
|||
### ABP Suite: Better Naming For Multiple Navigation Properties |
|||
|
|||
> **Note:** As a developer, you don't need to make any changes in your solution regarding this change. We just wanted to highlight this change and let you know. |
|||
|
|||
Prior to this version, when you defined multiple (same) navigation properties to same entity, then ABP Suite was renaming them with a duplicate number. |
|||
|
|||
Consider the following scenario for an example: If you have a book with an author and coauthor, prior to this version ABP Suite was creating a DTO class as below: |
|||
|
|||
```csharp |
|||
public class BookWithNavigationPropertiesDto |
|||
{ |
|||
public BookDto Book { get; set; } |
|||
|
|||
public AuthorDto Author { get; set; } |
|||
|
|||
public AuthorDto Author1 { get; set; } |
|||
} |
|||
``` |
|||
|
|||
Notice, that since the book entity has two same navigation properties, ABP Suite renamed them with a duplicate number. In this version, ABP Suite will ask you to define a propertyName for the **navigation properties** and you'll be able to specify a meaningful name such as: |
|||
|
|||
```csharp |
|||
public class BookWithNavigationPropertiesDto |
|||
{ |
|||
public BookDto Book { get; set; } |
|||
|
|||
public AuthorDto Author { get; set; } |
|||
|
|||
//used the specified property name |
|||
public AuthorDto CoAuthor { get; set; } |
|||
} |
|||
``` |
|||
|
|||
### CMS Kit Pro: Feedback Feature Improvements |
|||
|
|||
In this version, we revised the **CMS Kit's Feedback Feature** and as a result, we made the following changes: |
|||
|
|||
* `CmsKitProSettingGroupViewComponent` doesn't inject any service anymore and the design of the component has been updated. (no need for a change in your code, if you did not override the component) |
|||
* `Default.cshtml` and `Default.js` files (under the **Pages/Public/Shared/Components/PageFeedbacks/** directory) have been updated. (no need for a change in your code, if you did not override the files) |
|||
* `FeedbackUserId` property has been added to the `PageFeedback` entity, and that means you should create a new migration and apply it to your database. |
|||
* `PageFeedbackManager.CreateAsync` method now expecting an additional parameter: ***Guid feedbackUserId***. (no need for a change in your code, if you did not override or use this file) |
|||
* `PageFeedbackPublicAppService` has been updated due to saving the feedback user id. (no need for a change in your code, if you did not override or use this file) |
|||
@ -0,0 +1,36 @@ |
|||
# Azure Deployment using Application Service |
|||
|
|||
````json |
|||
//[doc-params] |
|||
{ |
|||
"UI": ["MVC", "Blazor", "BlazorServer", "NG"], |
|||
"DB": ["EF", "Mongo"], |
|||
"Tiered": ["Yes", "No"] |
|||
} |
|||
```` |
|||
|
|||
> This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider. For other options, please change the preference on top of this document. |
|||
|
|||
## Prerequisites |
|||
|
|||
- An active Azure account. If you don't have one, you can sign up for a [free account](https://azure.microsoft.com/en-us/free/) |
|||
|
|||
- Your ABP **{{ UI_Value }}** project must be ready at a GitHub repository because we will use GitHub Actions to deploy the ABP application to the Azure Web App Service. |
|||
|
|||
- **{{ DB_Value }}** database must be ready to use with your project. If you don't have a database, you can create a new Azure SQL database or Cosmos DB by following the instructions below: |
|||
|
|||
- [Create a new Azure SQL Database](https://docs.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart?tabs=azure-portal) |
|||
|
|||
- [Create a new Azure Cosmos DB](https://docs.microsoft.com/en-us/azure/cosmos-db/create-cosmosdb-resources-portal) |
|||
|
|||
|
|||
### Description of the process in three steps: |
|||
|
|||
1. [Creating an Azure Web App Service Environment ](step1-create-azure-resources) |
|||
2. [Customizing the Configuration of Your ABP Application](step2-configuration-application) |
|||
3. [Deploying Your Application to Azure Web App Service](step3-deployment-github-action) |
|||
|
|||
|
|||
## What's next? |
|||
|
|||
- [Creating an Azure Web App Service Environment](step1-create-azure-resources) |
|||
@ -0,0 +1,174 @@ |
|||
````json |
|||
//[doc-params] |
|||
{ |
|||
"UI": ["MVC", "Blazor", "BlazorServer", "NG"], |
|||
"DB": ["EF", "Mongo"], |
|||
"Tiered": ["Yes", "No"] |
|||
} |
|||
```` |
|||
|
|||
## Step 1: Creating an Azure Web App Service Environment |
|||
|
|||
To create a new Azure Web App Service, choose one of the following options: |
|||
|
|||
- [Create a new Azure Web App Service using the Azure Portal](#create-a-new-azure-web-app-service-using-the-azure-portal) (Recommended) |
|||
|
|||
- [Create a new Azure Web App Service using the Terraform Template](terraform-web-app-service.md) (If you have experience with Terraform) |
|||
|
|||
{{ if UI == "MVC" && Tiered == "No" }} |
|||
|
|||
### Create a new Azure Web App service using the Azure Portal |
|||
|
|||
1. Log in to the [Azure Portal](https://portal.azure.com/). |
|||
|
|||
2. Click the **Create a resource** button. |
|||
|
|||
3. Search for **Web App** and select **Web App** from the results. |
|||
|
|||
 |
|||
|
|||
4. Click the **Create** button. |
|||
|
|||
5. Fill in the required fields and click the **Review + create** button. |
|||
|
|||
6. Click the **Create** button. |
|||
|
|||
 |
|||
|
|||
7. Wait for the deployment to complete. |
|||
|
|||
 |
|||
|
|||
{{else}} |
|||
|
|||
{{ if UI == "BlazorServer" || UI == "MVC" }} |
|||
|
|||
### Create a new Azure Web App service using the Azure Portal |
|||
|
|||
1. Log in to the [Azure Portal](https://portal.azure.com/). |
|||
|
|||
2. Click the **Create a resource** button. |
|||
|
|||
3. Search for **Web App** and select **Web App** from the results. |
|||
|
|||
 |
|||
|
|||
4. Click the **Create** button. |
|||
|
|||
5. Fill in the required fields and click the **Review + create** button. |
|||
|
|||
6. Click the **Create** button. |
|||
|
|||
 |
|||
|
|||
7. Wait for the deployment to complete. |
|||
|
|||
 |
|||
|
|||
{{ else if UI == 'NG' }} |
|||
|
|||
### Create a new Azure Static Web App for Angular using the Azure Portal |
|||
|
|||
1. Log in to the [Azure Portal](https://portal.azure.com/). |
|||
|
|||
2. Click the **Create a resource** button. |
|||
|
|||
3. Search for **Static Web App** and select **Static Web App** from the results. |
|||
|
|||
 |
|||
|
|||
4. Click the **Create** button. |
|||
|
|||
5. Fill in the required fields and click the **Review + create** button. |
|||
|
|||
6. Click the **Create** button. |
|||
|
|||
 |
|||
|
|||
7. Wait for the deployment to complete. |
|||
|
|||
 |
|||
|
|||
{{else}} |
|||
|
|||
### Create a new Azure Static Web App for Blazor using the Azure Portal |
|||
|
|||
1. Log in to the [Azure Portal](https://portal.azure.com/). |
|||
|
|||
2. Click the **Create a resource** button. |
|||
|
|||
3. Search for **Static Web App** and select **Static Web App** from the results. |
|||
|
|||
 |
|||
|
|||
4. Click the **Create** button. |
|||
|
|||
5. Fill in the required fields and click the **Review + create** button. |
|||
|
|||
6. Click the **Create** button. |
|||
|
|||
 |
|||
|
|||
7. Wait for the deployment to complete. |
|||
|
|||
 |
|||
|
|||
{{end}} |
|||
|
|||
### Create a new Azure Web App Service for API application |
|||
|
|||
1. You can create a new Azure Web App Service for an API application in the same resource group. |
|||
|
|||
2. Click the **Create** button on the top of the resource group page. |
|||
|
|||
3. Search for **Web App** and select **Web App** from the results. |
|||
|
|||
 |
|||
|
|||
4. Click the **Create** button. |
|||
|
|||
5. Fill in the required fields and click the **Review + create** button. |
|||
|
|||
6. Click the **Create** button. |
|||
|
|||
 |
|||
|
|||
7. Wait for the deployment to complete. |
|||
|
|||
 |
|||
|
|||
{{ if Tiered == "Yes" && (UI == "MVC" || UI == "BlazorServer")}} |
|||
|
|||
### Create a new Azure Web App Service for AuthServer application |
|||
|
|||
Similar to the API application, you can create a new Azure Web App Service for an AuthServer application in the same resource group. |
|||
|
|||
Same as above, but you only need to modify the name of the web app service to **authserver-yourapp** in step 5. |
|||
|
|||
### Create Azure Cache for Redis |
|||
|
|||
1. Click the **Create** button on the top of the resource group page. |
|||
|
|||
2. Search for **Redis Cache** and select **Redis Cache** from the results. |
|||
|
|||
 |
|||
|
|||
3. Click the **Create** button. |
|||
|
|||
4. Fill in the required fields and click the **Review + create** button. |
|||
|
|||
5. Click the **Create** button. |
|||
|
|||
 |
|||
|
|||
6. Wait for the deployment to complete. |
|||
|
|||
 |
|||
|
|||
{{ end }} |
|||
|
|||
{{ end }} |
|||
|
|||
## What's next? |
|||
|
|||
- [Customizing the Azure Web App Service](step2-configuration-application.md) |
|||
@ -0,0 +1,231 @@ |
|||
````json |
|||
//[doc-params] |
|||
{ |
|||
"UI": ["MVC", "Blazor", "BlazorServer", "NG"], |
|||
"DB": ["EF", "Mongo"], |
|||
"Tiered": ["Yes", "No"] |
|||
} |
|||
```` |
|||
|
|||
## Step 2: Customizing the Configuration of the ABP Application |
|||
|
|||
- To customize the configuration of your ABP application, modify the `ConnectionString` values in every location throughout your project. The `ConnectionString` values are stored in the `appsettings.json` files. |
|||
|
|||
This includes the following files: |
|||
{{ if UI == "MVC" && Tiered == "No" }} |
|||
**./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.Web/appsettings.json** |
|||
{{else}} |
|||
**./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** |
|||
{{end}} |
|||
{{if Tiered == "Yes"}} |
|||
**./src/yourapp.AuthServer/appsettings.json** |
|||
{{end}} |
|||
|
|||
```json |
|||
"ConnectionStrings": { |
|||
"Default": "Server=tcp:yourserver.database.windows.net,1433;Initial Catalog=yourdatabase;Persist Security Info=False;User ID=yourusername;Password=yourpassword;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;" |
|||
} |
|||
``` |
|||
|
|||
{{ if UI == "MVC" }} |
|||
|
|||
{{if Tiered == "No"}} |
|||
|
|||
- Modify the **yourapp.Web** URL in every location throughout your project, especially within the **./src/yourapp.Web/appsettings.json** and **./src/yourapp.DbMigrator/appsettings.json** files, to match your Azure Web App Service URL. |
|||
|
|||
```json |
|||
"App": { |
|||
"SelfUrl": "https://yourapp.azurewebsites.net" |
|||
} |
|||
``` |
|||
|
|||
{{else}} |
|||
|
|||
- Modify the **yourapp.Web** URL in every location throughout your project. |
|||
|
|||
This includes the following files: |
|||
|
|||
**./src/yourapp.Web/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** , **./src/yourapp.HttpApi.Host/appsettings.json** and **./src/yourapp.AuthServer/appsettings.json** |
|||
|
|||
```json |
|||
"App": { |
|||
"SelfUrl": "https://yourapp.azurewebsites.net" |
|||
} |
|||
``` |
|||
|
|||
- Modify the **yourapp.ApiHost** URL in every location throughout your project. |
|||
|
|||
This includes the following files: |
|||
|
|||
**./src/yourapp.HttpApi.Host/appsettings.json** , **./src/yourapp.Web/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.AuthServer/appsettings.json** |
|||
|
|||
```json |
|||
"App": { |
|||
"SelfUrl": "https://yourapp-apihost.azurewebsites.net" |
|||
} |
|||
``` |
|||
|
|||
- Modify the **yourapp.AuthServer** URL in every location throughout your project. |
|||
|
|||
This includes the following files: |
|||
|
|||
**./src/yourapp.Web/appsettings.json** , **./src/yourapp.AuthServer/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** |
|||
|
|||
```json |
|||
"App": { |
|||
"SelfUrl": "https://yourapp-authserver.azurewebsites.net" |
|||
} |
|||
``` |
|||
|
|||
- Modify the **Redis__Configuration** URL in every location throughout your project. |
|||
|
|||
This includes the following files: |
|||
|
|||
**./src/yourapp.Web/appsettings.json** , **./src/yourapp.AuthServer/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** |
|||
|
|||
```json |
|||
"Redis": { |
|||
"Configuration": "redis-abpdemo.redis.cache.windows.net:6380,password={yourpassword},ssl=true,abortConnect=False" |
|||
}, |
|||
``` |
|||
|
|||
{{end}} |
|||
|
|||
{{ else if UI == "NG" }} |
|||
|
|||
- Modify the **`localhost:4200`** in every location throughout your project. |
|||
|
|||
This includes the following files: |
|||
|
|||
**./angular/src/environments/environment.prod.ts** , **./aspnet-core/src/yourapp.DbMigrator/appsettings.json** and **./aspnet-core/src/yourapp.HttpApi.Host/appsettings.json** |
|||
|
|||
```typescript |
|||
application: { |
|||
baseUrl: 'https://yourapp.azurestaticapps.net' |
|||
} |
|||
``` |
|||
|
|||
- Modify the **yourapp.HttpApi.Host** URL in every location throughout your project. |
|||
|
|||
This includes the following files: |
|||
|
|||
**./angular/src/environments/environment.prod.ts** , **./aspnet-core/src/yourapp.DbMigrator/appsettings.json** and **./aspnet-core/src/yourapp.HttpApi.Host/appsettings.json** |
|||
|
|||
```json |
|||
"App": { |
|||
"SelfUrl": "https://yourApiHost.azurewebsites.net" |
|||
} |
|||
``` |
|||
|
|||
{{ else if UI == "Blazor" }} |
|||
|
|||
- Modify the **yourapp.Blazor** URL in every location throughout your project. |
|||
|
|||
This includes the following files: |
|||
|
|||
**./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** |
|||
|
|||
```json |
|||
"App": { |
|||
"SelfUrl": "https://yourapp.azurewebsites.net" |
|||
} |
|||
``` |
|||
|
|||
- Modify the **yourapp.HttpApi.Host** URL in every location throughout your project. |
|||
|
|||
This includes the following files: |
|||
|
|||
**./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** |
|||
|
|||
```json |
|||
"App": { |
|||
"SelfUrl": "https://yourApiHost.azurewebsites.net" |
|||
} |
|||
``` |
|||
|
|||
{{ else }} |
|||
|
|||
{{if Tiered == "No"}} |
|||
|
|||
- Modify the **yourapp.Web** URL in every location throughout your project. |
|||
|
|||
This includes the following files: |
|||
|
|||
**./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** |
|||
|
|||
```json |
|||
"App": { |
|||
"SelfUrl": "https://yourapp.azurewebsites.net" |
|||
} |
|||
``` |
|||
|
|||
- Modify the **yourapp.ApiHost** URL in every location throughout your project. |
|||
|
|||
This includes the following files: |
|||
|
|||
**./src/yourapp.HttpApi.Host/appsettings.json** , **./src/yourapp.Blazor/appsettings.json** and **./src/yourapp.DbMigrator/appsettings.json** |
|||
|
|||
```json |
|||
"App": { |
|||
"SelfUrl": "https://yourapp-apihost.azurewebsites.net" |
|||
} |
|||
``` |
|||
|
|||
{{else}} |
|||
|
|||
- Modify the **yourapp.Web** URL in every location throughout your project. |
|||
|
|||
This includes the following files: |
|||
|
|||
**./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** , **./src/yourapp.HttpApi.Host/appsettings.json** and **./src/yourapp.AuthServer/appsettings.json** |
|||
|
|||
```json |
|||
"App": { |
|||
"SelfUrl": "https://yourapp.azurewebsites.net" |
|||
} |
|||
``` |
|||
|
|||
- Modify the **yourapp.ApiHost** URL in every location throughout your project. |
|||
|
|||
This includes the following files: |
|||
|
|||
**./src/yourapp.HttpApi.Host/appsettings.json** , **./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.AuthServer/appsettings.json** |
|||
|
|||
```json |
|||
"App": { |
|||
"SelfUrl": "https://yourapp-apihost.azurewebsites.net" |
|||
} |
|||
``` |
|||
|
|||
- Modify the **yourapp.AuthServer** URL in every location throughout your project. |
|||
|
|||
This includes the following files: |
|||
|
|||
**./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.AuthServer/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** |
|||
|
|||
```json |
|||
"App": { |
|||
"SelfUrl": "https://yourapp-authserver.azurewebsites.net" |
|||
} |
|||
``` |
|||
|
|||
- Modify the **Redis__Configuration** URL in every location throughout your project. |
|||
|
|||
This includes the following files: |
|||
|
|||
**./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.AuthServer/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json** |
|||
|
|||
```json |
|||
"Redis": { |
|||
"Configuration": "redis-abpdemo.redis.cache.windows.net:6380,password={yourpassword},ssl=true,abortConnect=False" |
|||
}, |
|||
``` |
|||
|
|||
{{end}} |
|||
|
|||
{{end}} |
|||
|
|||
|
|||
## What's next? |
|||
|
|||
- [Deploying Your ABP Application to Azure](step3-deployment-github-action.md) |
|||
@ -0,0 +1,735 @@ |
|||
````json |
|||
//[doc-params] |
|||
{ |
|||
"UI": ["MVC", "Blazor", "BlazorServer", "NG"], |
|||
"DB": ["EF", "Mongo"], |
|||
"Tiered": ["Yes", "No"] |
|||
} |
|||
```` |
|||
|
|||
## Step 3: Deploying the ABP Application to Azure Web App Service |
|||
|
|||
### Deploying the ABP Application to Azure Web App Service using GitHub Actions |
|||
|
|||
1. Create a new GitHub repository for your project if you don't have one. |
|||
|
|||
2. Push your project to the new GitHub repository. |
|||
|
|||
3. Navigate to the **Actions** tab of your GitHub repository. |
|||
|
|||
4. Click the **set up a workflow yourself** button. |
|||
|
|||
 |
|||
|
|||
5. Copy this content to the opened file and commit it. |
|||
|
|||
{{if UI == "NG"}} |
|||
|
|||
{%{ |
|||
|
|||
```yaml |
|||
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy |
|||
# More GitHub Actions for Azure: https://github.com/Azure/actions |
|||
|
|||
name: Build and deploy ASP.Net Core with Angular app to Azure Web App |
|||
|
|||
on: |
|||
push: |
|||
branches: |
|||
- main |
|||
workflow_dispatch: |
|||
|
|||
jobs: |
|||
build-backend: |
|||
runs-on: ubuntu-latest |
|||
|
|||
steps: |
|||
- uses: actions/checkout@v4 |
|||
|
|||
- name: Set up .NET Core |
|||
uses: actions/setup-dotnet@v4 |
|||
with: |
|||
dotnet-version: '8.x' |
|||
include-prerelease: true |
|||
|
|||
- name: Install ABP CLI |
|||
run: | |
|||
dotnet tool install -g Volo.Abp.Cli |
|||
abp install-libs |
|||
shell: bash |
|||
|
|||
- name: Build with dotnet |
|||
run: dotnet build --configuration Release |
|||
working-directory: ./aspnet-core |
|||
|
|||
- name: Run migrations |
|||
run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" |
|||
working-directory: ./aspnet-core/src/Demo.AzureAppsAngular.DbMigrator # Replace with your project name |
|||
|
|||
- name: dotnet publish apihost |
|||
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost |
|||
working-directory: ./aspnet-core/src/Demo.AzureAppsAngular.HttpApi.Host # Replace with your project name |
|||
|
|||
- name: Generate authserver.pfx |
|||
run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/apihost/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password |
|||
|
|||
- name: Upload artifact for apihost |
|||
uses: actions/upload-artifact@v4 |
|||
with: |
|||
name: .net-apihost |
|||
path: ${{env.DOTNET_ROOT}}/apihost |
|||
|
|||
deploy-backend: |
|||
runs-on: ubuntu-latest |
|||
needs: build-backend |
|||
environment: |
|||
name: 'Production' |
|||
url: ${{ steps.deploy-to-webapp-1.outputs.webapp-url }} |
|||
|
|||
steps: |
|||
- name: Download artifact from apihost |
|||
uses: actions/download-artifact@v1 |
|||
with: |
|||
name: .net-apihost |
|||
path: ./apihost |
|||
|
|||
- name: Deploy apihost |
|||
id: deploy-to-webapp-1 |
|||
uses: azure/webapps-deploy@v3 |
|||
with: |
|||
app-name: 'apihost-angular' # Replace with your app name |
|||
slot-name: 'Production' |
|||
publish-profile: ${{ secrets.apihostangularPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings |
|||
path: ./apihost |
|||
|
|||
build-deploy-frontend: |
|||
runs-on: ubuntu-latest |
|||
needs: deploy-backend |
|||
name: Build and Deploy Angular App |
|||
steps: |
|||
- uses: actions/checkout@v3 |
|||
with: |
|||
submodules: true |
|||
- name: Build And Deploy |
|||
id: builddeploy |
|||
uses: Azure/static-web-apps-deploy@v1 |
|||
with: |
|||
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_PROUD_STONE }} # Set your Azure Static Web App API token as a secret in your repository settings |
|||
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for GitHub integrations (eg: PR comments) |
|||
action: "upload" |
|||
app_location: "angular" # App source code path |
|||
api_location: "" # Api source code path - optional |
|||
output_location: "dist/AzureAppsAngular" # Built app content directory - optional |
|||
``` |
|||
|
|||
}%} |
|||
|
|||
{{ else if UI == "Blazor" }} |
|||
|
|||
{%{ |
|||
|
|||
```yaml |
|||
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy |
|||
# More GitHub Actions for Azure: https://github.com/Azure/actions |
|||
|
|||
name: Build and deploy ASP.Net Core with Blazor to Azure Web App |
|||
|
|||
on: |
|||
push: |
|||
branches: |
|||
- main |
|||
workflow_dispatch: |
|||
|
|||
jobs: |
|||
build-apihost: |
|||
runs-on: ubuntu-latest |
|||
|
|||
steps: |
|||
- uses: actions/checkout@v4 |
|||
|
|||
- name: Set up .NET Core |
|||
uses: actions/setup-dotnet@v4 |
|||
with: |
|||
dotnet-version: '8.x' |
|||
include-prerelease: true |
|||
|
|||
- name: Install ABP CLI |
|||
run: | |
|||
dotnet tool install -g Volo.Abp.Cli |
|||
abp install-libs |
|||
shell: bash |
|||
|
|||
- name: Build with dotnet |
|||
run: dotnet build --configuration Release |
|||
|
|||
- name: Run migrations |
|||
run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" |
|||
working-directory: ./src/demo.BlazorNonTierEfCore.DbMigrator # Replace with your project name |
|||
|
|||
- name: dotnet publish apihost |
|||
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost |
|||
working-directory: ./src/demo.BlazorNonTierEfCore.HttpApi.Host # Replace with your project name |
|||
|
|||
- name: Generate authserver.pfx |
|||
run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/apihost/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password |
|||
|
|||
- name: Upload artifact for apihost |
|||
uses: actions/upload-artifact@v4 |
|||
with: |
|||
name: .net-apihost |
|||
path: ${{env.DOTNET_ROOT}}/apihost |
|||
|
|||
deploy-apihost: |
|||
runs-on: ubuntu-latest |
|||
needs: build-apihost |
|||
environment: |
|||
name: 'Production' |
|||
|
|||
steps: |
|||
- name: Download artifact from apihost |
|||
uses: actions/download-artifact@v4 |
|||
with: |
|||
name: .net-apihost |
|||
path: ./apihost |
|||
|
|||
- name: Deploy apihost |
|||
id: deploy-to-webapp-2 |
|||
uses: azure/webapps-deploy@v3 |
|||
with: |
|||
app-name: 'apihost-blazor' # Replace with your app name |
|||
slot-name: 'Production' |
|||
publish-profile: ${{ secrets.apihostblazorPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings |
|||
|
|||
build-deploy-frontend: |
|||
runs-on: ubuntu-latest |
|||
needs: deploy-apihost |
|||
name: Build and Deploy Job |
|||
steps: |
|||
- uses: actions/checkout@v3 |
|||
with: |
|||
submodules: true |
|||
- name: Build And Deploy |
|||
id: builddeploy |
|||
uses: Azure/static-web-apps-deploy@v1 |
|||
with: |
|||
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS }} # Set your Azure Static Web App API token as a secret in your repository settings |
|||
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for GitHub integrations (eg: PR comments) |
|||
action: "upload" |
|||
app_location: "src/demo.BlazorNonTierEfCore.Blazor" # App source code path |
|||
api_location: "" # Api source code path - optional |
|||
output_location: "wwwroot" # Built app content directory - optional |
|||
``` |
|||
|
|||
}%} |
|||
|
|||
{{ else if UI == "BlazorServer" }} |
|||
|
|||
{{ if Tiered == "No" }} |
|||
|
|||
{%{ |
|||
|
|||
```yaml |
|||
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy |
|||
# More GitHub Actions for Azure: https://github.com/Azure/actions |
|||
|
|||
name: Build and deploy ASP.Net Core with BlazorServer to Azure Web App |
|||
|
|||
on: |
|||
push: |
|||
branches: |
|||
- main |
|||
workflow_dispatch: |
|||
|
|||
jobs: |
|||
build: |
|||
runs-on: ubuntu-latest |
|||
|
|||
steps: |
|||
- uses: actions/checkout@v4 |
|||
|
|||
- name: Set up .NET Core |
|||
uses: actions/setup-dotnet@v4 |
|||
with: |
|||
dotnet-version: '8.x' |
|||
include-prerelease: true |
|||
|
|||
- name: Install ABP CLI |
|||
run: | |
|||
dotnet tool install -g Volo.Abp.Cli |
|||
abp install-libs |
|||
shell: bash |
|||
|
|||
- name: Build with dotnet |
|||
run: dotnet build --configuration Release |
|||
|
|||
- name: Run migrations |
|||
run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" # Set your connection string as a secret in your repository settings |
|||
working-directory: ./src/blazorservertierdemo.DbMigrator # Replace with your project name |
|||
|
|||
- name: dotnet publish apihost |
|||
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost |
|||
working-directory: ./src/blazorservertierdemo.HttpApi.Host # Replace with your project name |
|||
|
|||
- name: Generate authserver.pfx |
|||
run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/apihost/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password |
|||
|
|||
- name: dotnet publish webapp |
|||
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/webapp |
|||
working-directory: ./src/blazorservertierdemo.Blazor # Replace with your project name |
|||
|
|||
- name: Upload artifact for apihost |
|||
uses: actions/upload-artifact@v4 |
|||
with: |
|||
name: .net-apihost |
|||
path: ${{env.DOTNET_ROOT}}/apihost |
|||
|
|||
- name: Upload artifact for webapp |
|||
uses: actions/upload-artifact@v4 |
|||
with: |
|||
name: .net-webapp |
|||
path: ${{env.DOTNET_ROOT}}/webapp |
|||
|
|||
deploy: |
|||
runs-on: ubuntu-latest |
|||
needs: build |
|||
environment: |
|||
name: 'Production' |
|||
url: ${{ steps.deploy-to-webapp-3.outputs.webapp-url }} |
|||
|
|||
- name: Download artifact from apihost |
|||
uses: actions/download-artifact@v4 |
|||
with: |
|||
name: .net-apihost |
|||
path: ./apihost |
|||
|
|||
- name: Deploy apihost |
|||
id: deploy-to-webapp-2 |
|||
uses: azure/webapps-deploy@v3 |
|||
with: |
|||
app-name: 'apihost-blazorserver' # Replace with your app name |
|||
slot-name: 'Production' |
|||
publish-profile: ${{ secrets.apihostblazorserverPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings |
|||
package: ./apihost |
|||
|
|||
- name: Download artifact from webapp |
|||
uses: actions/download-artifact@v4 |
|||
with: |
|||
name: .net-webapp |
|||
path: ./webapp |
|||
|
|||
- name: Deploy webapp |
|||
id: deploy-to-webapp-3 |
|||
uses: azure/webapps-deploy@v3 |
|||
with: |
|||
app-name: 'webapp-blazorserver' # Replace with your app name |
|||
slot-name: 'Production' |
|||
publish-profile: ${{ secrets.webappblazorserverPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings |
|||
package: ./webapp |
|||
``` |
|||
|
|||
}%} |
|||
|
|||
{{ else }} |
|||
|
|||
{%{ |
|||
|
|||
```yaml |
|||
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy |
|||
# More GitHub Actions for Azure: https://github.com/Azure/actions |
|||
|
|||
name: Build and deploy ASP.Net Core with BlazorServer to Azure Web App |
|||
|
|||
on: |
|||
push: |
|||
branches: |
|||
- main |
|||
workflow_dispatch: |
|||
|
|||
jobs: |
|||
build: |
|||
runs-on: ubuntu-latest |
|||
|
|||
steps: |
|||
- uses: actions/checkout@v4 |
|||
|
|||
- name: Set up .NET Core |
|||
uses: actions/setup-dotnet@v4 |
|||
with: |
|||
dotnet-version: '8.x' |
|||
include-prerelease: true |
|||
|
|||
- name: Install ABP CLI |
|||
run: | |
|||
dotnet tool install -g Volo.Abp.Cli |
|||
abp install-libs |
|||
shell: bash |
|||
|
|||
- name: Build with dotnet |
|||
run: dotnet build --configuration Release |
|||
|
|||
- name: Run migrations |
|||
run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" # Set your connection string as a secret in your repository settings |
|||
working-directory: ./src/blazorservertierdemo.DbMigrator # Replace with your project name |
|||
|
|||
- name: dotnet publish authserver |
|||
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/authserver |
|||
working-directory: ./src/blazorservertierdemo.AuthServer # Replace with your project name |
|||
|
|||
- name: Generate authserver.pfx |
|||
run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/authserver/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password |
|||
|
|||
- name: dotnet publish apihost |
|||
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost |
|||
working-directory: ./src/blazorservertierdemo.HttpApi.Host # Replace with your project name |
|||
|
|||
- name: dotnet publish webapp |
|||
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/webapp |
|||
working-directory: ./src/blazorservertierdemo.Blazor # Replace with your project name |
|||
|
|||
- name: Upload artifact for authserver |
|||
uses: actions/upload-artifact@v4 |
|||
with: |
|||
name: .net-authserver |
|||
path: ${{env.DOTNET_ROOT}}/authserver |
|||
|
|||
- name: Upload artifact for apihost |
|||
uses: actions/upload-artifact@v4 |
|||
with: |
|||
name: .net-apihost |
|||
path: ${{env.DOTNET_ROOT}}/apihost |
|||
|
|||
- name: Upload artifact for webapp |
|||
uses: actions/upload-artifact@v4 |
|||
with: |
|||
name: .net-webapp |
|||
path: ${{env.DOTNET_ROOT}}/webapp |
|||
|
|||
deploy: |
|||
runs-on: ubuntu-latest |
|||
needs: build |
|||
environment: |
|||
name: 'Production' |
|||
url: ${{ steps.deploy-to-webapp-3.outputs.webapp-url }} |
|||
|
|||
steps: |
|||
- name: Download artifact from authserver |
|||
uses: actions/download-artifact@v4 |
|||
with: |
|||
name: .net-authserver |
|||
path: ./authserver |
|||
|
|||
- name: Deploy authserver |
|||
id: deploy-to-webapp |
|||
uses: azure/webapps-deploy@v3 |
|||
with: |
|||
app-name: 'authserver-blazorserver' # Replace with your app name |
|||
slot-name: 'Production' |
|||
publish-profile: ${{ secrets.authserverblazorserverPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings |
|||
package: ./authserver |
|||
|
|||
- name: Download artifact from apihost |
|||
uses: actions/download-artifact@v4 |
|||
with: |
|||
name: .net-apihost |
|||
path: ./apihost |
|||
|
|||
- name: Deploy apihost |
|||
id: deploy-to-webapp-2 |
|||
uses: azure/webapps-deploy@v3 |
|||
with: |
|||
app-name: 'apihost-blazorserver' # Replace with your app name |
|||
slot-name: 'Production' |
|||
publish-profile: ${{ secrets.apihostblazorserverPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings |
|||
package: ./apihost |
|||
|
|||
- name: Download artifact from webapp |
|||
uses: actions/download-artifact@v4 |
|||
with: |
|||
name: .net-webapp |
|||
path: ./webapp |
|||
|
|||
- name: Deploy webapp |
|||
id: deploy-to-webapp-3 |
|||
uses: azure/webapps-deploy@v3 |
|||
with: |
|||
app-name: 'webapp-blazorserver' # Replace with your app name |
|||
slot-name: 'Production' |
|||
publish-profile: ${{ secrets.webappblazorserverPublishSettings }} # Set your Azure Web App publish your profile as a secret in your repository settings |
|||
``` |
|||
|
|||
}%} |
|||
|
|||
{{end}} |
|||
|
|||
{{ else if UI == "MVC" }} |
|||
|
|||
{{ if Tiered == "No" }} |
|||
|
|||
{%{ |
|||
|
|||
```yaml |
|||
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy |
|||
# More GitHub Actions for Azure: https://github.com/Azure/actions |
|||
|
|||
name: Build and deploy ASP.Net Core with MVC to Azure Web App |
|||
|
|||
on: |
|||
push: |
|||
branches: |
|||
- main |
|||
workflow_dispatch: |
|||
|
|||
jobs: |
|||
build: |
|||
runs-on: ubuntu-latest |
|||
|
|||
steps: |
|||
- uses: actions/checkout@v4 |
|||
|
|||
- name: Set up .NET Core |
|||
uses: actions/setup-dotnet@v4 |
|||
with: |
|||
dotnet-version: '8.x' |
|||
include-prerelease: true |
|||
|
|||
- name: Install ABP CLI |
|||
run: | |
|||
dotnet tool install -g Volo.Abp.Cli |
|||
abp install-libs |
|||
shell: bash |
|||
|
|||
- name: Build with dotnet |
|||
run: dotnet build --configuration Release |
|||
|
|||
- name: Run migrations |
|||
run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" # Set your connection string as a secret in your repository settings |
|||
working-directory: ./src/yourapp.DbMigrator # Replace with your project name |
|||
|
|||
- name: dotnet publish |
|||
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp |
|||
working-directory: ./src/yourapp.Web # Replace with your project name |
|||
|
|||
- name: Generate authserver.pfx |
|||
run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/myapp/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password |
|||
|
|||
- name: Upload artifact for deployment job |
|||
uses: actions/upload-artifact@v4 |
|||
with: |
|||
name: .net-app |
|||
path: ${{env.DOTNET_ROOT}}/myapp |
|||
|
|||
deploy: |
|||
runs-on: ubuntu-latest |
|||
needs: build |
|||
environment: |
|||
name: 'Production' |
|||
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} |
|||
|
|||
steps: |
|||
- name: Download artifact from build job |
|||
uses: actions/download-artifact@v4 |
|||
with: |
|||
name: .net-app |
|||
|
|||
- name: Deploy to Azure Web App |
|||
id: deploy-to-webapp |
|||
uses: azure/webapps-deploy@v3 |
|||
with: |
|||
app-name: 'yourapp' # Replace with your azure web app name |
|||
slot-name: 'Production' |
|||
publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE }} # Set your Azure Web App publish your profile as a secret in your repository settings |
|||
package: . |
|||
``` |
|||
|
|||
}%} |
|||
|
|||
{{ else }} |
|||
|
|||
{%{ |
|||
|
|||
```yaml |
|||
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy |
|||
# More GitHub Actions for Azure: https://github.com/Azure/actions |
|||
|
|||
name: Build and deploy ASP.Net Core with MVC to Azure Web App |
|||
|
|||
on: |
|||
push: |
|||
branches: |
|||
- main |
|||
workflow_dispatch: |
|||
|
|||
jobs: |
|||
build: |
|||
runs-on: ubuntu-latest |
|||
|
|||
steps: |
|||
- uses: actions/checkout@v4 |
|||
|
|||
- name: Set up .NET Core |
|||
uses: actions/setup-dotnet@v4 |
|||
with: |
|||
dotnet-version: '8.x' |
|||
include-prerelease: true |
|||
|
|||
- name: Install ABP CLI |
|||
run: | |
|||
dotnet tool install -g Volo.Abp.Cli |
|||
abp install-libs |
|||
shell: bash |
|||
|
|||
- name: Build with dotnet |
|||
run: dotnet build --configuration Release |
|||
|
|||
- name: Run migrations |
|||
run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" # Set your connection string as a secret in your repository settings |
|||
working-directory: ./src/mvctierdemo.DbMigrator # Replace with your project name |
|||
|
|||
- name: dotnet publish authserver |
|||
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/authserver |
|||
working-directory: ./src/mvctierdemo.AuthServer # Replace with your project name |
|||
|
|||
- name: Generate authserver.pfx |
|||
run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/authserver/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password |
|||
|
|||
- name: dotnet publish apihost |
|||
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost |
|||
working-directory: ./src/mvctierdemo.HttpApi.Host # Replace with your project name |
|||
|
|||
- name: dotnet publish webapp |
|||
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/webapp |
|||
working-directory: ./src/mvctierdemo.Web # Replace with your project name |
|||
|
|||
- name: Upload artifact for authserver |
|||
uses: actions/upload-artifact@v4 |
|||
with: |
|||
name: .net-authserver |
|||
path: ${{env.DOTNET_ROOT}}/authserver |
|||
|
|||
- name: Upload artifact for apihost |
|||
uses: actions/upload-artifact@v4 |
|||
with: |
|||
name: .net-apihost |
|||
path: ${{env.DOTNET_ROOT}}/apihost |
|||
|
|||
- name: Upload artifact for webapp |
|||
uses: actions/upload-artifact@v4 |
|||
with: |
|||
name: .net-webapp |
|||
path: ${{env.DOTNET_ROOT}}/webapp |
|||
|
|||
deploy: |
|||
runs-on: ubuntu-latest |
|||
needs: build |
|||
environment: |
|||
name: 'Production' |
|||
url: ${{ steps.deploy-to-webapp-3.outputs.webapp-url }} |
|||
|
|||
steps: |
|||
- name: Download artifact from apihost |
|||
uses: actions/download-artifact@v4 |
|||
with: |
|||
name: .net-apihost |
|||
path: ./apihost |
|||
|
|||
- name: Deploy apihost |
|||
id: deploy-to-webapp-2 |
|||
uses: azure/webapps-deploy@v3 |
|||
with: |
|||
app-name: 'apihost-prodemo' |
|||
slot-name: 'Production' |
|||
publish-profile: ${{ secrets.apihostprodemoPublishSettings }} # Set your Azure Web App publish your profile as a secret in your repository settings |
|||
package: ./apihost |
|||
|
|||
- name: Download artifact from authserver |
|||
uses: actions/download-artifact@v4 |
|||
with: |
|||
name: .net-authserver |
|||
path: ./authserver |
|||
|
|||
- name: Deploy authserver |
|||
id: deploy-to-webapp |
|||
uses: azure/webapps-deploy@v3 |
|||
with: |
|||
app-name: 'authserver-prodemo' |
|||
slot-name: 'Production' |
|||
publish-profile: ${{ secrets.authserverprodemoPublishSettings }} # Set your Azure Web App publish your profile as a secret in your repository settings |
|||
package: ./authserver |
|||
|
|||
- name: Download artifact from webapp |
|||
uses: actions/download-artifact@v4 |
|||
with: |
|||
name: .net-webapp |
|||
path: ./webapp |
|||
|
|||
- name: Deploy webapp |
|||
id: deploy-to-webapp-3 |
|||
uses: azure/webapps-deploy@v3 |
|||
with: |
|||
app-name: 'webapp-prodemo' |
|||
slot-name: 'Production' |
|||
publish-profile: ${{ secrets.webappprodemoPublishSettings }} # Set your Azure Web App publish your profile as a secret in your repository settings |
|||
package: ./webapp |
|||
``` |
|||
|
|||
}%} |
|||
|
|||
{{end}} |
|||
|
|||
{{end}} |
|||
|
|||
|
|||
7. Navigate to the **Settings** tab of your GitHub repository. |
|||
|
|||
8. Click the **Secrets** button. |
|||
|
|||
9. Click the **New repository secret** button. |
|||
|
|||
 |
|||
|
|||
10. Add the following secrets: |
|||
|
|||
- **CONNECTION_STRING**: The connection string of your database. |
|||
|
|||
Example of Azure SQL connection string: |
|||
|
|||
 |
|||
|
|||
- **AZUREAPPSERVICE_PUBLISHPROFILE**: The publish the profile of your Azure Web App Service. You can download it from the **Overview** tab of your Azure Web App Service. |
|||
|
|||
 |
|||
|
|||
{{ if UI == "NG" || UI == "Blazor"}} |
|||
|
|||
- **AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS**: The API token of your Azure Static Web App. You can get it from the **Overview** tab of your Azure Static Web App. |
|||
|
|||
 |
|||
|
|||
{{end}} |
|||
|
|||
11. Navigate to the **Actions** tab of your GitHub repository. |
|||
|
|||
12. Click the **Deploy to Azure Web App** workflow. |
|||
|
|||
 |
|||
|
|||
13. Click the **Run workflow** button. |
|||
|
|||
 |
|||
|
|||
14. Navigate to the web app URL to see the deployed application. |
|||
|
|||
 |
|||
|
|||
> If deploying your application was unsuccessful, you can check the logs of the deployment by clicking the **Deploy to Azure Web App** workflow and then clicking the **deploy-to-webapp** job. |
|||
|
|||
> If deployment is successful, but you get an error when you navigate to the web app url, you can check the logs of the web app by clicking the **Logs** button on the **Overview** tab of your Azure Web App Service. |
|||
|
|||
> Finally, you have the CI/CD pipeline for your application. Every time you push your code to the main branch, your application will be deployed to Azure Web App Service automatically. |
|||
|
|||
|
|||
## What's next? |
|||
|
|||
- [Docker Deployment using Docker Compose](../deployment-docker-compose.md) |
|||
|
|||
- [IIS Deployment](../deployment-iis.md) |
|||
@ -0,0 +1,572 @@ |
|||
# Provisioning an Azure Web App using Terraform |
|||
|
|||
````json |
|||
//[doc-params] |
|||
{ |
|||
"UI": ["MVC", "Blazor", "BlazorServer", "NG"], |
|||
"DB": ["EF", "Mongo"], |
|||
"Tiered": ["Yes", "No"] |
|||
} |
|||
```` |
|||
|
|||
In this tutorial, we'll walk through the steps to provision an Azure Web App using Terraform. Terraform is an open-source infrastructure as a code tool that allows you to define and manage your infrastructure in a declarative way. |
|||
|
|||
## Prerequisites |
|||
|
|||
Before you begin, you'll need the following: |
|||
|
|||
- [Azure account](https://azure.microsoft.com/en-us/free/) |
|||
- [Terraform installed](https://developer.hashicorp.com/terraform/downloads) on your local machine |
|||
- [Azure CLI installed](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) on your local machine |
|||
|
|||
## Creating a Service Principal for Terraform in Azure |
|||
|
|||
When working with Terraform on Azure, you'll need a "Service Principal" for authentication. A "Service Principal" is an identity created to be used with applications, hosted services, and automated tools to access Azure resources. |
|||
|
|||
[To create a service principal](https://learn.microsoft.com/en-us/azure/developer/terraform/authenticate-to-azure?tabs=bash#create-a-service-principal), run the following command in the Azure CLI: |
|||
|
|||
1. Login to Azure CLI |
|||
|
|||
Before you begin, make sure you are logged into your Azure account with the Azure CLI: |
|||
```bash |
|||
az login |
|||
``` |
|||
|
|||
2. Set your Subscription: |
|||
|
|||
If you have multiple Azure subscriptions, specify the one you intend to use: |
|||
```bash |
|||
az account set --subscription="YOUR_SUBSCRIPTION_ID" |
|||
``` |
|||
|
|||
3. Create the Service Principal: |
|||
|
|||
The following command will create a service principal. Replace YOUR_APP_NAME with a suitable name for your application: |
|||
```bash |
|||
az ad sp create-for-rbac --name "YOUR_APP_NAME" --role contributor --scopes /subscriptions/YOUR_SUBSCRIPTION_ID |
|||
``` |
|||
> Replace `YOUR_SUBSCRIPTION_ID` with your subscription id. |
|||
|
|||
The output of this command will provide the **appId**, **displayName**, **name**, **password**, and **tenant**. It's crucial to note these values, especially **appId (Client ID)** and **password (Client Secret)**, as you'll need them for Terraform authentication. |
|||
|
|||
4. Specify the service principal credentials in environment variables |
|||
|
|||
bash: |
|||
```bash |
|||
export ARM_SUBSCRIPTION_ID="<azure_subscription_id>" |
|||
export ARM_TENANT_ID="<azure_subscription_tenant_id>" |
|||
export ARM_CLIENT_ID="<service_principal_appid>" |
|||
export ARM_CLIENT_SECRET="<service_principal_password>" |
|||
``` |
|||
To execute the ~/.bashrc script, run source ~/.bashrc (or its abbreviated equivalent . ~/.bashrc). You can also exit and reopen Cloud Shell for the script to run automatically. |
|||
Run the following bash command to verify the Azure environment variables: |
|||
```bash |
|||
. ~/.bashrc |
|||
``` |
|||
powershell: |
|||
```powershell |
|||
$env:ARM_SUBSCRIPTION_ID="<azure_subscription_id>" |
|||
$env:ARM_TENANT_ID="<azure_subscription_tenant_id>" |
|||
$env:ARM_CLIENT_ID="<service_principal_appid>" |
|||
$env:ARM_CLIENT_SECRET="<service_principal_password>" |
|||
``` |
|||
Run the following PowerShell command to verify the Azure environment variables: |
|||
```powershell |
|||
gci env:ARM_* |
|||
``` |
|||
> Replace the values with your own. |
|||
|
|||
## Creating a Terraform Configuration |
|||
|
|||
1. Create a new directory for your Terraform configuration files. |
|||
|
|||
2. Create a new file named `main.tf` in the directory and add the following code: |
|||
|
|||
{{if UI == "NG"}} |
|||
|
|||
```terraform |
|||
# Configure the Azure provider |
|||
terraform { |
|||
required_providers { |
|||
azurerm = { |
|||
source = "hashicorp/azurerm" |
|||
version = "~> 3.0.0" |
|||
} |
|||
} |
|||
required_version = ">= 0.14.9" |
|||
} |
|||
provider "azurerm" { |
|||
features {} |
|||
} |
|||
|
|||
# Create the resource group |
|||
resource "azurerm_resource_group" "rg" { |
|||
name = "demo-angular-web-app-rg" |
|||
location = "westeurope" |
|||
} |
|||
|
|||
# Create the Linux App Service Plan |
|||
resource "azurerm_service_plan" "appserviceplan" { |
|||
name = "demo-angular-web-app-plan" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
os_type = "Linux" |
|||
sku_name = "B3" |
|||
} |
|||
|
|||
|
|||
resource "azurerm_linux_web_app" "apihost" { |
|||
name = "apihost-angular" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
service_plan_id = azurerm_service_plan.appserviceplan.id |
|||
https_only = true |
|||
site_config { |
|||
application_stack { |
|||
dotnet_version = "6.0" |
|||
} |
|||
minimum_tls_version = "1.2" |
|||
} |
|||
} |
|||
|
|||
resource "azurerm_static_site" "angularweb" { |
|||
name = "angularweb" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
} |
|||
``` |
|||
|
|||
{{ else if UI == "Blazor" }} |
|||
|
|||
```terraform |
|||
# Configure the Azure provider |
|||
terraform { |
|||
required_providers { |
|||
azurerm = { |
|||
source = "hashicorp/azurerm" |
|||
version = "~> 3.0.0" |
|||
} |
|||
} |
|||
required_version = ">= 0.14.9" |
|||
} |
|||
provider "azurerm" { |
|||
features {} |
|||
} |
|||
|
|||
# Create the resource group |
|||
resource "azurerm_resource_group" "rg" { |
|||
name = "blazor-app-nontier-rg" |
|||
location = "westeurope" |
|||
} |
|||
|
|||
# Create the Linux App Service Plan |
|||
resource "azurerm_service_plan" "appserviceplan" { |
|||
name = "blazor-app-nontier-plan" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
os_type = "Linux" |
|||
sku_name = "B3" |
|||
} |
|||
|
|||
# Create the web app, pass in the App Service Plan ID |
|||
|
|||
resource "azurerm_linux_web_app" "apihost" { |
|||
name = "apihost-blazor" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
service_plan_id = azurerm_service_plan.appserviceplan.id |
|||
https_only = true |
|||
site_config { |
|||
application_stack { |
|||
dotnet_version = "6.0" |
|||
} |
|||
minimum_tls_version = "1.2" |
|||
} |
|||
} |
|||
resource "azurerm_static_site" "blazorweb" { |
|||
name = "blazorweb" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
} |
|||
``` |
|||
|
|||
{{ else if UI == "BlazorServer" }} |
|||
|
|||
{{if Tiered == "No"}} |
|||
|
|||
```terraform |
|||
# Configure the Azure provider |
|||
terraform { |
|||
required_providers { |
|||
azurerm = { |
|||
source = "hashicorp/azurerm" |
|||
version = "~> 3.0.0" |
|||
} |
|||
} |
|||
required_version = ">= 0.14.9" |
|||
} |
|||
provider "azurerm" { |
|||
features {} |
|||
} |
|||
|
|||
# Create the resource group |
|||
resource "azurerm_resource_group" "rg" { |
|||
name = "blazorserver-app-nontier-rg" |
|||
location = "westeurope" |
|||
} |
|||
|
|||
# Create the Linux App Service Plan |
|||
resource "azurerm_service_plan" "appserviceplan" { |
|||
name = "blazorserver-app-nontier-plan" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
os_type = "Linux" |
|||
sku_name = "B3" |
|||
} |
|||
|
|||
# Create the web app, pass in the App Service Plan ID |
|||
resource "azurerm_linux_web_app" "authserver" { |
|||
name = "authserver-blazorserver" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
service_plan_id = azurerm_service_plan.appserviceplan.id |
|||
https_only = true |
|||
site_config { |
|||
application_stack { |
|||
dotnet_version = "6.0" |
|||
} |
|||
minimum_tls_version = "1.2" |
|||
} |
|||
} |
|||
resource "azurerm_linux_web_app" "apihost" { |
|||
name = "apihost-blazorserver" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
service_plan_id = azurerm_service_plan.appserviceplan.id |
|||
https_only = true |
|||
site_config { |
|||
application_stack { |
|||
dotnet_version = "6.0" |
|||
} |
|||
minimum_tls_version = "1.2" |
|||
} |
|||
} |
|||
resource "azurerm_linux_web_app" "webapp" { |
|||
name = "webapp-blazorserver" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
service_plan_id = azurerm_service_plan.appserviceplan.id |
|||
https_only = true |
|||
site_config { |
|||
application_stack { |
|||
dotnet_version = "6.0" |
|||
} |
|||
minimum_tls_version = "1.2" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
{{ else }} |
|||
|
|||
```terraform |
|||
# Configure the Azure provider |
|||
terraform { |
|||
required_providers { |
|||
azurerm = { |
|||
source = "hashicorp/azurerm" |
|||
version = "~> 3.0.0" |
|||
} |
|||
} |
|||
required_version = ">= 0.14.9" |
|||
} |
|||
provider "azurerm" { |
|||
features {} |
|||
} |
|||
|
|||
# Create the resource group |
|||
resource "azurerm_resource_group" "rg" { |
|||
name = "blazorserver-app-tier-rg" |
|||
location = "westeurope" |
|||
} |
|||
|
|||
# Create the Linux App Service Plan |
|||
resource "azurerm_service_plan" "appserviceplan" { |
|||
name = "blazorserver-app-tier-plan" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
os_type = "Linux" |
|||
sku_name = "B3" |
|||
} |
|||
|
|||
# Create the web app, pass in the App Service Plan ID |
|||
resource "azurerm_linux_web_app" "authserver" { |
|||
name = "authserver-blazorserver" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
service_plan_id = azurerm_service_plan.appserviceplan.id |
|||
https_only = true |
|||
site_config { |
|||
application_stack { |
|||
dotnet_version = "6.0" |
|||
} |
|||
minimum_tls_version = "1.2" |
|||
} |
|||
app_settings = { |
|||
"Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string |
|||
} |
|||
} |
|||
resource "azurerm_linux_web_app" "apihost" { |
|||
name = "apihost-blazorserver" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
service_plan_id = azurerm_service_plan.appserviceplan.id |
|||
https_only = true |
|||
site_config { |
|||
application_stack { |
|||
dotnet_version = "6.0" |
|||
} |
|||
minimum_tls_version = "1.2" |
|||
} |
|||
app_settings = { |
|||
"Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string |
|||
} |
|||
} |
|||
resource "azurerm_linux_web_app" "webapp" { |
|||
name = "webapp-blazorserver" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
service_plan_id = azurerm_service_plan.appserviceplan.id |
|||
https_only = true |
|||
site_config { |
|||
application_stack { |
|||
dotnet_version = "6.0" |
|||
} |
|||
minimum_tls_version = "1.2" |
|||
} |
|||
app_settings = { |
|||
"Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string |
|||
} |
|||
} |
|||
|
|||
resource "azurerm_redis_cache" "redis" { |
|||
name = "redis-blazorserver" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
capacity = 0 |
|||
family = "C" |
|||
sku_name = "Basic" |
|||
enable_non_ssl_port = false |
|||
minimum_tls_version = "1.2" |
|||
|
|||
redis_configuration { |
|||
maxmemory_reserved = 2 |
|||
maxmemory_delta = 2 |
|||
maxmemory_policy = "volatile-lru" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
{{end}} |
|||
|
|||
{{ else if UI == "MVC" }} |
|||
|
|||
{{ if Tiered == "No" }} |
|||
|
|||
```terraform |
|||
# Configure the Azure provider |
|||
terraform { |
|||
required_providers { |
|||
azurerm = { |
|||
source = "hashicorp/azurerm" |
|||
version = "~> 3.0.0" |
|||
} |
|||
} |
|||
required_version = ">= 0.14.9" |
|||
} |
|||
provider "azurerm" { |
|||
features {} |
|||
} |
|||
|
|||
# Create the resource group |
|||
resource "azurerm_resource_group" "rg" { |
|||
name = "demo-abp-web-app" |
|||
location = "westeurope" |
|||
} |
|||
|
|||
# Create the Linux App Service Plan |
|||
resource "azurerm_service_plan" "appserviceplan" { |
|||
name = "demo-abp-web-app-plan" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
os_type = "Linux" |
|||
sku_name = "B3" |
|||
} |
|||
|
|||
# Create the web app, pass in the App Service Plan ID |
|||
resource "azurerm_linux_web_app" "webapp" { |
|||
name = "demo-abp-web-app" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
service_plan_id = azurerm_service_plan.appserviceplan.id |
|||
https_only = true |
|||
site_config { |
|||
application_stack { |
|||
dotnet_version = "6.0" |
|||
} |
|||
minimum_tls_version = "1.2" |
|||
} |
|||
} |
|||
|
|||
output "webappurl" { |
|||
|
|||
value = "${azurerm_linux_web_app.webapp.name}.azurewebsites.net" |
|||
} |
|||
``` |
|||
|
|||
{{ else }} |
|||
|
|||
```terraform |
|||
# Configure the Azure provider |
|||
terraform { |
|||
required_providers { |
|||
azurerm = { |
|||
source = "hashicorp/azurerm" |
|||
version = "~> 3.0.0" |
|||
} |
|||
} |
|||
required_version = ">= 0.14.9" |
|||
} |
|||
provider "azurerm" { |
|||
features {} |
|||
} |
|||
|
|||
# Create the resource group |
|||
resource "azurerm_resource_group" "rg" { |
|||
name = "demo-abp-web-app-tier-rg" |
|||
location = "westeurope" |
|||
} |
|||
|
|||
# Create the Linux App Service Plan |
|||
resource "azurerm_service_plan" "appserviceplan" { |
|||
name = "demo-abp-web-app-tier-plan" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
os_type = "Linux" |
|||
sku_name = "B3" |
|||
} |
|||
|
|||
# Create the web app, pass in the App Service Plan ID |
|||
resource "azurerm_linux_web_app" "authserver" { |
|||
name = "authserver-prodemo" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
service_plan_id = azurerm_service_plan.appserviceplan.id |
|||
https_only = true |
|||
site_config { |
|||
application_stack { |
|||
dotnet_version = "6.0" |
|||
} |
|||
minimum_tls_version = "1.2" |
|||
} |
|||
app_settings = { |
|||
"Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string |
|||
} |
|||
} |
|||
resource "azurerm_linux_web_app" "apihost" { |
|||
name = "apihost-prodemo" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
service_plan_id = azurerm_service_plan.appserviceplan.id |
|||
https_only = true |
|||
site_config { |
|||
application_stack { |
|||
dotnet_version = "6.0" |
|||
} |
|||
minimum_tls_version = "1.2" |
|||
} |
|||
app_settings = { |
|||
"Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string |
|||
} |
|||
} |
|||
resource "azurerm_linux_web_app" "webapp" { |
|||
name = "webapp-prodemo" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
service_plan_id = azurerm_service_plan.appserviceplan.id |
|||
https_only = true |
|||
site_config { |
|||
application_stack { |
|||
dotnet_version = "6.0" |
|||
} |
|||
minimum_tls_version = "1.2" |
|||
} |
|||
app_settings = { |
|||
"Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string |
|||
} |
|||
} |
|||
|
|||
resource "azurerm_redis_cache" "redis" { |
|||
name = "redis-prodemo" |
|||
location = azurerm_resource_group.rg.location |
|||
resource_group_name = azurerm_resource_group.rg.name |
|||
capacity = 0 |
|||
family = "C" |
|||
sku_name = "Basic" |
|||
enable_non_ssl_port = false |
|||
minimum_tls_version = "1.2" |
|||
|
|||
redis_configuration { |
|||
maxmemory_reserved = 2 |
|||
maxmemory_delta = 2 |
|||
maxmemory_policy = "volatile-lru" |
|||
} |
|||
} |
|||
|
|||
output "authserver" { |
|||
|
|||
value = "${azurerm_linux_web_app.authserver.name}.azurewebsites.net" |
|||
} |
|||
|
|||
output "apihost" { |
|||
|
|||
value = "${azurerm_linux_web_app.apihost.name}.azurewebsites.net" |
|||
} |
|||
|
|||
output "webapp" { |
|||
|
|||
value = "${azurerm_linux_web_app.webapp.name}.azurewebsites.net" |
|||
} |
|||
|
|||
output "redis_hostname" { |
|||
value = azurerm_redis_cache.redis.hostname |
|||
description = "The hostname for the Redis instance." |
|||
} |
|||
``` |
|||
|
|||
{{end}} |
|||
|
|||
{{end}} |
|||
|
|||
|
|||
3. Run `terraform init` to initialize the directory. |
|||
|
|||
4. Run `terraform plan` to see the execution plan. |
|||
|
|||
5. Run `terraform apply` to apply the changes. Write `yes` when prompted to confirm the deployment. |
|||
|
|||
6. Wait for the deployment to complete. |
|||
|
|||
7. Navigate to the web app URL to see the deployed application. |
|||
|
|||
> You can also see the web app URL in the output of the `terraform apply` command. |
|||
|
|||
> You have to change the **dotnet version** of the runtime stack according to your application. For example, if you are using .NET 7, you should change `dotnet_version = "6.0"` to `dotnet_version = "7.0"`. |
|||
|
|||
 |
|||
|
|||
## Destroying the Terraform Configuration |
|||
|
|||
1. Run `terraform destroy` to destroy the created resources. |
|||
|
|||
2. Type `yes` when prompted to confirm the destruction. |
|||
|
|||
@ -0,0 +1,292 @@ |
|||
# IIS Deployment |
|||
|
|||
````json |
|||
//[doc-params] |
|||
{ |
|||
"UI": ["MVC", "Blazor", "BlazorServer", "NG"], |
|||
"DB": ["EF", "Mongo"], |
|||
"Tiered": ["Yes", "No"] |
|||
} |
|||
```` |
|||
|
|||
> This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider. For other options, please change the preference on top of this document. |
|||
|
|||
## Prerequisites |
|||
|
|||
- An IIS Server that is ready for deployment. |
|||
|
|||
- Install the [hosting bundle](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/hosting-bundle). |
|||
|
|||
- **{{ DB_Value }}** database must be ready to use with your project. |
|||
|
|||
- If you want to publish in a local environment, this guide will use mkcert to create self-signed certificates. Follow the [installation guide](https://github.com/FiloSottile/mkcert#installation) to install mkcert. |
|||
|
|||
{{ if Tiered == "Yes" }} |
|||
|
|||
- A Redis instance prepared for caching. |
|||
|
|||
{{end}} |
|||
|
|||
## Generate an Authentication Certificate |
|||
|
|||
If you're using OpenIddict, you need to generate an authentication certificate. You can execute this command in {{ if Tiered == "Yes" }}AuthServer{{ else if UI == "NG" || UI == "Blazor" }}HttpApi.Host{{ else if UI == "BlazorServer" }}Blazor{{ else }}Web{{ end }} folder. |
|||
|
|||
````bash |
|||
dotnet dev-certs https -v -ep authserver.pfx -p 00000000-0000-0000-0000-000000000000 |
|||
```` |
|||
|
|||
> `00000000-0000-0000-0000-000000000000` is the password of the certificate, you can change it to any password you want. |
|||
|
|||
## Creating the Publish Files |
|||
|
|||
You can execute this commands in your project root folder. |
|||
|
|||
````bash |
|||
dotnet publish ./src/Volo.Sample.DbMigrator/Volo.Sample.DbMigrator.csproj -c Release -o ./publish/dbmigrator # Replace with your project name |
|||
```` |
|||
|
|||
{{ if UI == "NG" }} |
|||
|
|||
````bash |
|||
cd angular && yarn build:prod --output-path ../publish/angular && cd .. |
|||
dotnet publish ./aspnet-core/src/Volo.Sample.HttpApi.Host/Volo.Sample.HttpApi.Host.csproj -c Release -o ./publish/apihost # Replace with your project name |
|||
{{ if Tiered == "Yes" }} |
|||
dotnet publish ./aspnet-core/src/Volo.Sample.AuthServer/Volo.Sample.AuthServer.csproj -c Release -o ./publish/authserver # Replace with your project name |
|||
{{ end }} |
|||
```` |
|||
|
|||
{{ else if UI == "Blazor" }} |
|||
|
|||
````bash |
|||
dotnet publish ./src/Volo.Sample.Blazor/Volo.Sample.Blazor.csproj -c Release -o ./publish/blazor # Replace with your project name |
|||
dotnet publish ./src/Volo.Sample.HttpApi.Host/Volo.Sample.HttpApi.Host.csproj -c Release -o ./publish/apihost # Replace with your project name |
|||
{{ if Tiered == "Yes" }} |
|||
dotnet publish ./src/Volo.Sample.AuthServer/Volo.Sample.AuthServer.csproj -c Release -o ./publish/authserver # Replace with your project name |
|||
{{ end }} |
|||
```` |
|||
|
|||
{{ else if UI == "BlazorServer" }} |
|||
|
|||
````bash |
|||
dotnet publish ./src/Volo.Sample.Blazor/Volo.Sample.Blazor.csproj -c Release -o ./publish/blazor # Replace with your project name |
|||
{{ if Tiered == "Yes" }} |
|||
dotnet publish ./src/Volo.Sample.HttpApi.Host/Volo.Sample.HttpApi.Host.csproj -c Release -o ./publish/apihost # Replace with your project name |
|||
dotnet publish ./src/Volo.Sample.AuthServer/Volo.Sample.AuthServer.csproj -c Release -o ./publish/authserver # Replace with your project name |
|||
{{ end }} |
|||
```` |
|||
|
|||
{{ else }} |
|||
|
|||
````bash |
|||
dotnet publish ./src/Volo.Sample.Web/Volo.Sample.Web.csproj -c Release -o ./publish/web # Replace with your project name |
|||
{{ if Tiered == "Yes" }} |
|||
dotnet publish ./src/Volo.Sample.HttpApi.Host/Volo.Sample.HttpApi.Host.csproj -c Release -o ./publish/apihost # Replace with your project name |
|||
dotnet publish ./src/Volo.Sample.AuthServer/Volo.Sample.AuthServer.csproj -c Release -o ./publish/authserver # Replace with your project name |
|||
{{ end }} |
|||
```` |
|||
|
|||
{{ end }} |
|||
|
|||
## Run the DbMigrator With Your Custom Settings |
|||
|
|||
Update the connection string and OpenIddict section with your domain names. Run the DbMigrator app. |
|||
|
|||
> For example, in a tiered MVC project. |
|||
|
|||
````json |
|||
{ |
|||
"ConnectionStrings": { |
|||
"Default": "Server=volo.sample;Database=Sample;User Id=sa;Password=1q2w3E**;TrustServerCertificate=true" |
|||
}, |
|||
"Redis": { |
|||
"Configuration": "volo.sample" |
|||
}, |
|||
"OpenIddict": { |
|||
"Applications": { |
|||
"Sample_Web": { |
|||
"ClientId": "Sample_Web", |
|||
"ClientSecret": "1q2w3e*", |
|||
"RootUrl": "https://web.sample" |
|||
}, |
|||
"Sample_Swagger": { |
|||
"ClientId": "Sample_Swagger", |
|||
"RootUrl": "https://api.sample" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
## Preparing for Local Deployment |
|||
|
|||
You can skip this part if you're going to deploy on a server with real domain names. |
|||
|
|||
### Creating a Self-Signed Certificate with mkcert |
|||
|
|||
You can execute this command in your command prompt. |
|||
|
|||
````bash |
|||
cd Desktop # or another path |
|||
mkcert -pkcs12 auth.sample api.sample web.sample # Replace with your domain names |
|||
```` |
|||
|
|||
Rename the created file extension to ".pfx" |
|||
|
|||
Import the certificate to IIS |
|||
|
|||
 |
|||
|
|||
### Add domain names to hosts file |
|||
|
|||
Add domain names to hosts file(in Windows: `C:\Windows\System32\drivers\etc\hosts`, in Linux and macOS: `/etc/hosts`). |
|||
|
|||
> For example, in a tiered MVC project. |
|||
````json |
|||
127.0.0.1 auth.sample |
|||
127.0.0.1 api.sample |
|||
127.0.0.1 web.sample |
|||
```` |
|||
|
|||
## Publish the Application(s) On IIS |
|||
|
|||
### Update the appsettings |
|||
|
|||
Update the appsettings according to your project type and domain names. |
|||
|
|||
> For example, in a tiered MVC project. |
|||
|
|||
````json |
|||
//AuthServer |
|||
{ |
|||
"App": { |
|||
"SelfUrl": "https://auth.sample", |
|||
"CorsOrigins": "https://api.sample,https://web.sample", |
|||
"RedirectAllowedUrls": "https://api.sample,https://web.sample", |
|||
"DisablePII": "false" |
|||
}, |
|||
"ConnectionStrings": { |
|||
"Default": "Server=volo.sample;Database=Sample;User Id=sa;Password=1q2w3E**;TrustServerCertificate=true" |
|||
}, |
|||
"AuthServer": { |
|||
"Authority": "https://auth.sample", |
|||
"RequireHttpsMetadata": "true" |
|||
}, |
|||
"StringEncryption": { |
|||
"DefaultPassPhrase": "f9uRkTLdtAZLmlh3" |
|||
}, |
|||
"Redis": { |
|||
"Configuration": "volo.sample" |
|||
} |
|||
} |
|||
//HttpApi.Host |
|||
{ |
|||
"App": { |
|||
"SelfUrl": "https://api.sample", |
|||
"CorsOrigins": "https://web.sample", |
|||
"DisablePII": "false", |
|||
"HealthCheckUrl": "/health-status" |
|||
}, |
|||
"ConnectionStrings": { |
|||
"Default": "Server=volo.sample;Database=Sample;User Id=sa;Password=1q2w3E**;TrustServerCertificate=true" |
|||
}, |
|||
"Redis": { |
|||
"Configuration": "volo.sample" |
|||
}, |
|||
"AuthServer": { |
|||
"Authority": "https://auth.sample", |
|||
"RequireHttpsMetadata": "true", |
|||
"SwaggerClientId": "Sample_Swagger" |
|||
}, |
|||
"StringEncryption": { |
|||
"DefaultPassPhrase": "f9uRkTLdtAZLmlh3" |
|||
} |
|||
} |
|||
//Web |
|||
{ |
|||
"App": { |
|||
"SelfUrl": "https://web.sample", |
|||
"DisablePII": "false" |
|||
}, |
|||
"RemoteServices": { |
|||
"Default": { |
|||
"BaseUrl": "https://api.sample/" |
|||
}, |
|||
"AbpAccountPublic": { |
|||
"BaseUrl": "https://auth.sample/" |
|||
} |
|||
}, |
|||
"Redis": { |
|||
"Configuration": "volo.sample" |
|||
}, |
|||
"AuthServer": { |
|||
"Authority": "https://auth.sample", |
|||
"RequireHttpsMetadata": "true", |
|||
"ClientId": "Sample_Web", |
|||
"ClientSecret": "1q2w3e*" |
|||
}, |
|||
"StringEncryption": { |
|||
"DefaultPassPhrase": "f9uRkTLdtAZLmlh3" |
|||
} |
|||
} |
|||
```` |
|||
|
|||
### Copy the .pfx file |
|||
|
|||
You need to copy pfx file from ./src/{{ if Tiered == "Yes" }}AuthServer{{ else if UI == "NG" || UI == "Blazor" }}HttpApi.Host{{ else if UI == "BlazorServer" }}Blazor{{ else }}Web{{ end }} to ./publish/{{ if Tiered == "Yes" }}authserver{{ else if UI == "NG" || UI == "Blazor" }}apihost{{ else if UI == "BlazorServer" }}blazor{{ else }}web{{ end }} folder. |
|||
|
|||
### Publish the Applications(s) |
|||
|
|||
You can add as website from IIS. |
|||
|
|||
> For {{ if Tiered == "Yes" }}authserver{{ else if UI == "NG" || UI == "Blazor" }}apihost{{ else if UI == "BlazorServer" }}blazor{{ else }}web{{ end }} we need to enable load user profile to true from application pool for created web site. |
|||
|
|||
 |
|||
|
|||
> For local deployment select the SSL certificate when you add the web site. |
|||
|
|||
 |
|||
|
|||
The final result should look like this (depending on your project type). |
|||
|
|||
 |
|||
|
|||
We can visit the websites from a browser. |
|||
|
|||
 |
|||
|
|||
## How to get stdout-log |
|||
|
|||
If your application is running on IIS and getting errors like `502.5, 500.3x`, you can enable stdout logs to see the error details. |
|||
|
|||
To enable and view stdout logs: |
|||
|
|||
1. Navigate to the site's deployment folder on the hosting system. |
|||
2. If the logs folder isn't present, create the folder. For instructions on how to enable MSBuild to create the logs folder in the deployment automatically, see the [Directory structure topic](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/directory-structure?view=aspnetcore-8.0). |
|||
3. Edit the `web.config` file. Set `stdoutLogEnabled` to `true` and change the `stdoutLogFile` path to point to the logs folder (for example, `.\logs\stdout`). stdout in the path is the log file name prefix. A timestamp, process id, and file extension are added automatically when the log is created. Using stdout as the file name prefix, a typical log file is named `stdout_20180205184032_5412.log`. |
|||
4. Ensure your application pool's identity has write permissions to the logs folder. |
|||
5. Save the updated `web.config` file. |
|||
6. Make a request to the app. |
|||
7. Navigate to the logs folder. Find and open the most recent stdout log. |
|||
|
|||
> The following sample aspNetCore element configures stdout logging at the relative path `.\log\.` Confirm that the AppPool user identity has permission to write to the path provided. |
|||
|
|||
```xml |
|||
<aspNetCore processPath="dotnet" |
|||
arguments=".\MyAbpApp.dll" |
|||
stdoutLogEnabled="true" |
|||
stdoutLogFile=".\logs\stdout" |
|||
hostingModel="inprocess"> |
|||
</aspNetCore> |
|||
``` |
|||
|
|||
Reference: |
|||
|
|||
[IIS log creation and redirection](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/logging-and-diagnostics) |
|||
|
|||
[Troubleshoot ASP.NET Core on Azure App Service and IIS](https://learn.microsoft.com/en-us/aspnet/core/test/troubleshoot-azure-iis) |
|||
|
|||
## What's next? |
|||
|
|||
- [Docker Deployment using Docker Compose](deployment-docker-compose.md) |
|||
|
|||
- [Azure Deployment using Application Service](deployment-azure-application-service.md) |
|||
@ -0,0 +1,111 @@ |
|||
# IdentityServer Deployment |
|||
|
|||
IdentityServer configuration may be different based on deployment configurations. Basically, you need update identityserver client related data and update your hosting preferences based on your deployment environment. |
|||
|
|||
## Update Cors Origins |
|||
|
|||
Cors origins configuration for **gateways**, **microservices** swagger authorization and **Angular/Blazor** (web assembly) must be updated for deployment. This can be found under **App** configuration in *appsettings.json* |
|||
|
|||
```json |
|||
"CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200,https://localhost:44307,https://localhost:44325,https://localhost:44353,https://localhost:44367,https://localhost:44388,https://localhost:44381,https://localhost:44361", |
|||
``` |
|||
|
|||
## Update Redirect Allowed Urls |
|||
|
|||
This configuration must be done if **Angular** or **Blazor** (web assembly) is used as back-office web application. It is found under **App** configuration in appsettings.json |
|||
|
|||
```json |
|||
"RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307" |
|||
``` |
|||
|
|||
## Update DbMigrator |
|||
|
|||
`IdentityServerDataSeedContributor` uses **IdentityServer.Clients** section of `appsettings.json` for `ClientId`, `RedirectUri`, `PostLogoutRedirectUri`, `CorsOrigins`. |
|||
|
|||
Update DbMigrator project `appsettings.json` **IdentityServer.Clients.RootUrls** with production values: |
|||
|
|||
 |
|||
|
|||
Or, manually add production values to `IdentityServerClientRedirectUris`, `IdentityServerClientPostLogoutRedirectUris`, `IdentityServerClientCorsOrigins` tables in your database. |
|||
|
|||
> If you are using microservice template on-the-fly migration and not using dbmigrator project, update **IdentityService** appsettings. |
|||
|
|||
Eventually, you shouldn't have `localhost` related data. |
|||
|
|||
## Update IdentityServer |
|||
|
|||
You need to update token signing certificate and identityserver midware based on your hosting environment. |
|||
|
|||
### Signing Certificate |
|||
|
|||
Default development environment uses [developer signing certificates option](https://github.com/abpframework/abp/blob/dev/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderOptions.cs#L29). Using developer signing certificates may cause *IDX10501: Signature validation failed* error on production. |
|||
|
|||
Update **IdentityServerModule** with using real certificate on `IIdentityServerBuilder` pre-configuration. |
|||
|
|||
 |
|||
|
|||
You can also [create self-signed certificate](https://docs.abp.io/en/commercial/5.0/startup-templates/microservice/tye-integration#create-developer-certificates) and use it. |
|||
|
|||
> If you are using self signed certificate, do not forget to set the certificate (.pfx file) as `EmbeddedResource` and set `CopyToOutputDirectory`. File needs to exist physically. |
|||
|
|||
### Use HTTPS |
|||
|
|||
Update **IdentityServerModule** to [enfcore https](https://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-6.0&tabs=visual-studio). Add `UseHsts` to add hsts headers to clients, add `UseHttpsRedirection` to redirect http requests to https. |
|||
|
|||
 |
|||
|
|||
### Behind Load Balancer |
|||
|
|||
To redirect http requests to https from load balancer, update `OnApplicationInitialization` method of the **IdentityServerModule** with the midware below: |
|||
|
|||
```csharp |
|||
app.Use((httpContext, next) => |
|||
{ |
|||
httpContext.Request.Scheme = "https"; |
|||
return next(); |
|||
}); |
|||
``` |
|||
|
|||
### Kubernetes |
|||
|
|||
A common scenario is running applications in kubernetes environment. While IdentityServer needs to face internet on https, internal requests can be done using http. |
|||
|
|||
 |
|||
|
|||
**HttpApi.Host** and **Web** applications authority should be set to http since token validations will done using http request. |
|||
|
|||
 |
|||
|
|||
> You can use different appsettings files like *appsettings.production.json* to override these values or directly override environment values from kubernetes. |
|||
|
|||
To isolate internal identityserver requests from external network (internet), append extra header instead of overwriting. |
|||
For ingress, you can use `nginx.ingress.kubernetes.io/configuration-snippet`: |
|||
|
|||
```yaml |
|||
apiVersion: networking.k8s.io/v1 |
|||
kind: Ingress |
|||
metadata: |
|||
name: myidentityserver-ingress |
|||
annotations: |
|||
nginx.ingress.kubernetes.io/rewrite-target: / |
|||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true" |
|||
nginx.ingress.kubernetes.io/proxy-buffer-size: "32k" |
|||
nginx.ingress.kubernetes.io/proxy-buffers-number: "8" |
|||
nginx.ingress.kubernetes.io/configuration-snippet: | |
|||
more_set_input_headers "from-ingress: true"; |
|||
spec: |
|||
``` |
|||
|
|||
You need to set the IdentityServer origin based on header. Update `OnApplicationInitialization` method of the **IdentityServerModule** with the midware below: |
|||
|
|||
```csharp |
|||
app.Use(async (ctx, next) => |
|||
{ |
|||
if (ctx.Request.Headers.ContainsKey("from-ingress")) |
|||
{ |
|||
ctx.SetIdentityServerOrigin("https://myidentityserver.com"); |
|||
} |
|||
|
|||
await next(); |
|||
}); |
|||
``` |
|||
@ -0,0 +1,20 @@ |
|||
# Deployment |
|||
|
|||
````json |
|||
//[doc-params] |
|||
{ |
|||
"UI": ["MVC", "Blazor", "BlazorServer", "NG"], |
|||
"DB": ["EF", "Mongo"], |
|||
"Tiered": ["Yes", "No"] |
|||
} |
|||
```` |
|||
|
|||
> This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider. For other options, please change the preference on top of this document. |
|||
|
|||
This guide explains how to deploy your application in staging and production environments based on your application architecture; |
|||
|
|||
- [Docker Deployment using Docker Compose](deployment-docker-compose.md) |
|||
|
|||
- [Azure Deployment using Application Service](azure-deployment/azure-deployment.md) |
|||
|
|||
- [IIS Deployment](deployment-iis.md) |
|||
@ -0,0 +1,127 @@ |
|||
# OpenIddict Deployment |
|||
|
|||
[OpenIddict](https://github.com/openiddict/openiddict-core) is the default OpenId Provider library used by ABP templates through the [OpenIddict Module](https://docs.abp.io/en/abp/latest/Modules/OpenIddict). It is hosted by the **AuthServer** project in the tiered/seperate-authserver application templates. For non-tiered applications, it is hosted by the Web (MVC/Razor), BlazorServer or the **HttpApi.Host** project for Blazor and Angular applications. |
|||
|
|||
## Update Cors Origins |
|||
|
|||
Cors origins configuration for ***gateways***, ***microservices*** swagger authorization, and ***Angular/Blazor*** (web assembly) must be updated for deployment. This can be found under the ***App*** configuration in **appsettings.json** |
|||
|
|||
```json |
|||
"CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200,https://localhost:44307,https://localhost:44325,https://localhost:44353,https://localhost:44367,https://localhost:44388,https://localhost:44381,https://localhost:44361", |
|||
``` |
|||
## Update Redirect Allowed URLs |
|||
|
|||
If **Angular** or **Blazor** (Web Assembly) is used as a back-office web application, this configuration must be done. It is found under **App** configuration in `appsettings.json`. |
|||
|
|||
```json |
|||
"RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307" |
|||
``` |
|||
## Update DbMigrator |
|||
|
|||
`OpenIddictDataSeedContributor` uses **OpenIddict.Applications** section of `appsettings.json` for `ClientId`, `RedirectUri`, `PostLogoutRedirectUri` and `CorsOrigins`. |
|||
|
|||
Update DbMigrator project `appsettings.json` **OpenIddict.Applications.RootUrls** with production values or override them: |
|||
|
|||
 |
|||
|
|||
|
|||
> If you are using microservice template self-migration and not using DbMigrator project, update **IdentityService** appsettings. |
|||
|
|||
Eventually, you shouldn't have any `localhost` related data. |
|||
|
|||
## Update AuthServer |
|||
|
|||
In the development environment, OpenIddict uses a development encryption and signing certificate. In the production environment, this must be disabled. OpenIddict needs a real certificate for signing and encrypting the tokens. |
|||
|
|||
### Signing and Encryption Certificate |
|||
|
|||
The default development environment uses [developer signing certificates option](https://github.com/abpframework/abp/blob/bda231b319b62582dee4f8389494cd4442ac474f/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs#L104-L105). Using developer signing certificates may cause *IDX10501: Signature validation failed* error on production. |
|||
|
|||
Update **AuthServerModule** by using a real certificate on `OpenIddictBuilder` pre-configuration. |
|||
|
|||
 |
|||
|
|||
When you create a new application from the application template, ABP CLI automatically generates a new self-signed certificate with the name `openiddict.pfx` and a random password. This file and the password are provided in the `GetSigningCertificate` method. |
|||
|
|||
> Note: If you are receiving errors about not being able to reach the `openiddict.pfx` file on the server, make sure you have the necessary permissions. |
|||
|
|||
The best place to store your certificates will depend on your host: |
|||
|
|||
- For IIS applications, [storing the certificates in the machine store](https://www.sonicwall.com/support/knowledge-base/how-can-i-import-certificates-into-the-ms-windows-local-machine-certificate-store/170504615105398/) is the recommended option. |
|||
- On Azure, certificates can be uploaded and exposed to Azure App Service applications using the special `WEBSITE_LOAD_CERTIFICATES` flag. For more information, visit the [Use a TLS/SSL certificate in your code in Azure App Service](https://docs.microsoft.com/en-us/azure/app-service/configure-ssl-certificate-in-code) document. |
|||
|
|||
Please check [OpenIddict documentation](https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html#registering-a-certificate-recommended-for-production-ready-scenarios) for more information and using different types of signing/encryption keys. |
|||
|
|||
### Using or Disabling the HTTPS |
|||
|
|||
AuthServer that hosts the OpenIddict openid-provider library uses the SSL/TLS binding of the ASP.NET Core middleware. If you host it on `HTTPS`, the **Issuer** will be hosted on `HTTPS`. |
|||
|
|||
In some deployment scenarios, you may come across an error: |
|||
|
|||
```json |
|||
error: invalid_request |
|||
error_description: This server only accepts HTTPS requests. |
|||
error_uri: https//documnentation.openiddict.com/errors/ID2083 |
|||
``` |
|||
|
|||
You can easily disable the HTTPS requirement from the **appsettings.json**: |
|||
```json |
|||
"AuthServer": { |
|||
"Authority": "https://localhost:44369", |
|||
"RequireHttpsMetadata": "false" |
|||
}, |
|||
``` |
|||
|
|||
This configuration can be found under the `ConfigureServices` method of the AuthServer project: |
|||
```csharp |
|||
if (!Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"])) |
|||
{ |
|||
Configure<OpenIddictServerAspNetCoreOptions>(options => |
|||
{ |
|||
options.DisableTransportSecurityRequirement = true; |
|||
}); |
|||
} |
|||
``` |
|||
|
|||
### Behind Load Balancer |
|||
|
|||
You may need to forward the headers if you are using [Nginx](https://www.nginx.com/) or [Kubernetes Nginx Ingress](https://github.com/kubernetes/ingress-nginx). |
|||
Configure the options in the **ConfigureServices** method of `AuthServerModule`: |
|||
|
|||
```csharp |
|||
Configure<ForwardedHeadersOptions>(options => |
|||
{ |
|||
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; |
|||
}); |
|||
``` |
|||
And use the middleware in the **OnApplicationInitialization** method of `AuthServerModule`: |
|||
```csharp |
|||
if (env.IsDevelopment()) |
|||
{ |
|||
app.UseDeveloperExceptionPage(); |
|||
} |
|||
|
|||
app.UseForwardedHeaders(); |
|||
... |
|||
``` |
|||
|
|||
Sometimes, including forwarded headers in requests proxied to the application may be impossible. |
|||
If the proxy enforces that all public external requests are HTTPS, the scheme can be manually set before using any middleware. |
|||
Configure it under the **OnApplicationInitialization** method of `AuthServerModule`: |
|||
|
|||
```csharp |
|||
app.Use((httpContext, next) => |
|||
{ |
|||
httpContext.Request.Scheme = "https"; |
|||
return next(); |
|||
}); |
|||
``` |
|||
|
|||
# FAQ |
|||
|
|||
- I see `Server Error 502!` |
|||
- Check your application logs under the *Logs* folder. A misconfiguration can prevent your application from starting up, and the easiest way is to pinpoint the problem by checking the logs. |
|||
- `System.IO.FileNotFoundException: Signing Certificate couldn't found!:` |
|||
- Ensure you have the **.pfx** file in the related location. The **.pfx** file should be marked as an embedded resource, and it should be in the publish directory when you publish your application. |
|||
- I can't see the login page! It shows an `HTTP 400` error. |
|||
- This is related to the generated URL from the application that tries to authenticate against the AuthServer. Check the AuthServer logs and make sure you have **valid redirect_uri** seeded from the *OpenIddictDataSeedContributor* and the application that redirects to AuthServer has the same configuration. |
|||
|
After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 71 KiB |