@ -0,0 +1,94 @@ |
|||
name: 🤠 ABP Studio |
|||
description: Create a report to help us improve the ABP Studio |
|||
labels: [studio] |
|||
body: |
|||
- type: markdown |
|||
attributes: |
|||
value: | |
|||
We welcome bug reports! This template will help us gather the information we need to start the triage process. |
|||
|
|||
Please keep in mind that the GitHub issue tracker is not intended as a general support forum, but for reporting **non-security** bugs and feature requests. |
|||
If you believe you have an issue that affects the SECURITY of the platform, please do NOT create an issue and instead email your issue details to info@abp.io. |
|||
For other types of questions, consider using [StackOverflow](https://stackoverflow.com/questions/tagged/abp). |
|||
- type: checkboxes |
|||
id: searched |
|||
attributes: |
|||
label: Is there an existing issue for this? |
|||
description: Please search to see if an issue already exists for the bug you encountered or feature request ([abp/issues](https://github.com/abpframework/abp/issues?q=is%3Aopen+is%3Aissue+label%3Astudio)). |
|||
options: |
|||
- label: I have searched the existing issues |
|||
required: true |
|||
- type: textarea |
|||
id: background |
|||
attributes: |
|||
label: Description |
|||
description: Please share a clear and concise description of the problem. |
|||
placeholder: Description |
|||
validations: |
|||
required: true |
|||
- type: markdown |
|||
attributes: |
|||
value: | |
|||
## Setup |
|||
Please provide more information on your ABP Studio setup. |
|||
- type: input |
|||
id: version |
|||
attributes: |
|||
label: Version |
|||
description: Which version of ABP Studio are you using? |
|||
placeholder: Version |
|||
validations: |
|||
required: true |
|||
- type: dropdown |
|||
id: Operation-System |
|||
attributes: |
|||
label: Operation System |
|||
description: What is the operation system of the computer? |
|||
options: |
|||
- Windows (Default) |
|||
- Linux |
|||
- macOS |
|||
- Others |
|||
validations: |
|||
required: true |
|||
- type: textarea |
|||
id: solution-config |
|||
attributes: |
|||
label: Solution Configuration |
|||
description: | |
|||
If there is an open solution, what are the configurations of the solution? |
|||
🧐 Hint: You can see all the information about your solution from the configuration window, which opens when you right-click on the [solution](https://abp.io/docs/latest/studio/solution-explorer#solution) and click on the `Solution Configuration` button. |
|||
placeholder: | |
|||
- **Template**: app |
|||
- **Created ABP Studio Version**: 0.7.9 |
|||
- **Tiered**: No |
|||
- **UI Framework**: mvc |
|||
- **Theme**: leptonx |
|||
- **Theme Style**: system |
|||
- **Database Provider**: ef |
|||
- **Database Management System**: sqlserver |
|||
- **Separate Tenant Schema**: No |
|||
- **Mobile Framework**: none |
|||
- **Public Website**: No |
|||
- **Optional Modules**: |
|||
* GDPR |
|||
* TextTemplateManagement |
|||
* LanguageManagement |
|||
* AuditLogging |
|||
* SaaS |
|||
* OpenIddictAdmin |
|||
validations: |
|||
required: false |
|||
- type: markdown |
|||
attributes: |
|||
value: | |
|||
--- |
|||
- type: textarea |
|||
id: other-info |
|||
attributes: |
|||
label: Other information |
|||
description: | |
|||
If you have an idea where the problem might lie, let us know that here. Please include any pointers to code, relevant changes, or related issues you know of. |
|||
placeholder: Other information |
|||
validations: |
|||
required: false |
|||
@ -1,8 +1,8 @@ |
|||
blank_issues_enabled: true |
|||
contact_links: |
|||
- name: Issue with ABP Commercial |
|||
url: https://support.abp.io/QA/Questions |
|||
about: Please open ABP Commercial related issues at https://support.abp.io. |
|||
url: https://abp.io/support/questions |
|||
about: Please open ABP Commercial related issues at https://abp.io/support/questions. |
|||
- name: Ask a question (community support) |
|||
url: https://stackoverflow.com/questions/tagged/abp |
|||
about: Ask a question that will be answered by the ABP community |
|||
|
|||
@ -1,8 +1,9 @@ |
|||
{ |
|||
"culture": "en", |
|||
"texts": { |
|||
"AbpTitle": "Read All Blog Posts", |
|||
"AbpTitle": "New Blog Post | ABP.IO", |
|||
"AbpDescription": "ABP is an open source application framework focused on AspNet Core based web application development. Don't repeat yourself, focus on your own business code.", |
|||
"AbpDefinition": "ABP blog for .NET development, cross-platform, ASP.NET application templates, ABP-related news and more..." |
|||
"AbpDefinition": "Create a new blog post and share your knowledge and experience with ABP.", |
|||
"Blogs": "Blog Posts" |
|||
} |
|||
} |
|||
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 268 KiB After Width: | Height: | Size: 261 KiB |
@ -0,0 +1,77 @@ |
|||
# ABP.IO Platform 8.3 Final Has Been Released! |
|||
|
|||
 |
|||
|
|||
[ABP](https://abp.io/) 8.3 stable version has been released today. |
|||
|
|||
## What's New With Version 8.3? |
|||
|
|||
All the new features were explained in detail in the [8.3 RC Announcement Post](https://blog.abp.io/abp/announcing-abp-8-3-release-candidate), so there is no need to review them again. You can check it out for more details. |
|||
|
|||
## Getting Started with 8.3 |
|||
|
|||
### Creating New Solutions |
|||
|
|||
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) to create new solutions. |
|||
|
|||
By default, ABP Studio uses stable versions to create solutions. Therefore, it will be creating the solution with the latest stable version, which is v8.3 for now, so you don't need to specify the version. |
|||
|
|||
### How to Upgrade an Existing Solution |
|||
|
|||
You can upgrade your existing solutions with either ABP Studio or ABP CLI. In the following sections, both approaches are explained: |
|||
|
|||
### Upgrading via ABP Studio |
|||
|
|||
If you are already using the ABP Studio, you can upgrade it to the latest version to align it with ABP v8.3. ABP Studio periodically checks for updates in the background, and when a new version of ABP Studio is available, you will be notified through a modal. Then, you can update it by confirming the opened modal. See [the documentation](https://abp.io/docs/latest/studio/installation#upgrading) for more info. |
|||
|
|||
After upgrading the ABP Studio, then you can open your solution in the application, and simply click the **Switch to stable** action button to instantly upgrade your solution: |
|||
|
|||
 |
|||
|
|||
### Upgrading via ABP CLI |
|||
|
|||
Alternatively, you can upgrade your existing solution via ABP CLI. First, you need to install the ABP CLI or upgrade it to the latest version. |
|||
|
|||
If you haven't installed it yet, you can run the following command: |
|||
|
|||
```bash |
|||
dotnet tool install -g Volo.Abp.Studio.Cli |
|||
``` |
|||
|
|||
Or to update the existing CLI, you can run the following command: |
|||
|
|||
```bash |
|||
dotnet tool update -g Volo.Abp.Studio.Cli |
|||
``` |
|||
|
|||
After installing/updating the ABP CLI, you can use the [`update` command](https://abp.io/docs/latest/CLI#update) to update all the ABP related NuGet and NPM packages in your solution as follows: |
|||
|
|||
```bash |
|||
abp update |
|||
``` |
|||
|
|||
> You can run this command in the root folder of your solution. |
|||
|
|||
## Migration Guides |
|||
|
|||
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.2 or earlier: [ABP Version 8.3 Migration Guide](https://abp.io/docs/8.3/release-info/migration-guides/abp-8-3) |
|||
|
|||
## Community News |
|||
|
|||
### New ABP Community Posts |
|||
|
|||
As always, exciting articles have been contributed by the ABP community. I will highlight some of them here: |
|||
|
|||
* [Alper Ebicoglu](https://twitter.com/alperebicoglu) has created **three** new community articles: |
|||
* [Do You Really Need Multi-tenancy?](https://abp.io/community/articles/do-you-really-need-multitenancy-hpwn44r3) |
|||
* [What is Angular Schematics?](https://abp.io/community/articles/what-is-angular-schematics-2z4jusf5) |
|||
* [Understanding Angular AOT vs JIT Compilations](https://abp.io/community/articles/understanding-angular-aot-vs-jit-compilations-0r0a0a3f) |
|||
* [Dynamic Widget Communication](https://abp.io/community/articles/dynamic-widget-communication-uvun7q23) by [Suhaib Mousa](https://suhaibmousa.com/) |
|||
* [Introducing the Google Cloud Storage BLOB Provider](https://abp.io/community/articles/introducing-the-google-cloud-storage-blob-provider-yrt6azc0) by [Engincan Veske](https://twitter.com/EngincanVeske) |
|||
* [Switching Between Organization Units](https://abp.io/community/articles/switching-between-organization-units-i5tokpzt) by [Liming Ma](https://github.com/maliming) |
|||
|
|||
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. |
|||
|
|||
## About the Next Version |
|||
|
|||
The next feature version will be 9.0. You can follow the [release planning here](https://github.com/abpframework/abp/milestones). Please [submit an issue](https://github.com/abpframework/abp/issues/new) if you have any problems with this version. |
|||
|
After Width: | Height: | Size: 6.9 MiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 145 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 422 KiB |
|
After Width: | Height: | Size: 728 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 263 KiB |
|
After Width: | Height: | Size: 538 KiB |
|
After Width: | Height: | Size: 44 KiB |
@ -0,0 +1,87 @@ |
|||
# DotNext 2024 Conference: A Speaker’s Impressions |
|||
|
|||
 |
|||
|
|||
Last week, I had the chance of being a speaker at **DotNext 2024** in Moscow. [JUG Ru Group](https://jugru.org/en/) is arranging the DotNext Conferences since [2014](https://dotnext.ru/archive/). It's a specific conference for .NET developers held at the [MonArch Moscow Hotel](https://www.moscowmonarch.com/) on 10, 11 September 2024. This event brought together over **600 developers on-site, 200 developers online**, with around **35 speakers** delivering more than **30 talks**, making it one of the largest gatherings of the .NET community in Russia. |
|||
|
|||
 |
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## Key Highlights & Popular Sessions |
|||
|
|||
One of the standout aspects of the conference was its strong technical focus, particularly on deep-dive .NET topics. Talks covered subjects like **low-level optimizations**, architecture, performance, and platform internals. |
|||
|
|||
The conference started with Sergei Benzenko's talk "What's New in .NET 9". There are important topics like ".NET Aspire in Action", "AI-Driven Software Development", "DDD and Strategic Design" and "OAuth 2.0 User-Managed Access in ASP.NET Core with Keycloak". |
|||
|
|||
 |
|||
|
|||
There were two international speakers: me and Halil Ibrahim Kalkan from ABP Core Team. Halil's topic was **Implementing Domain-Driven Design as a Pragmatic Developer**. In his session, he gave practical real world examples of bad and best practices of DDD development. |
|||
|
|||
 |
|||
|
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## My Talk |
|||
|
|||
My presentation topic was **Building Multi-Tenant ASP.NET Core Applications** was part of this technical deep dive, and I was thrilled to see so much interest in scalable multi-tenant solutions. I generally talked about meta data in SaaS development and explained how to identify the active tenant, how to isolate the data in the same database, how to set `TenantId` automatically for new entities, how to select DB connection for the active tenant, how to change the active tenant when needed, how to disable multi-tenancy temporarily, how to handle database migrations and lastly feature system. These features are major multi-tenancy features, and you'll learn how they are implemented in an open-source web app framework. |
|||
|
|||
 |
|||
|
|||
 |
|||
|
|||
- My presentation 🌐https://github.com/ebicoglu/presentations/tree/main. |
|||
|
|||
- My conf profile🌐 https://dotnext.ru/en/persons/cbe6e4b2cc214a47bfc3752cdb0b1f88/ |
|||
|
|||
|
|||
 |
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## Venue and Atmosphere |
|||
|
|||
The MonArch Moscow Hotel provided a great venue, combining spacious halls for sessions with cozy areas for networking. There were also afterparty events, which added a fun, informal touch to the otherwise highly technical environment. The setup allowed plenty of opportunities for spontaneous discussions with attendees and experts, both during and after the sessions. |
|||
|
|||
 |
|||
|
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## Boat Tour on Moscow River |
|||
|
|||
After the conference ended, the organizing team took all the speakers on a boat tour on the Moscow River. It was a great open buffet dinner in a nice boat. We had a chance to chat with other speakers. |
|||
|
|||
 |
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## Networking and Community |
|||
|
|||
DotNext 2024 provided an excellent platform for connecting with fellow developers and industry leaders. In addition to presentations, there were plenty of opportunities to interact with other participants, including representatives from Microsoft, Volosoft, and local Russian tech giants like Ozon and beeline. The exhibition hall was filled with partner stands, including those from PVS-Studio, Kontur, Eremex and OzonTech which offered interactive displays and demos. |
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## Conclusion |
|||
|
|||
Overall, DotNext 2024 lived up to its reputation as a key event for .NET developers. From highly technical talks to networking opportunities, it was a fantastic experience, and I came away with new insights into both the technical and community aspects of the .NET ecosystem. If you’re a .NET developer looking to stay ahead in your field, DotNext is definitely a conference worth attending! |
|||
|
|||
Looking forward to come again! |
|||
|
|||
|
|||
Lastly, I took some beautiful photos of Moscow, here are a few... |
|||
|
|||
 |
|||
|
After Width: | Height: | Size: 274 KiB |
@ -0,0 +1,64 @@ |
|||
|
|||
|
|||
 |
|||
|
|||
Ahead-of-Time (AOT) compilation and Just-in-Time (JIT) compilation are two different methods for compiling Angular applications. Here's a breakdown of the differences between them: |
|||
|
|||
### **Ahead-of-Time (AOT) Compilation** |
|||
|
|||
**What is AOT?** |
|||
|
|||
- AOT compilation refers to the process of compiling your Angular application during the build phase, before the application is served to the browser. |
|||
- The Angular compiler converts your TypeScript and HTML templates into efficient JavaScript code ahead of time. |
|||
|
|||
**Advantages:** |
|||
|
|||
1. **Faster Rendering:** Since the compilation is done beforehand, the browser receives precompiled code, leading to faster rendering and better performance when the app loads. |
|||
2. **Smaller Bundle Size:** AOT eliminates the need for the Angular compiler in the client-side bundle, which reduces the overall bundle size. |
|||
3. **Improved Security:** AOT compilation checks your templates and bindings during the build process, catching errors early and reducing the risk of injection attacks. |
|||
4. **Early Error Detection:** Errors related to templates and bindings are caught during the build time rather than at runtime, leading to more robust and error-free applications. |
|||
|
|||
**When to Use:** |
|||
|
|||
- AOT is typically used in production builds because it provides better performance, smaller bundles, and more secure applications. |
|||
|
|||
**How to Use:** |
|||
|
|||
- AOT is the default when you run `ng build --prod` in an Angular project. |
|||
|
|||
### **Just-in-Time (JIT) Compilation** |
|||
|
|||
**What is JIT?** |
|||
|
|||
- JIT compilation occurs in the browser at runtime. The Angular compiler translates the TypeScript and HTML templates into JavaScript code just before the application runs in the browser. |
|||
- The application is compiled on the fly as the user interacts with it. |
|||
|
|||
**Advantages:** |
|||
|
|||
1. **Faster Build Time:** Since there’s no pre-compilation step, the build process is faster during development. |
|||
2. **More Flexible Development:** JIT allows for rapid iteration during development, as changes can be quickly reflected without needing to rebuild the entire application. |
|||
3. **Dynamic Components:** JIT allows for more flexibility in scenarios where components need to be dynamically created or compiled at runtime. |
|||
|
|||
**When to Use:** |
|||
|
|||
- JIT is typically used in development environments because it allows for quicker build times and easier debugging. |
|||
|
|||
**How to Use:** |
|||
|
|||
- JIT is the default compilation method when you run `ng serve` for development builds in Angular. |
|||
|
|||
### **Comparison Summary:** |
|||
|
|||
| Feature | AOT (Ahead-of-Time) | JIT (Just-in-Time) | |
|||
| ---------------------- | ----------------------------- | ---------------------------------- | |
|||
| **Compilation Timing** | At build time | At runtime | |
|||
| **Performance** | Faster application startup | Slower application startup | |
|||
| **Bundle Size** | Smaller (no Angular compiler) | Larger (includes Angular compiler) | |
|||
| **Error Detection** | Catches template errors early | Errors caught at runtime | |
|||
| **Use Case** | Production | Development | |
|||
| **Dynamic Components** | Less flexible | More flexible | |
|||
|
|||
### **Best Practices:** |
|||
|
|||
- **Use AOT** for production builds to ensure faster load times, smaller bundle sizes, and more secure applications. |
|||
- **Use JIT** during development to take advantage of quicker builds and easier debugging. |
|||
|
After Width: | Height: | Size: 399 KiB |
@ -0,0 +1,85 @@ |
|||
# What is Angular Schematics? |
|||
|
|||
 |
|||
|
|||
**Angular Schematics** is a powerful tool which is part of the Angular CLI that allows developers to automate various development tasks by **generating and modifying code**. Schematics provides a way to create **templates and boilerplate code** for Angular applications or libraries, enabling consistency and reducing the amount of repetitive work. |
|||
|
|||
### Key Concepts of Angular Schematics: |
|||
|
|||
1. **Code Generation:** |
|||
- Schematics can generate boilerplate code for various Angular artifacts, such as components, services, modules, pipes... For example, when you run a command like `ng generate component my-component`, Angular uses a schematic to create the component files and update the necessary modules. |
|||
|
|||
2. **Code Modification:** |
|||
- Schematics can also modify existing code in your project. This includes tasks like updating configuration files, adding new routes, or modifying Angular modules. They can be very useful when upgrading projects to a new version of Angular or adding new features that require changes to the existing codebase. |
|||
|
|||
3. **Custom Schematics:** |
|||
- Developers can create their own custom schematics to automate repetitive tasks specific to their projects. For example, if your team frequently needs to set up a certain type of service or configure specific libraries, you can create a schematic that automates these steps. In [ABP Suite](https://abp.io/suite), we use the custom schematics templates to generate CRUD pages for Angular UI. |
|||
|
|||
4. **Collection of Schematics:** |
|||
- Schematics are often grouped into collections. The Angular CLI itself is a collection of schematics. You can create your own collection or use third-party schematic collections created by the Angular community. |
|||
|
|||
5. **Integration with Angular CLI:** |
|||
- Schematics is integrated with the Angular CLI. The `ng generate` and `ng add` commands are examples of how schematics are used in everyday Angular development. When you use these commands, the Angular CLI runs the corresponding schematic to perform the desired operation. |
|||
|
|||
6. **Upgrade Tasks:** |
|||
- Schematics can be used to automate the process of upgrading Angular applications. For example, the Angular Update command (`ng update`) uses schematics to automatically apply necessary changes to your project when upgrading to a new version of Angular. |
|||
|
|||
### Common Use Cases: |
|||
|
|||
- **Generating Components, Services, Modules.:** Easily create Angular building blocks with commands like `ng generate component`, `ng generate service`, or `ng generate module`. |
|||
|
|||
- **Adding Libraries:** Automatically set up and configure third-party libraries with `ng add`. For example, `ng add @angular/material` uses a schematic to install and configure Angular Material in your project. |
|||
|
|||
- **Automating Project Upgrades:** Simplify the process of upgrading Angular versions by running `ng update`, which uses schematics to make necessary code changes. |
|||
|
|||
- **Custom Project Scaffolding:** Create custom schematics to enforce your team's development standards and best practices by automating the creation of specific project structures. |
|||
|
|||
### How to Create a Custom Schematic: |
|||
|
|||
Creating a custom schematic involves several steps: |
|||
1. **Install the Schematics CLI:** |
|||
```bash |
|||
npm install -g @angular-devkit/schematics-cli |
|||
``` |
|||
|
|||
2. **Create a New Schematic Project:** |
|||
```bash |
|||
schematics blank --name=my-schematic |
|||
cd my-schematic |
|||
``` |
|||
|
|||
3. **Define Your Schematic:** Modify the files in the schematic project to define what your schematic will generate or modify. |
|||
|
|||
4. **Test Your Schematic:** You can run your schematic locally using the `schematics` command. |
|||
|
|||
5. **Publish Your Schematic (Optional):** Once your schematic is ready, you can publish it to npm or include it in your Angular projects. |
|||
|
|||
#### Example: |
|||
If you want to create a custom component with specific settings or styles, you can create a schematic to automate this. Every time a developer on your team needs to create this type of component, they can run the schematic, ensuring consistency across the project. |
|||
|
|||
|
|||
|
|||
### Helpful Links |
|||
|
|||
Here are the direct links for the Angular Schematics resources: |
|||
|
|||
- [Angular Official Documentation: Schematics Overview — angular.io](https://angular.io/guide/schematics) |
|||
|
|||
- [Creating Custom Schematics — angular.io](https://angular.io/guide/schematics-for-libraries) |
|||
|
|||
- [CLI Schematic Command — angular.io](https://angular.io/cli/schematic) |
|||
|
|||
- [Devkit Schematics— github.com](https://github.com/angular/angular-cli/tree/main/packages/angular_devkit/schematics) |
|||
|
|||
- [Schematics Examples — github.com](https://github.com/angular/angular-cli/tree/main/packages/schematics/angular) |
|||
|
|||
- [Debugging Angular Schematics — dev.to](https://dev.to/nikolasleblanc/debugging-angular-schematics-1ne0) |
|||
|
|||
- [Using Schematics with Nx — nx.dev](https://nx.dev/guides/using-angular-schematics) |
|||
|
|||
- [Schematics API — angular.io](https://angular.io/api/schematics) |
|||
|
|||
|
|||
|
|||
### Conclusion: |
|||
Angular Schematics is a powerful tool for automating repetitive tasks, generating consistent code, and managing project upgrades. By leveraging schematics, Angular developers can save time, reduce errors, and enforce best practices across their projects. |
|||
|
After Width: | Height: | Size: 35 KiB |
@ -0,0 +1,123 @@ |
|||
# Do You Really Need Multi-tenancy? |
|||
|
|||
This article discusses whether you need a multi-tenancy architecture for your next project. Answer my critical questions to decide if multi-tenancy suits your application or not! |
|||
|
|||
 |
|||
|
|||
## What’s Multi-tenancy? |
|||
|
|||
It’s an architectural approach to building SaaS solutions. In this model, the hardware and software resources are shared between tenants, and application data is virtually or physically isolated between tenants. Here, **the main goal is minimizing costs and maximizing customer count**. |
|||
|
|||
**An ideal multi-tenant application should be;** |
|||
|
|||
- A multi-tenancy system should be designed to **work seamlessly** and make your application code **multi-tenancy aware** as much as possible. |
|||
- When a customer wants to separate their database, it **should also be deployable to on-premise**. |
|||
|
|||
|
|||
 |
|||
|
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## Multi-tenant Development is Hard - Reconsider! |
|||
|
|||
**Developing a multi-tenant application is harder** compared to non-multi-tenant applications. You add `TenandId` to all your shared entities. And each time you make a query, you need to filter by `TenantId`. There is an increased risk of security breaches if one tenant's data is compromised. Multi-tenancy can limit the extent of customization available to each tenant since they all operate on the same core infrastructure. Also, in a microservice environment, things get two times more complicated. So you should carefully consider if you need multi-tenancy or not. Sometimes, I got questions like; |
|||
|
|||
 |
|||
|
|||
**No! These are not multi-tenant applications.** It just needs a simple filtering by your different branches/faculties/departments/holding sub-companies/ groups or whatever hierarchy is… |
|||
**You are confusing "grouping" with "resource sharing".** |
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## Do I Really Need Multi-tenancy? |
|||
|
|||
Ask yourself the following questions if you cannot decide whether your app needs multi-tenancy or not; |
|||
|
|||
1. Can a user be shared among other tenants? |
|||
2. Any tenant needs to see other tenant's data? |
|||
3. Does your application break when you physically move one of the tenants? |
|||
4. Do your customers need higher security and better GDPR enforcement? |
|||
5. Do you need cumulative queries over your tenants? |
|||
|
|||
|
|||
|
|||
Let's answer these questions; |
|||
|
|||
|
|||
|
|||
##### **1. Can a user be shared among other tenants?** |
|||
|
|||
If you need to *share a user among other tenants, or in other words, users can be members of different tenants,* then **your application is definitely not multi-tenant**! Multi-tenancy means a tenant’s data is always isolated, even if it’s logically separated. **You cannot share a user among your tenants.** The reason is simple: In the future, if you move a tenant to on-premise, then your application will break! |
|||
|
|||
 |
|||
|
|||
##### **2. Does any tenant need to see other tenants' data?** |
|||
|
|||
If your answer is **YES**, **then** **your application is not multi-tenant**. In multi-tenant apps, the tenant's data cannot be shared in any circumstances among the other tenants. Business decision-makers sometimes want to share some entities with other tenants. If there's this requirement, you shouldn't start a multi-tenant architecture. You can simply group these tenants manually. Again, reply to this question; **In the future, if I move a tenant physically to another environment, will my app still work properly?** In this case, it will not! |
|||
|
|||
 |
|||
|
|||
Let's say your app is *Amazon.com* and you have a product entity *iPhone* that you want to share with other sellers. This requirement violates the multi-tenant rule. While your *Amazon.com* is still SaaS, it shouldn't be multi-tenant. |
|||
|
|||
On the other hand, if you serve several online shopping websites dedicated to different brands. Let's say Nike and Adidas want to have their own e-commerce websites. And your ***Amazon.com* provides these companies with their own subdomains: *nike.amazon.com* and *adidas.amazon.com***. In this architecture, these companies will have their own user, roles, settings. Also these companies will have their own branding like custom login screen, custom logo, different theme layouts, menu items, language options, payment gateways etc... Hence, **this is %100 multi-tenant.** |
|||
|
|||
|
|||
|
|||
##### **3. Does your application break when you physically move one of the tenants?** |
|||
|
|||
If your answer is **YES**, you should **stop making it multi-tenant**. It is **not a multi-tenant app**! This means your tenants are tightly coupled with the application's infrastructure or database, and this requirement prevents you from making it multi-tenant because it disrupts the entire system when you take out a tenant. |
|||
|
|||
 |
|||
|
|||
|
|||
##### **4. Do your customers need higher security and better GDPR enforcement?** |
|||
|
|||
If your answer is **YES**, you **should not make it multi-tenancy.** When a **hacker** gets into your server, he can **steal all your client data**. Also, if you have a security hole, **a tenant can gain access** to other tenants' data. Especially your tenants' data is being shared in the same database... On the other hand, some customers, for example, government agencies or banks, may be required to locate the database in their own geo-location and make it unreachable from the main application. In this case, you should go with a single-tenant architecture. Another difficulty is that some tenants may have **different data retention policies**, so you must implement different strategies for each tenant. In this case, you should also consider making it a single-tenant. |
|||
|
|||
 |
|||
|
|||
##### **5. Do you need cumulative queries over your tenants?** |
|||
|
|||
This question is not a clear decision parameter for multi-tenancy. But it can be a supportive parameter for your decision. Actually, this is a common feature in multi-tenant systems where aggregated reporting or analytics across tenants is required. In a virtually isolated multi-tenant environment, you can easily do this by just disabling the multi-tenancy filter. However, when some of your tenants have separate databases or application instances, it becomes harder to get aggregate reports. |
|||
|
|||
Do you need cumulative queries over your tenants? If your answer is YES, then you should keep all your tenants' data in a shared database to easily query them. But if you still need to physically move some of the tenants, then you have the following strategies: |
|||
|
|||
* First, all your databases need to be on the same network so that you can gather data from different databases. |
|||
* Second, in some cases, according to the GDPR requirements or government agency regulations, you must locate the database in their geo-location. And you cannot connect to these databases. In this case, you can create a Web API in your application that gives you a report for this specific tenant. Later, you'll gather the reports from all your tenants like this and merge them. |
|||
* Third; When the tenant databases are in different geo-location (inaccessible), then each tenant can send their report to your central server. So you can generate cumulative reports. |
|||
|
|||
|
|||
|
|||
## Conclusion |
|||
|
|||
- It's important to decide on the first day whether your application needs to be multi-tenant. To decide this, consider these topics; |
|||
|
|||
- **Do my tenants really have a relationship with each other?** No, they have nothing to do in common; **OK, go with multi-tenancy**. |
|||
- **My tenants don't have a relationship** with each other, and the only thing they have in common is sharing my application. **OK, go with multi-tenancy**. |
|||
- **When a tenant leaves the system (by removing their data), the other tenants also stop working** This means that the tenants are coupled. **Do not do multi-tenancy!** |
|||
|
|||
|
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
 |
|||
|
|||
We’ve been working for a long time on multi-tenancy, microservices, modular development topics, and developing tools and frameworks for repetitive development tasks. Check out the amazing open-source [ABP Framework](https://github.com/abpframework/abp), which provides all the alternative solutions to implement a multi-tenant architecture. The multi-tenancy logic is seamlessly done at the core level, and you can simply focus on your business code. Keep it simple, nice and neat with ABP. |
|||
|
|||
|
|||
```bash |
|||
ABP.IO: The Modern Way of Developing Web Apps for .NET Developers! |
|||
``` |
|||
|
|||
|
|||
|
|||
Alper Ebicoglu / [x.com/alperebicoglu](https://x.com/alperebicoglu) |
|||
|
|||
— ABP Team |
|||
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 989 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 544 KiB |
@ -0,0 +1,149 @@ |
|||
# ASP.NET Core Blazor 9.0 New Features Summary 🆕 |
|||
|
|||
In this article, I'll highlight .NET 9's Blazor updates and important features for ASP.NET Core 9.0. These features are based on the latest .NET 9 Preview 7. |
|||
|
|||
 |
|||
|
|||
## .NET MAUI Blazor Hybrid App and Web App solution template |
|||
|
|||
There's a new solution template to create .**NET MAUI native** and **Blazor web client** apps. This new template allows to choose a Blazor interactive render mode, it uses a shared Razor class library to maintain the UI's Razor components. |
|||
|
|||
For more info: |
|||
|
|||
* [learn.microsoft.com > maui blazor web app tutorial](https://learn.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/maui-blazor-web-app?view=aspnetcore-9.0) |
|||
* [reddit.com/r/Blazor/comments/1dabyzk/net_8_blazor_hybrid_maui_app_web_hosting/](https://www.reddit.com/r/Blazor/comments/1dabyzk/net_8_blazor_hybrid_maui_app_web_hosting/) |
|||
|
|||
|
|||
|
|||
## A new middleware: `MapStaticAssets` |
|||
|
|||
This new middleware optimizes the delivery of static assets in any ASP.NET Core app, also for Blazor. Basically it compresses assets via [Gzip](https://datatracker.ietf.org/doc/html/rfc1952), [fingerprints](https://developer.mozilla.org/docs/Glossary/Fingerprinting) for all assets at build time with a Base64 and removes caches when Visual Studio Hot Reload (development time) is in action. |
|||
|
|||
For more info: |
|||
|
|||
* [learn.microsoft.com > optimizing static web assets](https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-9.0?view=aspnetcore-8.0#optimizing-static-web-asset-delivery) |
|||
* [learn.microsoft.com > fundamentals of static files](https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/static-files?view=aspnetcore-9.0#static-asset-middleware) |
|||
|
|||
|
|||
|
|||
## Simplifying the process of querying component states at runtime |
|||
|
|||
1. Finding the component's current execution location: This can be especially helpful for component performance optimization and debugging. |
|||
2. Verifying whether the component is operating in a dynamic environment by checking: This can be useful for parts whose actions vary according to how their surroundings interact. |
|||
3. Obtaining the render mode allocated to the component: Comprehending the render mode can aid in enhancing the rendering procedure and augmenting the component's general efficiency. |
|||
|
|||
For more info: |
|||
|
|||
* [learn.microsoft.com > detect rendering location interactivity & render mode runtime](https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-9.0#detect-rendering-location-interactivity-and-assigned-render-mode-at-runtime) |
|||
|
|||
|
|||
|
|||
## Detecting component's location, interactivity support and render mode |
|||
|
|||
The `ComponentBase.RendererInfo` and `ComponentBase.AssignedRenderMode` now allows to detect the following actions: |
|||
|
|||
* `RendererInfo.Name` returns the location where the component is executing |
|||
* `RendererInfo.IsInteractive` indicates if the component supports interactivity at the time of rendering. |
|||
* `ComponentBase.AssignedRenderMode` exposes the component's assigned render mode |
|||
|
|||
|
|||
|
|||
## Better server-side reconnection |
|||
|
|||
* When the previous app is disconnected and the user navigates to this app, or browser put this app in sleep mode, Blazor runs reconnection mechanism. |
|||
|
|||
* When reconnection is not successful because your server killed connection, it automatically makes a full page refresh. |
|||
|
|||
* With the new below config, you can adjust your reconnection retry time: |
|||
|
|||
* ```csharp |
|||
Blazor.start({ |
|||
circuit: { |
|||
reconnectionOptions: { |
|||
retryIntervalMilliseconds: (previousAttempts, maxRetries) => |
|||
previousAttempts >= maxRetries ? null : previousAttempts * 1000 |
|||
}, |
|||
}, |
|||
}); |
|||
``` |
|||
|
|||
|
|||
|
|||
## Simple serialization for authentication |
|||
|
|||
The new APIs in ASP.NET make it easier to add authentication to existing Blazor Web Apps. These APIs, now part of the Blazor Web App project template, allow authentication state to be serialized on the server and deserialized in the browser, simplifying the process of integrating authentication. This removes the need for developers to manually implement or copy complex code, especially when using WebAssembly-based interactivity. |
|||
|
|||
For more info: |
|||
|
|||
- [learn.microsoft.com > blazor Identity UI individual accounts](https://learn.microsoft.com/en-us/aspnet/core/blazor/security/server/?view=aspnetcore-9.0#blazor-identity-ui-individual-accounts) |
|||
- [learn.microsoft.com > manage authentication state](https://learn.microsoft.com/en-us/aspnet/core/blazor/security/server/?view=aspnetcore-9.0#manage-authentication-state-in-blazor-web-apps) |
|||
|
|||
|
|||
|
|||
## Easily add static server-side rendering pages |
|||
|
|||
With .NET 9, adding static server-side rendering (SSR) pages to globally interactive Blazor Web Apps has become simpler. The new `[ExcludeFromInteractiveRouting]` attribute allows developers to mark specific Razor component pages that require static SSR, such as those relying on HTTP cookies and the request/response cycle. Pages annotated with this attribute exit interactive routing and trigger a full-page reload, while non-annotated pages default to interactive rendering modes like `InteractiveServer`. This approach enables flexibility between static and interactive rendering depending on the page's requirements. |
|||
|
|||
For more info: |
|||
|
|||
* [learn.microsoft.com > render-modes](https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-9.0#static-ssr-pages-in-a-globally-interactive-app) |
|||
|
|||
|
|||
|
|||
## Constructor Injection in Razor Components |
|||
|
|||
Razor components support constructor injection, allowing services like `NavigationManager` to be injected directly into a component's constructor. This can be used to manage navigation actions, such as redirecting the user upon an event like a button click. |
|||
|
|||
For more info: |
|||
|
|||
* [learn.microsoft.com> dependency-injection](https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/dependency-injection?view=aspnetcore-9.0#request-a-service-in-a-component) |
|||
|
|||
|
|||
|
|||
## Configuring WebSocket Compression and Frame-Ancestors CSP in Interactive Server Components |
|||
|
|||
By default, Interactive Server components enable WebSocket compression and set a `frame-ancestors` Content Security Policy (CSP) to `self`, restricting embedding the app in `<iframe>`. Besides, compression can be disabled to improve security by setting `ConfigureWebSocketOptions` to null, though this may reduce performance. To prevent embedding the app in any `iframe` while maintaining WebSocket compression, set the `ContentSecurityFrameAncestorsPolicy` to 'none'. |
|||
|
|||
For more info: |
|||
|
|||
- [learn.microsoft.com > websocket compression](https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/signalr?view=aspnetcore-9.0#websocket-compression-for-interactive-server-components) |
|||
- [learn.microsoft.com > interactive server-side rendering when compression enabled](https://learn.microsoft.com/en-us/aspnet/core/blazor/security/server/interactive-server-side-rendering?view=aspnetcore-9.0#interactive-server-components-with-websocket-compression-enabled) |
|||
|
|||
|
|||
|
|||
## Tracking Composition State with `KeyboardEventArgs.IsComposing` |
|||
|
|||
The new `KeyboardEventArgs.IsComposing` property indicates whether a keyboard event is part of a composition session, which is essential for properly handling international character input methods. |
|||
|
|||
|
|||
|
|||
## Configuring Row Overscan in `QuickGrid` with new `OverscanCount` parameter |
|||
|
|||
The `QuickGrid` component now includes an `OverscanCount` property, which controls how many extra rows are rendered before and after the visible area when virtualization is enabled. By default, `OverscanCount` is set to **3**, but it can be adjusted as below to **5**. |
|||
|
|||
```html |
|||
<QuickGrid ItemsProvider="itemsProvider" Virtualize="true" OverscanCount="5">...</QuickGrid> |
|||
``` |
|||
|
|||
|
|||
|
|||
## Range Input Support in `InputNumber<TValue>` Component |
|||
|
|||
The `InputNumber<TValue>` component now supports the `type="range"` [attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/range), allowing for range inputs like sliders or dials. This feature supports model binding and form validation, offering a more interactive way to input numerical data compared to the traditional text box. |
|||
|
|||
```html |
|||
<EditForm> |
|||
<InputNumber @bind-Value="Model.ProductCount" max="999" min="1" step="1" type="range" /> |
|||
</EditForm> |
|||
|
|||
@code { |
|||
public class MyModel |
|||
{ |
|||
[Required, Range(minimum: 1, maximum: 999)] |
|||
public int ProductCount { get; set; } |
|||
} |
|||
} |
|||
``` |
|||
|
|||
|
|||
|
|||
|
After Width: | Height: | Size: 216 KiB |
@ -0,0 +1,124 @@ |
|||
# Difference Between "Promise" and "Observable" in Angular |
|||
|
|||
In this article, I will mention the differences between `Promise` and `Observable` . They are used in TypeScript (Angular) for handling async operations but have different use cases and behaviors. Let's see these six differences... |
|||
|
|||
 |
|||
|
|||
|
|||
|
|||
## 1. Eager or Lazy Evaluation |
|||
|
|||
- **Promise**: A `promise` is **eager**! This means that as soon as a `promise` is created, it executes the operation, like initiating immediately an HTTP request. **You can't control the execution start time; it begins right away!** |
|||
|
|||
- **Observable:** An `observable` is a **lazy** operation! It doesn't start executing until you subscribe to it. This allows you to define an `observable` without triggering the actual operation until it's needed. |
|||
|
|||
|
|||
|
|||
## 2. Handling Value Count |
|||
|
|||
- **Promise:** A `promise` is designed to **handle a single async value**. Once the operation completes, it either resolves with a value or rejects with an error, and that's it! You can't emit multiple values with a single `promise`. |
|||
|
|||
- **Observable:** An `observable` **can emit multiple values** over time. It can have several values, and it can continue to do so until it either completes or errors out. So `observable` is ideal for event streams or data streams. |
|||
|
|||
|
|||
|
|||
## 3. Cancellablity |
|||
|
|||
- **Promise:** Once a `promise` is created and the operation has started**, you cannot cancel it!** The `promise` will resolve or reject eventually, and there's no way to stop it from being executed. |
|||
|
|||
- **Observable:** An `observable` **can be canceled**. If you unsubscribe from an `observable`, it stops emitting values and can clean up any resources like canceling an ongoing HTTP request. This makes `observable` more flexible in scenarios where you need to abort an operation. |
|||
|
|||
|
|||
|
|||
## 4. Chaining and Composition |
|||
|
|||
- **Promise:** It **supports chaining** using `.then()` for handling the result and `.catch()` for handling errors. This is straightforward but can become complex for more advanced scenarios. |
|||
|
|||
- **Observable:** It **supports powerful operators** like `map`, `filter`, `merge`, `switchMap`. This allows for complex composition and transformation of data streams and makes it suitable for handling complex async scenarios. |
|||
|
|||
|
|||
|
|||
## 5. Error Handling: |
|||
|
|||
- **Promise:** Error handling in `promise` is done usually using `.catch()`. However, **if an error occurs**, the `promise` will reject, and **the chain will stop**. |
|||
|
|||
- **Observable:** It has more **robust error-handling mechanisms**. You can handle errors using operators like `catchError` and decide whether to recover, continue or retry the process. It can also be completed successfully after an error is handled. |
|||
|
|||
|
|||
|
|||
## 6. Built-In or RxJS |
|||
|
|||
- **Promise:** It’s a **built-in feature of JavaScript** and a part of the ECMAScript. Almost all **browsers support it**. |
|||
- **Observable:** It’s **not a built-in feature of JavaScript**. In Angular, it’s provided by the `RxJS` library. |
|||
|
|||
|
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## Use Cases |
|||
|
|||
**Promise:** |
|||
|
|||
- Simple async operations that return a single result, like fetching data from a Web API. |
|||
- Scenarios where you don’t need to cancel the operation. |
|||
- Handling a single event or action. |
|||
|
|||
**Observable:** |
|||
|
|||
- Operations that might emit multiple values over time, such as `WebSocket` connections, user input events, or real-time data streams. |
|||
- When you need the ability to cancel the operation. |
|||
- Complex async flows require composition, transformation, or error handling. |
|||
|
|||
|
|||
|
|||
--- |
|||
|
|||
|
|||
|
|||
## Examples |
|||
|
|||
### Promise Example |
|||
|
|||
```javascript |
|||
const myPromise = new Promise((resolve, reject) => { |
|||
setTimeout(() => { |
|||
resolve('Promise is resolved!'); |
|||
}, 1000); |
|||
}); |
|||
|
|||
myPromise.then(value => console.log(value)).catch(error => console.error(error)); |
|||
``` |
|||
|
|||
### Observable Example |
|||
|
|||
```javascript |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
const myObservable = new Observable(observer => { |
|||
setTimeout(() => { |
|||
observer.next('Value-1 retrieved!'); |
|||
observer.next('Value-2 retrieved!'); |
|||
observer.complete(); // No more values after this |
|||
}, 1000); |
|||
}); |
|||
|
|||
const subscription = myObservable.subscribe({ |
|||
next: value => console.log(value), |
|||
error: error => console.error(error), |
|||
complete: () => console.log('Observable finished!') |
|||
}); |
|||
|
|||
/* |
|||
You can unsubscribe to cancel the observable as below: |
|||
subscription.unsubscribe(); |
|||
*/ |
|||
``` |
|||
|
|||
|
|||
|
|||
## Summary |
|||
|
|||
- **A promise** is simple and suitable for operations that return a single value or need to handle a single event. It’s eager and can’t be canceled. |
|||
- **An observable** is more flexible, especially for handling multiple values over time, allowing for complex data manipulation, and providing the ability to cancel operations. It supports lazy operations via `RxJS`. |
|||
@ -0,0 +1,70 @@ |
|||
# BLOB Storing Google Provider |
|||
|
|||
BLOB Storing Google Provider can store BLOBs in [Google Cloud Storage](https://cloud.google.com/storage). |
|||
|
|||
> Read the [BLOB Storing document](../blob-storing) to understand how to use the BLOB storing system. This document only covers how to configure containers to use a Google Cloud Storage as the storage provider. |
|||
|
|||
## Installation |
|||
|
|||
Use the ABP CLI to add [Volo.Abp.BlobStoring.Google](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Google) NuGet package to your project: |
|||
|
|||
* Install the [ABP CLI](../../../cli) if you haven't installed before. |
|||
* Open a command line (terminal) in the directory of the `.csproj` file you want to add the `Volo.Abp.BlobStoring.Google` package. |
|||
* Run `abp add-package Volo.Abp.BlobStoring.Google` command. |
|||
|
|||
If you want to do it manually, install the [Volo.Abp.BlobStoring.Google](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Google) NuGet package to your project and add `[DependsOn(typeof(AbpBlobStoringGoogleModule))]` to the [ABP module](../../architecture/modularity/basics.md) class inside your project. |
|||
|
|||
## Configuration |
|||
|
|||
Configuration is done in the `ConfigureServices` method of your [module](../../architecture/modularity/basics.md) class, as explained in the [BLOB Storing document](../blob-storing). |
|||
|
|||
**Example: Configure to use the Google storage provider by default** |
|||
|
|||
````csharp |
|||
Configure<AbpBlobStoringOptions>(options => |
|||
{ |
|||
options.Containers.ConfigureDefault(container => |
|||
{ |
|||
container.UseGoogle(google => |
|||
{ |
|||
google.ClientEmail = "your coogle client email"; |
|||
google.ProjectId = "your coogle project id"; |
|||
google.PrivateKey = "your coogle private key"; |
|||
google.Scopes = "your coogle scopes"; |
|||
google.ContainerName = "your coogle container name"; |
|||
google.CreateContainerIfNotExists = true; |
|||
//google.UseApplicationDefaultCredentials = true; // If you want to use application default credentials |
|||
}); |
|||
}); |
|||
}); |
|||
```` |
|||
|
|||
> See the [BLOB Storing document](../blob-storing) to learn how to configure this provider for a specific container. |
|||
|
|||
### Options |
|||
|
|||
* **ClientEmail** (string): The client email of the Google service account. You can create a service account and get the client email. Please refer to Google documentation: https://cloud.google.com/iam/docs/service-account-overview |
|||
* **ProjectId** (string): The project ID of the Google service account. |
|||
* **PrivateKey** (string): The private key of the Google service account. You can create a service account and get the private key. Please refer to Google documentation: https://cloud.google.com/iam/docs/keys-create-delete |
|||
* **Scopes** (string): The scopes of the Google service account. |
|||
* **UseApplicationDefaultCredentials** (bool): If `true`, it uses the application default credentials(ADC). Default value is `false`. Please refer to Google documentation: https://cloud.google.com/docs/authentication/provide-credentials-adc |
|||
* **ContainerName** (string): You can specify the container name in Google. If this is not specified, it uses the name of the BLOB container defined with the `BlobContainerName` attribute (see the [BLOB storing document](../blob-storing)). Please note that Google has some **rules for naming containers**. A container name must be a valid DNS name, conforming to the [following naming rules](https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names): |
|||
* Container names must start or end with a letter or number, and can contain only letters, numbers, and the dash (-) character. |
|||
* Every dash (-) character must be immediately preceded and followed by a letter or number; consecutive dashes are not permitted in container names. |
|||
* All letters in a container name must be **lowercase**. |
|||
* Container names must be from **3** through **63** characters long. |
|||
* **CreateContainerIfNotExists** (bool): Default value is `false`, If a container does not exist in Google, `GoogleBlobProvider` will try to create it. |
|||
|
|||
|
|||
## Google Blob Name Calculator |
|||
|
|||
Google Blob Provider organizes BLOB name and implements some conventions. The full name of a BLOB is determined by the following rules by default: |
|||
|
|||
* Appends `host` string if [current tenant](../../architecture/multi-tenancy) is `null` (or multi-tenancy is disabled for the container - see the [BLOB Storing document](../blob-storing) to learn how to disable multi-tenancy for a container). |
|||
* Appends `tenants/<tenant-id>` string if current tenant is not `null`. |
|||
* Appends the BLOB name. |
|||
|
|||
## Other Services |
|||
|
|||
* `GoogleBlobProvider` is the main service that implements the Google BLOB storage provider, if you want to override/replace it via [dependency injection](../../fundamentals/dependency-injection.md) (don't replace `IBlobProvider` interface, but replace `GoogleBlobProvider` class). |
|||
* `IGoogleBlobNameCalculator` is used to calculate the full BLOB name (that is explained above). It is implemented by the `DefaultGoogleBlobNameCalculator` by default. |
|||
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 181 KiB |
|
After Width: | Height: | Size: 6.0 KiB |