diff --git a/.github/workflows/angular.yml b/.github/workflows/angular.yml
index a4036f8474..0c0f8d5b6c 100644
--- a/.github/workflows/angular.yml
+++ b/.github/workflows/angular.yml
@@ -12,9 +12,11 @@ on:
- 'dev'
jobs:
build-test-lint:
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
- uses: actions/cache@v2
with:
@@ -31,25 +33,13 @@ jobs:
working-directory: npm/ng-packs
- name: Run lint
- run: yarn ng lint
+ run: yarn affected:lint --base=remotes/origin/${{ github.base_ref }}
working-directory: npm/ng-packs
- - name: Run prepare workspace
- run: yarn prepare:workspace
+ - name: Run build
+ run: yarn affected:build --base=remotes/origin/${{ github.base_ref }}
working-directory: npm/ng-packs
- name: Run test
- run: yarn ci:test
- working-directory: npm/ng-packs
-
- - name: Build dev-app
- run: yarn build --prod
+ run: yarn affected:test --base=remotes/origin/${{ github.base_ref }}
working-directory: npm/ng-packs
-
- - name: Install packages of app template
- run: yarn install
- working-directory: templates/app/angular
-
- - name: Build app template
- run: yarn build --prod
- working-directory: templates/app/angular
diff --git a/.github/workflows/cancel-workflow.yml b/.github/workflows/cancel-workflow.yml
new file mode 100644
index 0000000000..78bbf94b3b
--- /dev/null
+++ b/.github/workflows/cancel-workflow.yml
@@ -0,0 +1,12 @@
+name: cancel-workflow
+on: [push]
+jobs:
+ cancel:
+ name: 'Cancel Previous Runs'
+ runs-on: ubuntu-latest
+ timeout-minutes: 3
+ steps:
+ - uses: styfle/cancel-workflow-action@0.6.0
+ with:
+ workflow_id: 10629,1299107,2792859,8268314
+ access_token: ${{ github.token }}
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index ae5d4fdacc..7aaad739e9 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -7,12 +7,22 @@ name: "CodeQL"
on:
push:
- branches: [dev, rel-1.0, rel-1.1, rel-2.0, rel-2.1, rel-2.2, rel-2.3, rel-2.4, rel-2.5, rel-2.6, rel-2.7, rel-2.8, rel-2.9, rel-3.0, rel-3.1, rel-3.2]
+ branches: [dev, rel-*]
+ paths:
+ - 'abp/**/*.js'
+ - 'abp/**/*.cs'
+ - 'abp/**/*.cshtml'
+ - 'abp/**/*.csproj'
+ - 'abp/**/*.razor'
pull_request:
# The branches below must be a subset of the branches above
branches: [dev]
- schedule:
- - cron: '0 8 * * 6'
+ paths:
+ - 'abp/**/*.js'
+ - 'abp/**/*.cs'
+ - 'abp/**/*.cshtml'
+ - 'abp/**/*.csproj'
+ - 'abp/**/*.razor'
jobs:
analyze:
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/ro-RO.json
new file mode 100644
index 0000000000..299aea53ed
--- /dev/null
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/ro-RO.json
@@ -0,0 +1,14 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "Account": "Cont ABP - Autentificare & Înregistrare | ABP.IO",
+ "Welcome": "Bun venit",
+ "UseOneOfTheFollowingLinksToContinue": "Folosiţi unul din următoarele linkuri pentru a continua",
+ "FrameworkHomePage": "Pagina principală a frameworkului",
+ "FrameworkDocumentation": "Documentaţia frameworkului",
+ "OfficialBlog": "Blogul oficial",
+ "CommercialHomePage": "Pagina principală comercială",
+ "CommercialSupportWebSite": "Site-ul web al suportului comercial",
+ "CommunityWebSite": "Site-ul web al comunităţii ABP"
+ }
+}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
index 10ca9a0a67..e23ed3fe5b 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
@@ -303,6 +303,13 @@
"ProductPrice": "Product Price",
"AdditionalDeveloper": "Additional developer",
"ThisPaymentHasBeenAlreadyUsed": "This payment has been already used",
- "PaymentTimeCannotBeFutureTime": "Payment time cannot be future time"
+ "PaymentTimeCannotBeFutureTime": "Payment time cannot be a future time!",
+ "SaveAndDownload": "Save and Download",
+ "BillingInfo": "Billing Info",
+ "GenerateInvoice": "Create Invoice",
+ "DeleteInvoice" : "Delete Invoice",
+ "SuccessfullyDeleted": "Successfully deleted!",
+ "PaymentStateSetTo" : "Payment state set to {0}",
+ "ChangeState": "Change State"
}
}
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ro-RO.json
new file mode 100644
index 0000000000..caf032d940
--- /dev/null
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ro-RO.json
@@ -0,0 +1,308 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "Permission:Organizations": "Organizaţii",
+ "Permission:Manage": "Administrare Organizaţii",
+ "Permission:DiscountRequests": "Cereri de reduceri",
+ "Permission:DiscountManage": "Administrare cereri de reduceri",
+ "Permission:Disable": "Dezactivează",
+ "Permission:Enable": "Activează",
+ "Permission:EnableSendEmail": "Activează trimitere Email",
+ "Permission:SendEmail": "Trimite Email",
+ "Permission:NpmPackages": "Pachete NPM",
+ "Permission:NugetPackages": "Pachete Nuget",
+ "Permission:Maintenance": "Întreţinere",
+ "Permission:Maintain": "Întreţine",
+ "Permission:ClearCaches": "Goleşte cache-ul",
+ "Permission:Modules": "Module",
+ "Permission:Packages": "Pachete",
+ "Permission:Edit": "Modifică",
+ "Permission:Delete": "Şterge",
+ "Permission:Create": "Creează",
+ "Permission:Accounting": "Contabilitate",
+ "Permission:Accounting:Quotation": "Citat",
+ "Permission:Accounting:Invoice": "Factură",
+ "Menu:Organizations": "Organizaţii",
+ "Menu:Accounting": "Contabilitate",
+ "Menu:Packages": "Pachete",
+ "Menu:DiscountRequests": "Cereri de reduceri",
+ "NpmPackageDeletionWarningMessage": "Sunteţi sigur(ă) că doriţi să ştergeţi acest pachet de tip NPM?",
+ "NugetPackageDeletionWarningMessage": "Sunteţi sigur(ă) că doriţi să ştergeţi acest pachet de tip Nuget?",
+ "ModuleDeletionWarningMessage": "Sunteţi sigur(ă) că doriţi să ştergeţi acest modul?",
+ "Name": "Nume",
+ "DisplayName": "Nume de afişare",
+ "ShortDescription": "Descriere scurtă",
+ "NameFilter": "Nume",
+ "CreationTime": "Data şi ora creării",
+ "IsPro": "Este pro",
+ "IsFreeToActiveLicenseOwners": "Gratuit pentru deţinătorii de licenţă",
+ "ShowOnModuleList": "Afişează în lista modulelor",
+ "EfCoreConfigureMethodName": "Configurează numele metodei",
+ "IsProFilter": "Este pro",
+ "ApplicationType": "Tipul aplicaţiei",
+ "Target": "Ţinta",
+ "TargetFilter": "Ţinta",
+ "ModuleClass": "Clasa modulului",
+ "NugetPackageTarget.DomainShared": "Domain Shared",
+ "NugetPackageTarget.Domain": "Domain",
+ "NugetPackageTarget.Application": "Application",
+ "NugetPackageTarget.ApplicationContracts": "Application Contracts",
+ "NugetPackageTarget.HttpApi": "Http Api",
+ "NugetPackageTarget.HttpApiClient": "Http Api Client",
+ "NugetPackageTarget.Web": "Web",
+ "NugetPackageTarget.EntityFrameworkCore": "DeleteAllEntityFramework Core",
+ "NugetPackageTarget.MongoDB": "MongoDB",
+ "Edit": "Modifică",
+ "Delete": "Şterge",
+ "Refresh": "Reîncarcă",
+ "NpmPackages": "Pachete NPM",
+ "NugetPackages": "Pachete Nuget",
+ "NpmPackageCount": "Număr pachete NPM",
+ "NugetPackageCount": "Număr pachete Nuget",
+ "Module": "Module",
+ "ModuleInfo": "Info module",
+ "CreateANpmPackage": "Crează un pachet NPM",
+ "CreateAModule": "Crează un modul",
+ "CreateANugetPackage": "Crează un pachet Nuget",
+ "AddNew": "Adaugă o înregistrare nouă",
+ "PackageAlreadyExist{0}": "Pachetul \"{0}\" este deja adăugat.",
+ "ModuleAlreadyExist{0}": "Modulul \"{0}\" este deja adăugat.",
+ "ClearCache": "Goleşte cache",
+ "SuccessfullyCleared": "Golit cu succes",
+ "Menu:NpmPackages": "Pachete de tip NPM",
+ "Menu:Modules": "Module",
+ "Menu:Maintenance": "Mentenanţă",
+ "Menu:NugetPackages": "Pachete de tip Nuget",
+ "CreateAnOrganization": "Crează o organizaţie",
+ "Organizations": "Organizaţii",
+ "LongName": "Nume complet",
+ "LicenseType": "Tipul licenţei",
+ "MissingLicenseTypeField": "Câmpul de tip licenţă este obligatoriu!",
+ "LicenseStartTime": "Ora de început a licenţei",
+ "LicenseEndTime": "Ora de sfârşit a licenţei",
+ "AllowedDeveloperCount": "Număr permis de dezvoltatori",
+ "UserNameOrEmailAddress": "Numele de utilizator sau adresa de email",
+ "AddOwner": "Adaugă proprietar",
+ "UserName": "Nume de utilizator",
+ "Email": "Email",
+ "Developers": "Dezvoltatori",
+ "AddDeveloper": "Adaugă dezvoltator",
+ "Create": "Creează",
+ "UserNotFound": "Utilizatorul nu a fost găsit",
+ "{0}WillBeRemovedFromDevelopers": "{0} va fi eliminat dintre dezvoltatori, confirmaţi?",
+ "{0}WillBeRemovedFromOwners": "{0} va fi eliminat dintre proprietari, confirmaţi?",
+ "{0}WillBeRemovedFromMembers": "{0} va fi eliminat dintre membri, confirmaţi?",
+ "Computers": "Calculatoare",
+ "UniqueComputerId": "Identificator unic calculator",
+ "LastSeenDate": "Data ultimei accesări",
+ "{0}Computer{1}WillBeRemovedFromRecords": "Calculatorul {0} ({1}) va fi eliminat dintre înregistrări",
+ "OrganizationDeletionWarningMessage": "Organizaţia va fi ştearsă",
+ "DeletingLastOwnerWarningMessage": "Organizaţia trebuie să aibă cel puţin un proprietar! Prin urmare nu puteţi şterge acest proprietar.",
+ "This{0}AlreadyExistInThisOrganization": "Acest(a) {0} există deja în această organizaţie",
+ "AreYouSureYouWantToDeleteAllComputers": "Sunteţi sigur(ă) că doriţi să ştergeţi toate calculatoarele?",
+ "DeleteAll": "Şterge tot",
+ "DoYouWantToCreateNewUser": "Vreţi să creaţi un nou utilizator?",
+ "MasterModules": "Module master",
+ "OrganizationName": "Nume organizaţie",
+ "CreationDate": "Data creării",
+ "LicenseStartDate": "Data de început a licenţei",
+ "LicenseEndDate": "Data de sfărşit a licenţei",
+ "OrganizationNamePlaceholder": "Numele organizaţiei...",
+ "TotalQuestionCountPlaceholder": "Numărul total de înrebări...",
+ "RemainingQuestionCountPlaceholder": "Numărul de întrebări rămase...",
+ "LicenseTypePlaceholder": "Tipul licenţei...",
+ "CreationDatePlaceholder": "Data creării...",
+ "LicenseStartDatePlaceholder": "Data de început a licenţei...",
+ "LicenseEndDatePlaceholder": "Data de sfârşit a licenţei...",
+ "UsernameOrEmail": "Nume de utilizator sau email",
+ "UsernameOrEmailPlaceholder": "Nume de utilizator sau email...",
+ "Member": "Membru",
+ "PurchaseOrderNo": "Achiziţia numărul",
+ "QuotationDate": "Data citării",
+ "CompanyName": "Nume companie",
+ "CompanyAddress": "Adresă companie",
+ "Price": "Preţ",
+ "DiscountText": "Text discount",
+ "DiscountQuantity": "Cantitate discount",
+ "DiscountPrice": "Preţ discount",
+ "Quotation": "Citare",
+ "ExtraText": "Text extra",
+ "ExtraAmount": "Cantitate extra",
+ "DownloadQuotation": "Descarcă citarea",
+ "Invoice": "Factură",
+ "TaxNumber": "Număr taxă",
+ "InvoiceNumber": "Număr factură",
+ "InvoiceDate": "Dată factură",
+ "InvoiceNote": "Notă factură",
+ "Quantity": "Cantitate",
+ "AddProduct": "Adaugă produs",
+ "AddProductWarning": "Trebuie să adăugaţi un produs!",
+ "TotalPrice": "Preţ total",
+ "Generate": "Generează",
+ "MissingQuantityField": "Câmpul de cantitate este obligatoriu!",
+ "MissingPriceField": "Câmpul de preţ este obligatoriu!",
+ "CodeUsageStatus": "Stare",
+ "Country": "Ţara",
+ "DeveloperCount": "Număr dezvoltatori",
+ "RequestCode": "Cod solicitare",
+ "WebSite": "Web Site",
+ "GithubUsername": "Nume utilizator de Github",
+ "PhoneNumber": "Număr de telefon",
+ "ProjectDescription": "Descriere proiect",
+ "Referrer": "Referent",
+ "DiscountRequests": "Cerere de reducere",
+ "Copylink": "Copiază linkul",
+ "Disable": "Dezactivează",
+ "Enable": "Activează",
+ "EnableSendEmail": "Activează trimitere Email",
+ "SendEmail": "Trimite Email",
+ "SuccessfullyDisabled": "Dezactivat cu succes",
+ "SuccessfullyEnabled": "Activat cu succes",
+ "EmailSent": "Email trimis",
+ "SuccessfullySent": "Trimis cu succes",
+ "SuccessfullyDeleted": "Şters cu succes",
+ "DiscountRequestDeletionWarningMessage": "Cererea de reducere va fi ştearsă",
+ "BusinessType": "Tip afacere",
+ "TotalQuestionCount": "Număr total de întrebări",
+ "RemainingQuestionCount": "Număr de întrebări rămase",
+ "TotalQuestionMustBeGreaterWarningMessage": "Numărul total de întrebări trebuie să fie mai mare decât numărul de întrebări rămase!",
+ "QuestionCountsMustBeGreaterThanZero": "Numărul total de întrebări şi numărul de întrebări rămase trebuie să fie mai mai mare sau egal cu 0!",
+ "UnlimitedQuestionCount": "Număr nelimitat de întrebări",
+ "Notes": "Notiţe",
+ "Menu:Community": "Comunitate",
+ "Menu:Articles": "Articole",
+ "Wait": "Aşteaptă",
+ "Approve": "Aprobă",
+ "Reject": "Respinge",
+ "Details": "Detalii",
+ "Url": "Url",
+ "Title": "Titlu",
+ "ContentSource": "Sursa conţinutului",
+ "Status": "Status",
+ "ReadArticle": "Citeşte articolul",
+ "ArticleHasBeenWaiting": "Articolul a fost în aşteptare",
+ "ArticleHasBeenApproved": "Articolul a fost aprobat",
+ "ArticleHasBeenRejected": "Articolul a fost respins",
+ "Permission:Community": "Comunitate",
+ "Permission:CommunityArticle": "Articole",
+ "Link": "Link",
+ "Enum:ContentSource:0": "Github",
+ "Enum:ContentSource:1": "External",
+ "Enum:Status:0": "Aşteptare",
+ "Enum:Status:1": "Respins",
+ "Enum:Status:2": "Aprobat",
+ "Summary": "Sumar",
+ "AuthorName": "Nume autor",
+ "CoverImage": "Imagine de copertă",
+ "RemoveCacheConfirmationMessage": "Sunteţi sigur(ă) că doriţi să eliminaţi cache-ul pentru articolul \"{0}\"?",
+ "SuccessfullyRemoved": "Eliminat cu succes",
+ "RemoveCache": "Elimină cache",
+ "Language": "Limba",
+ "Optional": "Opţional",
+ "CreateArticleLanguageInfo": "Limba în care este scris articolul",
+ "Enum:ContentSource:2": "Post Video",
+ "VideoPreview": "Previzualizare Video",
+ "VideoPreviewErrorMessage": "Adresa URL a clipului video nu a putut fi recuperată de pe Youtube. Acest lucru poate fi cauzat de faptul că videoclipul este privat, sau adresa URL nu este disponibilă.",
+ "DeleteCoverImage": "Şterge imaginea de copertă",
+ "DeleteCoverImageConfirmationMessage": "Sunteţi sigur(ă) că doriţi să ştergeti imaginea de copertă pentru \"{0}\"?",
+ "DeleteCoverImageSuccessMessage": "Imaginea de copertă a fost ştearsă cu succes",
+ "PaymentsOf": "Plăţi de",
+ "ShowPaymentsOfOrganization": "Plăţi",
+ "Date": "Data",
+ "Products": "Produse",
+ "TotalAmount": "Cantitate totală",
+ "Currency": "Valută",
+ "Gateway": "Gateway",
+ "State": "Stare",
+ "FailReason": "Motivul eşuării",
+ "ReIndexAllPosts": "Reindexati toate postările",
+ "ReIndexAllPostsConfirmationMessage": "Sunteţi sigur(ă) că doriţi să reindexaţi toate postările?",
+ "SuccessfullyReIndexAllPosts": "Toate postările au fost reindexate.",
+ "Permission:FullSearch": "Căutare integrală a textului",
+ "Menu:CliAnalytics": "Analitice Cli",
+ "TemplateName": "Nume şablon",
+ "TemplateVersion": "Versiune şablon",
+ "DatabaseProvider": "Furnizor bază de date",
+ "IsTiered": "Este nivelat",
+ "ProjectName": "Nume proiect",
+ "Username": "Nume utilizator",
+ "Tool": "Unealtă",
+ "Command": "Comandă",
+ "UiFramework": "Ui framework",
+ "Options": "Opţiuni",
+ "CliAnalytics": "Analitice Cli",
+ "Permission:CliAnalyticses": "Analitice Cli",
+ "Permission:CliAnalytics": "Analitice Cli",
+ "Search": "Caută",
+ "ClearFilter": "Şterge filtru",
+ "LicensePrivateKey": "Cheie privată licenţă",
+ "LicensePublicKey": "Cheie publică licenţă",
+ "ApiKey": "Cheie API NuGet",
+ "ShowInvoiceRequestsOfOrganization": "Solicitări de factură",
+ "ShowQuestionsOfOrganization": "Întrebări",
+ "Question": "Întrebare",
+ "Open": "Deschide",
+ "Questions": "Întrebări",
+ "InvoiceRequests": "Solicitări de factură",
+ "Address": "Adresa",
+ "TaxNo": "Taxa numărul",
+ "Permission:InvoiceRequest": "Solicitare de factură",
+ "Permission:Question": "Întrebare",
+ "AddNoteSuccessMessage": "Notă adăugată cu succes",
+ "NameSurname": "Nume Prenume",
+ "Note": "Notează",
+ "Add": "Adaugă",
+ "ProjectDownloads": "Descărcările proiectului",
+ "ShowProjectDownloadsOfOrganization": "Descărcările proiectului",
+ "ShowAuditLogsOfOrganization": "Jurnale de audit",
+ "Enum:EntityChangeType:0": "Creat",
+ "Enum:EntityChangeType:1": "Actualizat",
+ "Enum:EntityChangeType:2": "Şters",
+ "TenantId": "ID Tenant",
+ "ChangeTime": "Schimbă ora",
+ "EntityTypeFullName": "Numele complet al tipului entităţii",
+ "AuditLogsFor{0}Organization": "Jurnale de audit pentru organizaţia \"{0}\"",
+ "Permission:EntityChange": "Schimbă entitatea",
+ "Permission:ProjectDownload": "Descarcă proiectul",
+ "Permission:PaymentRequest": "Solicitări de plată",
+ "CreatorEmailAddress": "Adresa de email a creatorului",
+ "EmailSendDate": "Data trimiterii emailului",
+ "PaymentRequestsFor{0}Organization": "Solicitări de plată pentru organizaţia \"{0}\"",
+ "PaymentDetails": "Detalii plată",
+ "PaymentProduct": "Produs plată",
+ "ProductName": "Nume produs",
+ "Code": "Cod",
+ "GenerateInvoice": "Generează factură",
+ "ExportOrganizationsToExcel": "Exportă în Excel",
+ "ThisExtensionIsNotAllowed": "Această extensie nu este permisă.",
+ "TheFileIsTooLarge": "Dimensiunea fişierului este prea mare!",
+ "ArticleDeletionConfirmationMessage": "Sunteţi sigur(ă) că doriţi şă ştergeţi definitiv acest articol?",
+ "ChooseCoverImage": "Alege o imagine de copertă...",
+ "Menu:Quotation": "Citare",
+ "Menu:Invoice": "Factură",
+ "Menu:PaymentRequests": "Solicitări plată",
+ "Permission:PaymentRequests": "Solicitări plată",
+ "PaymentRequests": "Solicitări plată",
+ "Creator": "Creator",
+ "ExtraProperties": "Proprietăţi extra",
+ "Organization": "Organizaţia",
+ "Waiting": "În aşteptare",
+ "Completed": "Finalizat",
+ "Failed": "Eşuat",
+ "PaymentRequestDeletionWarningMessage": "Sunteţi sigur(ă) că doriţi să ştergeţi această plată?",
+ "Payment": "Plata",
+ "AddPayment": "Adaugă plată",
+ "Enum:PurchaseType:1": "Licenţă nouă",
+ "Enum:PurchaseType:2": "Extindere licenţă",
+ "Enum:PurchaseType:3": "Îmbunătăţire licenţă",
+ "Enum:PurchaseType:4": "Dezvoltator suplimentar",
+ "LicenceType": "Tipul licenţei",
+ "PurchaseType": "Tipul achiziţiei",
+ "ReceiptNo": "Chitanţa numărul",
+ "PaymentTime": "Data plăţii",
+ "ProductPrice": "Preţul produsului",
+ "AdditionalDeveloper": "Dezvoltator suplimentar",
+ "ThisPaymentHasBeenAlreadyUsed": "Această plată a fost deja folosită",
+ "PaymentTimeCannotBeFutureTime": "Data plăţii nu poate fi în viitor"
+ }
+}
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/ro-RO.json
new file mode 100644
index 0000000000..37084abbaf
--- /dev/null
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/ro-RO.json
@@ -0,0 +1,40 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "Volo.AbpIo.Domain:010004": "Numărul maxim de membri a fost atins!",
+ "Volo.AbpIo.Domain:010005": "Numărul maxim de proprietari a fost atins!",
+ "Volo.AbpIo.Domain:010006": "Există deja un proprietar în această organizaţie!",
+ "Volo.AbpIo.Domain:010007": "Acest utilizator este deja dezvoltator în această organizaţie!",
+ "Volo.AbpIo.Domain:010008": "Numărul permis de dezvoltatori nu poate fi mai mic decât numărul curent de dezvoltatori!",
+ "Volo.AbpIo.Domain:010009": "Numărul permis de dezvoltatori nu poate fi mai mic decât 0!",
+ "Volo.AbpIo.Domain:010010": "Numărul maxim de adrese de tip mac este depăşit!",
+ "Volo.AbpIo.Domain:010011": "Licenţa personală nu poate avea mai mult de un dezvoltator!",
+ "Volo.AbpIo.Domain:010012": "Licenţa nu poate fi prelungită la o lună după ce aceasta a expirat!",
+ "Volo.AbpIo.Domain:020001": "Nu s-a putut şterge acest pachet NPM deoarece \"{NugetPackages}\" există pachete Nuget dependente de acest pachet.",
+ "Volo.AbpIo.Domain:020002": "Nu s-a putut şterge acest pachet NPM deoarece \"{Modules}\" modulele folosesc acest pachet.",
+ "Volo.AbpIo.Domain:020003": "Nu s-a putut şterge acest pachet NPM deoarece \"{Modules}\" modulele folosesc acest pachet \"{NugetPackages}\" şi există pachete Nuget dependente de acest pachet.",
+ "Volo.AbpIo.Domain:020004": "Nu s-a putut şterge acest pachet Nuget deoarece \"{Modules}\" modulele folosesc acest pachet.",
+ "WantToLearn?": "Vrei să înveţi?",
+ "ReadyToGetStarted?": "Eşti gata pentru a începe?",
+ "JoinOurCommunity": "Alăturaţi-vă comunităţii noastre",
+ "GetStartedUpper": "ÎNCEPE",
+ "ForkMeOnGitHub": "Fork me on GitHub",
+ "Features": "Caracteristici",
+ "GetStarted": "Începe",
+ "Documents": "Documente",
+ "Community": "Comunitate",
+ "ContributionGuide": "Ghid de contribuţie",
+ "Blog": "Blog",
+ "Commercial": "Comercial",
+ "MyAccount": "Contul meu",
+ "Permission:License": "Licenţă",
+ "Permission:UserInfo": "Info utilizator",
+ "SeeDocuments": "Vezi documente",
+ "Samples": "Mostre",
+ "Framework": "Framework",
+ "Support": "Suport",
+ "FreeDDDBook": "DDD E-book gratis",
+ "New": "Nou",
+ "Volo.AbpIo.Domain:020005": "Anul prelungirii licenţei nu poate fi mai mic decât {MinExtendLicenseYear} şi mai mare decât {MaxExtendLicenseYear}"
+ }
+}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/ro-RO.json
new file mode 100644
index 0000000000..c5a76c1617
--- /dev/null
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/ro-RO.json
@@ -0,0 +1,5 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ }
+}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
index 58e4b561d6..46ff49bb4b 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
@@ -45,7 +45,7 @@
"IndexPageHeroSection": "A complete web development platformbuilt-on framework",
"AbpCommercialShortDescription": "ABP Commercial provides pre-built application modules, rapid application development tooling, professional UI themes, premium support and more.",
"LiveDemo": "Live Demo",
- "GetLicence" :"Get a Licence",
+ "GetLicence": "Get a Licence",
"Application": "Application",
"StartupTemplates": "Startup Templates",
"Startup": "Startup",
@@ -106,7 +106,7 @@
"DarkBlueTheme": "Dark Blue Theme",
"LightTheme": "Light Theme",
"ProudToWorkWith": "Proud to Work With",
- "OurConsumers": "Hundreds of enterprises and developers over 50 countries worldwide rely on ABP Commercial.",
+ "OurConsumers": "Thousands of enterprises and developers over 70 countries worldwide rely on ABP Commercial.",
"JoinOurConsumers": "Join them and build amazing products fast.",
"AdditionalServicesExplanation": "Do you need additional or custom services? We and our partners can provide;",
"CustomProjectDevelopment": "Custom Project Development",
@@ -174,8 +174,8 @@
"HowManyProductsExplanation": "There is no limit to create an ABP project. You can create as many project as you want, develop and upload them to different servers.",
"HowManyDevelopers": "How many developers can work on the ABP Commercial?",
"HowManyDevelopersExplanation": "ABP Commercial licenses are per developer. Different license types have different developer limits. However, you can add more developers to any license type whenever you need. See the prices page for license types, developer limits and additional developer costs.",
- "ChangingLicenseType": "Can I change my license type in the future?",
- "ChangingLicenseTypeExplanation": "You can always add new developers in your same license type. See also \"How many developers can work on the ABP Commercial?\". You can also upgrade to a higher license by paying the calculated price difference. When you upgrade to a higher license plan, you get the benefits of the new plan, but the license upgrade does not change the license expiry date.",
+ "ChangingLicenseType": "Can I upgrade my license type later?",
+ "ChangingLicenseTypeExplanation": "You can upgrade to a higher license by paying the difference within your active license period. When you upgrade to a higher license plan, you get the benefits of the new plan, but the license upgrade does not change the license expiry date. Besides, you can also add new developer seats to your existing license, see \"How many developers can work on the ABP Commercial?\"",
"LicenseExtendUpgradeDiff": "What is the difference between license extend and upgrade?",
"LicenseExtendUpgradeDiffExplanation": "Extending: By extending/renewing your license, you will continue to get premium support and get major updates for the modules and themes. Besides, you will be able to continue creating new projects. And you will still be able to use ABP Suite which speeds up your development.
Upgrading: By upgrading your license, you will promote to a higher license plan which will allow you to get additional benefits. See the license comparison table to check the differences between the license plans.On the other hand, when you upgrade, your license expiry date will not change!To extend your license end date, you need to extend your license.",
"LicenseRenewalCost": "What is the license renewal cost after 1 year?",
@@ -196,14 +196,14 @@
"WhatHappensWhenLicenseEndsExplanation4": "You can not install new modules and themes added to the ABP Commercial platform after your license ends.",
"WhatHappensWhenLicenseEndsExplanation5": "You can not use the ABP Suite.",
"WhatHappensWhenLicenseEndsExplanation6": "You can not get the premium support anymore.",
- "WhatHappensWhenLicenseEndsExplanation7": "You can renew your subscription if you want to continue to get these benefits. There is a 20% discount when you renew your subscription.",
+ "WhatHappensWhenLicenseEndsExplanation7": "You can renew your subscription if you want to continue to get these benefits. If you renew your subscription within 1 month after your license expires, a 20% discount is applied.",
"WhenShouldIRenewMyLicense": "When should I renew my license?",
- "WhenShouldIRenewMyLicenseExplanation1": "If you renew your license within 1 month after your license expires, %20 discount will be applied to total license price.",
+ "WhenShouldIRenewMyLicenseExplanation1": "If you renew your license within 1 month after your license expires, a %20 discount is be applied.",
"WhenShouldIRenewMyLicenseExplanation2": "If you renew your license after 1 month from your license expire date, the renew price will be same as license purchase price and there will be no discount for your renewal.",
"TrialPlan": "Do you have a trial plan?",
"TrialPlanExplanation": "For now, ABP Commercial doesn't have a trial plan. For the Team licenses we provide 30 days money back guarantee. You can just request a refund in the first 30 days. For the Business and Enterprise licenses, we provide 60% refund in 30 days. This is because Business and Enterprise licenses include the full source code of all the modules and the themes.",
"DoYouAcceptBankWireTransfer": "Do you accept bank wire transfer?",
- "DoYouAcceptBankWireTransferExplanation": "Yes, we accept bank wire transfer. After sending the license amount via bank wire transfer, send us your receipt and the requested license type via e-mail. Our international bank account information:",
+ "DoYouAcceptBankWireTransferExplanation": "Yes, we accept bank wire transfer. After sending the license fee via bank transfer, email us at info@abp.io your receipt and the type of license requested. Our international bank account information:",
"HowToUpgrade": "How to upgrade existing applications when a new version is available?",
"HowToUpgradeExplanation1": "When you create a new application using ABP Commercial, all the modules and the theme are used as NuGet and NPM packages. So, you can easily upgrade the packages when a new version is available.",
"HowToUpgradeExplanation2": "In addition to the standard NuGet/NPM upgrades, ABP CLI provides an update command that automatically finds and upgrades all ABP related packages in your solution.",
@@ -358,6 +358,25 @@
"WeWillSendYouADownloadLink": "A link to download the e-book has been sent to {0}. Check your inbox / junk / spam boxes!",
"InvalidFormInputs": "Please, type the valid information specified on the form.",
"DDDBookEmailBody": "Thank you. To download your book, click here.",
- "FreeDDDEBook": "Free DDD E-Book"
+ "FreeDDDEBook": "Free DDD E-Book",
+ "StartFree": "Start free",
+ "FreeTrial": "Free Trial",
+ "AcceptsMarketingCommunications": " Yes, I`d like to receive ABP Commercial marketing communications.",
+ "PurposeOfUsage": "Purpose of usage",
+ "Industry": "Industry",
+ "Choose": "- Choose -",
+ "CompanyOrganizationName": "Company / Organization Name",
+ "CompanySize": "Company Size",
+ "Next": "Next",
+ "StartTrial": "Start My Free Trial",
+ "ContactUsIssues": "Contact us if you have any issues",
+ "TrialActivatedWarning": "Dear {0}, a user is entitled to have only 1 free trial period. You already used your trial period.",
+ "ActivationRequirement": "You are one step away from starting your free trial. We have sent an email to {0} to activate your account. Check your inbox/junk/spam boxes!",
+ "SaveAndDownload": "Save And Download",
+ "CompanyNameValidationMessage": "Company name is too long!",
+ "AddressValidationMessage": "Address is too long!",
+ "TaxNoValidationMessage": "TAX/VAT No is too long!",
+ "NotesValidationMessage": "Notes field is too long!",
+ "CheckYourBillingInfo": "You can create your invoice only once! Check your billing information before creating your invoice."
}
}
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json
index 8de4891e99..8a0e6f22c1 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json
@@ -106,7 +106,7 @@
"DarkBlueTheme": "Tummansininen teema",
"LightTheme": "Kevyt teema",
"ProudToWorkWith": "Ylpeä työskennellä",
- "OurConsumers": "Sadat yritykset ja kehittäjät yli 50 maassa ympäri maailmaa luottavat ABP Commercialiin.",
+ "OurConsumers": "Sadat yritykset ja kehittäjät yli 70 maassa ympäri maailmaa luottavat ABP Commercialiin.",
"JoinOurConsumers": "Liity heihin ja rakenna upeita tuotteita nopeasti.",
"AdditionalServicesExplanation": "Tarvitsetko lisä- tai mukautettuja palveluita? Me ja kumppanimme voimme tarjota; ",
"CustomProjectDevelopment": "Mukautettu projektikehitys",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json
index e8f4165971..4db09019ed 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json
@@ -106,7 +106,7 @@
"DarkBlueTheme": "Thème bleu foncé",
"LightTheme": "Thème clair",
"ProudToWorkWith": "Fier de travailler avec",
- "OurConsumers": "Des centaines d'entreprises et de développeurs dans plus de 50 pays dans le monde font confiance à ABP Commercial.",
+ "OurConsumers": "Des centaines d'entreprises et de développeurs dans plus de 70 pays dans le monde font confiance à ABP Commercial.",
"JoinOurConsumers": "Rejoignez-les et créez rapidement des produits incroyables.",
"AdditionalServicesExplanation": "Avez-vous besoin de services supplémentaires ou personnalisés? Nous et nos partenaires pouvons fournir; ",
"CustomProjectDevelopment": "Développement de projets personnalisés",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json
index 4af2f31246..91158973d8 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json
@@ -106,7 +106,7 @@
"DarkBlueTheme": "डार्क ब्लू थीम",
"LightTheme": "प्रकाश थीम",
"ProudToWorkWith": "गर्व के साथ काम करने के लिए",
- "OurConsumers": "दुनिया भर में 50 से अधिक देशों के सैकड़ों उद्यम और डेवलपर्स एबीपी कमर्शियल पर निर्भर हैं।",
+ "OurConsumers": "दुनिया भर में 70 से अधिक देशों के सैकड़ों उद्यम और डेवलपर्स एबीपी कमर्शियल पर निर्भर हैं।",
"JoinOurConsumers": "उनके साथ जुड़ें और तेजी से अद्भुत उत्पादों का निर्माण करें।",
"AdditionalServicesExplanation": "क्या आपको अतिरिक्त या कस्टम सेवाओं की आवश्यकता है? हम और हमारे साथी प्रदान कर सकते हैं; ",
"CustomProjectDevelopment": "कस्टम परियोजना विकास",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json
index 722c10275f..ccb9f5ecd1 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json
@@ -106,7 +106,7 @@
"DarkBlueTheme": "Tema blu scuro",
"LightTheme": "Tema chiaro",
"ProudToWorkWith": "Orgoglioso di lavorare con",
- "OurConsumers": "Centinaia di aziende e sviluppatori in oltre 50 paesi in tutto il mondo si affidano a ABP Commercial.",
+ "OurConsumers": "Centinaia di aziende e sviluppatori in oltre 70 paesi in tutto il mondo si affidano a ABP Commercial.",
"JoinOurConsumers": "Unisciti a loro e crea prodotti sorprendenti velocemente.",
"AdditionalServicesExplanation": "Hai bisogno di servizi aggiuntivi o personalizzati? Noi e i nostri partner possiamo fornire; ",
"CustomProjectDevelopment": "Sviluppo di progetti personalizzati",
@@ -358,6 +358,25 @@
"WeWillSendYouADownloadLink": "Un link per scaricare il libro e-book è stato spedito a {0}. Controlla nella posta in arrivo / indesiderata / spam!",
"InvalidFormInputs": "Per favore, digita le informazioni valide specificate nel modulo",
"DDDBookEmailBody": "Grazie. Per scaricare il tuo libro, clicca qui.",
- "FreeDDDEBook": "E-Book Gratuito DDD"
+ "FreeDDDEBook": "E-Book Gratuito DDD",
+ "StartFree": "Inizia gratuitamente",
+ "FreeTrial": "Prova Gratuita",
+ "AcceptsMarketingCommunications": "Si desidero ricevere comunicazioni marketing riguardanti ABP Commercial",
+ "PurposeOfUsage": "Proposta di utilizzo",
+ "Industry": "Settore",
+ "Choose": "- Scegli -",
+ "CompanyOrganizationName": "Azienda / Nome organizzazione",
+ "CompanySize": "Dimensioni Azienda",
+ "Next": "Prossimo",
+ "StartTrial": "Inizia la mia prova gratuita",
+ "ContactUsIssues": "Contattaci per qualsiasi problema",
+ "TrialActivatedWarning": "Caro {0}, un utente ha diritto di avere 1 solo periodo di prova gratuito. Hai già utilizzato il tuo periodo di prova.",
+ "ActivationRequirement": "Ti manca un solo passo per iniziare il tuo periodo di prova gratuito. Abbiamo inviato un'email a {0} per attivare il tuo account. Controlla la tua casella di posta e non dimenticare la cartella spam!",
+ "SaveAndDownload": "Salva e Scarica",
+ "CompanyNameValidationMessage": "Il nome dell'azienda è troppo lungo!",
+ "AddressValidationMessage": "L'indirizzo è troppo lungo!",
+ "TaxNoValidationMessage": "TAX/VAT (IVA) è troppo lungo!",
+ "NotesValidationMessage": "Il campo note è troppo lungo!",
+ "CheckYourBillingInfo": "Puoi creare una fattura solo una volta! Controlla i tuoi dati di fatturazione prima di creare una fattura."
}
-}
\ No newline at end of file
+}
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json
new file mode 100644
index 0000000000..a88d581d36
--- /dev/null
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json
@@ -0,0 +1,363 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "OrganizationManagement": "Administrarea organizaţiilor",
+ "OrganizationList": "Lista organizaţiilor",
+ "Volo.AbpIo.Commercial:010003": "Nu sunteţi proprietarul acestei organizaţii!",
+ "OrganizationNotFoundMessage": "Nicio organizaţie găsită!",
+ "DeveloperCount": "Alocaţi / total dezvoltatori",
+ "QuestionCount": "Rămase / total întrebări",
+ "Unlimited": "Nelimitat",
+ "Owners": "Proprietari",
+ "AddMember": "Adaugă membru",
+ "AddOwner": "Adaugă proprietar",
+ "AddDeveloper": "Adaugă dezvoltator",
+ "UserName": "Nume utilizator",
+ "Name": "Nume",
+ "EmailAddress": "Adresă de email",
+ "Developers": "Dezvoltatori",
+ "LicenseType": "Tip licenţă",
+ "Manage": "Administrează",
+ "StartDate": "Data de început",
+ "EndDate": "Data de sfârşit",
+ "Modules": "Module",
+ "LicenseExtendMessage": "Data expirării licenţei dumneavoastră a fost prelungită până în {0}",
+ "LicenseUpgradeMessage": "Licenţa dumneavoastră a fost actualizată la {0}",
+ "LicenseAddDeveloperMessage": "{0} dezvoltatori au fost ataşaţi licenţei dumneavoastră",
+ "Volo.AbpIo.Commercial:010004": "Utilizatorul nu a putut fi găsit! Acesta trebuie să se fi înregistrat deja.",
+ "MyOrganizations": "Organizaţiile mele",
+ "ApiKey": "Cheie API",
+ "UserNameNotFound": "Nu există niciun utilizator cu numele {0}",
+ "SuccessfullyAddedToNewsletter": "Vă mulţumim pentru că v-aţi abonat la newsletter-ul nostru!",
+ "MyProfile": "Profilul meu",
+ "EmailNotValid": "Vă rugăm să introduceţi o adresa de email validă.",
+ "JoinOurMarketingNewsletter": "Alăturaţi-va newsletter-ului nostru de marketing",
+ "WouldLikeToReceiveMarketingMaterials": "Aş dori să primesc materiale de marketing precum oferte şi oferte speciale.",
+ "StartUsingYourLicenseNow": "Începe folosirea licenţei tale acum!",
+ "WelcomePage": "Pagina de bun venit",
+ "UnsubscriptionExpireEmail": "Dezabonează-te de la emailuri informative despre data expirării licenţei.",
+ "UnsubscribeLicenseExpireEmailReminderMessage": "Această abonament prin email conţine numai amintirea datei de expirare a licenţei.",
+ "UnsubscribeFromLicenseExpireEmails": "Dacă nu mai doriţi să primiţi emailuri informative despre data de expirare a licenţei dumneavoastră, puteţi să vă dezabonaţi oricând.",
+ "Unsubscribe": "Dezabonează-te",
+ "NotOrganizationMember": "Nu sunteţi membru al niciunei organizaţii.",
+ "UnsubscribeLicenseExpirationEmailSuccessTitle": "V-aţi dezabonat cu succes.",
+ "UnsubscribeLicenseExpirationEmailSuccessMessage": "Nu veţi mai primi emailuri informative despre data de expirare a licenţei dumneavoastră.",
+ "IndexPageHeroSection": "A complete web development platformbuilt-on framework",
+ "AbpCommercialShortDescription": "ABP Commercial oferă module de aplicaţii pre-construite, instrumente de dezvoltare rapidă a aplicaţiilor, teme UI profesionale, asistenţă premium şi multe altele.",
+ "LiveDemo": "Live Demo",
+ "GetLicence" :"Obţine o licenţă",
+ "Application": "Application",
+ "StartupTemplates": "Şabloane de lansare",
+ "Startup": "Lansare",
+ "Templates": "Şabloane",
+ "Developer": "Dezvoltator",
+ "Tools": "Unelte",
+ "Premium": "Premium",
+ "PremiumSupport": "Asistenţă Premium",
+ "PremiumForumSupport": "Forum asistenţă premium",
+ "UI": "UI",
+ "Themes": "Teme",
+ "JoinOurNewsletter": "Abonaţi-va newsletter-ului nostru",
+ "Send": "Trimite",
+ "Learn": "Învaţă",
+ "AdditionalServices": "Servicii suplimentare",
+ "WhatIsABPFramework": "CE ESTE FRAMEWORK-UL ABP?",
+ "OpenSourceBaseFramework": "Open Source Base Framework",
+ "ABPFrameworkExplanation": "
ABP Commercial se bazează pe framework-ul ABP, un framework open source şi bazat pe comunitate pentru ASP.NET Core.
ABP Framework oferă o infrastructură excelentă pentru a scrie cod care poate fi întreţinut, extins şi testat cu cele mai bune practici.
Construit şi integrat în instrumentele populare pe care le cunoaşteţi deja. Curbă de învăţare redusă, adaptare uşoară, dezvoltare confortabilă.
Construirea de aplicaţii web de nivel enterprise poate fi complexă şi poate consuma mult timp.
ABP Commercial oferă infrastructura de bază pentru toate soluţiile moderne bazate pe ASP.NET Core de nivel enterprise. De la proiectare până la implementare, întregul ciclu de dezvoltare este împuternicit de funcţiile şi modulele integrate ale ABP.
",
+ "StartupTemplatesShortDescription": "Şabloanele de pornire vă fac să începeţi proiectul în câteva secunde.",
+ "UIFrameworksOptions": "UI frameworks options;",
+ "DatabaseProviderOptions": "Opţiuni furnizor de bază de date;",
+ "PreBuiltApplicationModules": "Module de aplicaţii pre-construite",
+ "PreBuiltApplicationModulesShortDescription": "Cele mai comune cerinţe de aplicaţie sunt deja dezvoltate pentru dumneavoastră sub formă de module reutilizabile.",
+ "Account": "Cont",
+ "Blogging": "Blogging",
+ "Identity": "Identitate",
+ "IdentityServer": "Identity Server",
+ "Saas": "Saas",
+ "LanguageManagement": "Administrarea limbilor",
+ "TextTemplateManagement": "Text Template Management",
+ "SeeAllModules": "Vezi toate modulele",
+ "ABPSuite": "ABP Suite",
+ "AbpSuiteShortDescription": "ABP Suite este un instrument complementar pentru ABP Commercial.",
+ "AbpSuiteExplanation": "Vă permite să creaţi pagini web în câteva minute. Este un instrument .NET Core global, care poate fi instalat din linia de comandă. Poate crea o nouă soluţie ABP, poate genera pagini CRUD, începând de la baza de date până la front-end.",
+ "Details": "Detalii",
+ "LeptonTheme": "Tema Lepton",
+ "ProfessionalModernUIThemes": "Teme UI profesionale, moderne",
+ "LeptonThemeExplanation": "Lepton oferă o gamă de teme de administrare Bootstrap, care servesc ca o bază solidă pentru orice proiect care necesită tabloul de bord de administrare.",
+ "DefaultTheme": "Tema Default",
+ "MaterialTheme": "Tema Material",
+ "Default2Theme": "Tema Default 2",
+ "DarkTheme": "Tema Dark",
+ "DarkBlueTheme": "Tema Dark Blue",
+ "LightTheme": "Tema Light",
+ "ProudToWorkWith": "Mândru să lucrez cu",
+ "OurConsumers": "Sute de întreprinderi şi dezvoltatori din peste 70 de ţări din jurul lumii se bazează pe ABP Commercial.",
+ "JoinOurConsumers": "Alăturaţi-va lor şi construiţi produse uimitoare rapid.",
+ "AdditionalServicesExplanation": "Aveţi nevoie de servicii suplimentare sau personalizate? Noi şi partenerii noştri vi le putem oferi;",
+ "CustomProjectDevelopment": "Custom Project Development",
+ "CustomProjectDevelopmentExplanation": "Dezvoltatori dedicaţi pentru proiectele dumneavoastră personalizate.",
+ "PortingExistingProjects": "Portarea proiectelor existente",
+ "PortingExistingProjectsExplanation": "Migrarea proiectelor dumneavoastră vechi pe platforma ABP.",
+ "LiveSupport": "Asistenţă live",
+ "LiveSupportExplanation": "Opţiune de asistenţă live la distanţă oricând aveţi nevoie.",
+ "Training": "Instruire",
+ "TrainingExplanation": "Instruire dedicată pentru dezvoltatorii dumneavoastră.",
+ "OnBoarding": "Integrare",
+ "OnBoardingExplanation": "Ajutor pentru configurarea dezvoltării, mediilor CI & CD.",
+ "PrioritizedTechnicalSupport": "Asistenţă tehnică prioritară",
+ "PremiumSupportExplanation": "Pe lângă excelentul suport comunitar al framework-ului ABP, echipa noastră de asistenţă răspunde la întrebările tehnice şi la problemele utilizatorilor comerciali cu prioritate crescută.",
+ "SeeTheSupportOptions": "Vedeţi opţiunile de asistenţă",
+ "Contact": "Contact",
+ "TellUsWhatYouNeed": "Spuneţi-ne de ce aveţi nevoie.",
+ "YourMessage": "Mesajul dumneavoastră",
+ "YourFullName": "Numele dumneavoastră complet",
+ "EmailField": "Adresa de email",
+ "YourEmailAddress": "Adresa dumneavoastră de email",
+ "HowMayWeHelpYou": "Cum vă putem ajuta?",
+ "SendMessage": "Trimite mesaj",
+ "Success": "Succes",
+ "WeWillReplyYou": "Am primit mesajul dumneavoastră şi vă vom contacta cât de repede posibil.",
+ "GoHome": "Navigaţi acasă",
+ "CreateLiveDemo": "Crează Demo Live",
+ "RegisterToTheNewsletter": "Înregistraţi-va la newsletter pentru a primi informaţii despre ABP.IO, inclusiv lansări noi etc.",
+ "EnterYourEmailOrLogin": "Introduceţi-vă adresa de email pentru a vă crea demo-ul sau Autentificaţi-vă folosind contul existent.",
+ "ApplicationTemplate": "Application Template",
+ "ApplicationTemplateExplanation": "Şablonul de pornire a aplicaţiei este utilizat pentru a crea o nouă aplicaţie web.",
+ "EfCoreProvider": "Entity Framework (susţine SQL Server, MySQL, PostgreSQL, Oracle şi altele)",
+ "AlreadyIncludedInTemplateModules": "Următoarele module sunt deja incluse şi configurate în acest şablon:",
+ "ApplicationTemplateArchitecture": "Acest şablon de aplicaţie susţine arhitecturi structurate pe nivele, în care nivelul UI, nivelul API şi serviciul de autentificare sunt separate fizic.",
+ "SeeTheGuideOrGoToTheLiveDemo": "Consultaţi ghidul dezvoltatorului pentru informaţii tehnice despre acest şablon sau mergeţi la demo-ul live.",
+ "DeveloperGuide": "Ghidul dezvoltatorului",
+ "ModuleTemplate": "Module Template",
+ "ModuleTemplateExplanation1": "Vreţi să creaţi un modul pe care sa-l reutilizaţi în cadrul diferitelor aplicaţii? Acest şablon de pornire pregăteşte totul pentru a putea începe să creaţi un modul sau un microserviciu reutilizabil.",
+ "ModuleTemplateExplanation2": "
Puteţi susţine cadre UI simple sau multiple, furnizori unici sau multipli pentru baza de date pentru un singur modul. Şablonul de pornire este configurat pentru a rula şi testa modulul dumneavoastră într-o aplicaţie minimă, în plus faţă de infrastructura de testare şi integrare.
Consultaţi ghidul dezvoltatorului pentru informaţii tehnice despre acest şablon.
",
+ "WithAllStyleOptions": "cu toate opţiunile de stil",
+ "Demo": "Demo",
+ "SeeAllModules": "Vezi toate modulele",
+ "ABPCLIExplanation": "ABP CLI (Command Line Interface) este un instrument de linii de comandă pentru executarea unor operaţii comune pentru soluţiile ABP.",
+ "ABPSuiteEasilyCURD": "Suita ABP este un instrument care vă permite crearea cu uşurinţă a paginilor CRUD",
+ "WeAreHereToHelp": "Suntem aici să Ajutăm",
+ "BrowseOrAskQuestion": "Puteţi răsfoi subiectele noastre de ajutor sau puteţi căuta în cadrul secţiunii întrebărilor frecvent adresate, sau ne puteţi adresa o întrebare folosind formularul de contact.",
+ "SearchQuestionPlaceholder": "Caută în întrebările frecvent adresate",
+ "WhatIsTheABPCommercial": "Ce este ABP Commercial?",
+ "WhatAreDifferencesThanAbpFramework": "Care sunt diferenţele dintre ABP Framework şi ABP Comercial?",
+ "ABPCommercialExplanation": "ABP Commercial este un set de module premium, instrumente, teme şi servicii construite pe baza ABP framework. ABP Commercial este dezvoltat şi întreţinut de către aceeaşi echipă din spatele ABP framework.",
+ "WhatAreDifferencesThanABPFrameworkExplanation": "
ABP framework este un framework de dezvoltare de aplicaţii modulare, compatibil cu micro-servicii dedicate ASP.NET Core. Oferă o arhitectură completă şi o infrastructură puternică pentru a vă face să vă concentraţi asupra propriului cod, mai degrabă decât să vă repetaţi pentru fiecare proiect nou. Se bazează pe cele mai bune practici de dezvoltare software, şi pe instrumentele populare pe care le cunoaşteţi deja.
ABP Framework este complet gratuit, open-source şi bazat pe comunitate. De asemenea, oferă şi o temă gratuită şi câteva module pre-construite (de exemplu, gestionarea identităţii şi a chiriaşilor).
",
+ "VisitTheFrameworkVSCommercialDocument": "Accesaţi următorul link, pentru mai multe informaţii {1} ",
+ "ABPCommercialFollowingBenefits": "ABP Commercial adaugă următoarele beneficii peste framework-ul ABP;",
+ "Professional": "Profesional",
+ "UIThemes": "Teme UI",
+ "EnterpriseModules": "Module de aplicaţii pregătite pentru întreprinderi, bogate în funcţionalităţi, pre-construite (e.g. Identity Server management, SaaS management, language management)",
+ "ToolingToSupport": "Instrumente pentru a vă susţine productivitatea de dezvoltare (e.g. Suita ABP)",
+ "PremiumSupportLink": "Asistenţă premium",
+ "WhatDoIDownloadABPCommercial": "Ce descarc când cumpăr ABP Commercial?",
+ "CreateUnlimitedSolutions": "Odată ce aţi cumpărat o licenţă ABP Commercial, veţi putea să creaţi soluţii nelimitate, descrise în documentul Noţiuni de bază.",
+ "ABPCommercialSolutionExplanation": "Când creaţi o aplicaţie nouă, veţi primi o soluţie de Visual Studio (un şablon de pornire) bazat pe preferinţele dumneavoastră. Soluţia descărcată conţine module comerciale şi teme pre-instalate şi configurate pentru dumneavoastră. Puteţi şterge un modul pre-instalat sau să adăugaţi altul dacă doriţi. Toate modulele şi temele folosesc un pachet NuGet/NPM în mod implicit.",
+ "StartDevelopWithTutorials": "Soluţia descărcată este bine structurată şi documentată. Puteţi începe să vă dezvoltaţi codul dumneavoastră pe baza unuia dintre tutoriale",
+ "TryTheCommercialDemo": "Puteţi încerca versiunea demo pentru a vedea un exemplu de aplicaţie creată folosind şablonul de pornire ABP Commercial.",
+ "HowManyProducts": "Câte produse/soluţii diferite pot construi folosind ABP Commercial?",
+ "HowManyProductsExplanation": "Nu există nicio limită pentru crearea unui proiect ABP. Puteţi crea cât de multe proiecte doriţi, pe care să le dezvoltaţi sau încărcaţi pe diferite servere.",
+ "HowManyDevelopers": "Câţi dezvoltatori pot lucra pe ABP Commercial?",
+ "HowManyDevelopersExplanation": "Licenţele de ABP Commercial sunt per dezvoltator. Tipuri diferite de licenţă au limite diferite de dezvoltatori. Totuşi, puteţi ataşa mai mulţi dezvoltatori unei licenţe oricând doriţi. Consultaţi preţurile pentru tipurile de licenţă, limitele de dezvoltatori şi costurile adiţionale pentru dezvoltatori.",
+ "ChangingLicenseType": "Pe viitor pot să schimb tipul licenţei?",
+ "ChangingLicenseTypeExplanation": "Puteţi adăuga oricând noi dezvoltatori în licenţa dumneavoastră de acelaşi tip. Consultaţi \"Câţi dezvoltatori pot lucra pe ABP Commercial?\". De asemenea, puteţi opta pentru o licenţă superioară prin plătirea achitarea de preţ. Atunci când optaţi pentru o licenţă superioară, veţi avea parte de beneficiile noii licenţe, însă acest lucru nu va schimba data expirării licenţei.",
+ "LicenseExtendUpgradeDiff": "Care este diferenţa dintre prelungirea licenţei şi îmbunătăţirea acesteia?",
+ "LicenseExtendUpgradeDiffExplanation": "Prelungirea: Prin prelungirea/reînnoirea licenţei dumneavoastră, veţi continua să aveţi acces la asistenţă premium, şi veţi avea parte de actualizările majore ale modulelor şi temelor. Pe lângă asta, veţi putea în continuare să creaţi proiecte noi. Veţi putea folosi în continuare suita ABP, ceea ce va accelera dezvoltarea.Îmbunătăţirea: Prin îmbunătăţirea licenţei dumneavoastră, veţi promova la un plan de licenţă superior, care vă va permite să beneficiaţi de anumite avantaje. Consultaţi tabelul de comparare a licenţelor pentru a verifica diferenţele dintre planurile de licenţă.Pe de altă parte, când îmbunătăţiţi licenţa, data de expirare a acesteia nu se va schimba!Pentru a vă extinde data de încheiere a licenţei, va trebui să vă extindeţi licenţa.",
+ "LicenseRenewalCost": "Care este costul de reînnoire a licenţei dupa 1 an?",
+ "LicenseRenewalCostExplanation": "Rata de reînnoire (extindere) a tuturor licenţelor ABP Comercial reprezintă {0} din preţul listei licenţelor. Preţul de reînnoire a licenţei standard de echipă este de ${1}, cel pentru licenţa standard de afaceri este de ${2} iar cel pentru licenţa standard enterprise este de ${3}. Dacă deja sunteţi clientul nostru, autentificaţi-vă pentru a examina preţurile disponibile pentru reînnoire.",
+ "HowDoIRenewMyLicense": "Cum îmi reînnoiesc licenţa?",
+ "HowDoIRenewMyLicenseExplanation": "Puteţi să vă reînnoiţi licenţa prin accesarea paginii pagina de gestionare a organizaţiei. Pentru a profita de tarifele noastre reduse de reînnoire anticipată, asiguraţi-vă că reînnoiţi înainte de expirarea licenţei. Totuşi, nu vă faceţi griji dacă nu ştiţi când expiră oportunitatea dumneavoastră de reînnoire anticipată. Veţi primi 2 e-mailuri de reamintire înainte de expirarea abonamentului. Vi le vom trimite cu 30, respectiv 7 zile înainte de expirare.",
+ "IsSourceCodeIncluded": "Licenţa mea include şi codul sursă al modulelor comerciale şi a temelor?",
+ "IsSourceCodeIncludedExplanation1": "Depinde de tipul de licenţă pe care aţi achiziţionat-o:",
+ "IsSourceCodeIncludedExplanation2": "Team: Soluţia dumneavoastră foloseste modulele şi temele sub formă de pachete NuGet şi NPM. Nu include şi codul lor sursă. În acest mod, puteţi cu uşurinţă să îmbunătăţiţi aceste module şi teme oricând este o nouă versiune disponibilă. Totuşi, nu veţi primi codul sursă al modulelor şi temelor.",
+ "IsSourceCodeIncludedExplanation3": "Business/Enterprise: Pe lângă licenţa de tip Team, veţi putea să descărcaţi codul sursă al oricărui modul sau al oricărei teme doriţi. Puteţi chiar să eliminaţi referinţele pachetelor NuGet/NPM pentru un anume modul, şi să adăugaţi codul sursă al acestuia direct în soluţia dumneavoastră pentru a-l putea modifica pe deplin.",
+ "IsSourceCodeIncludedExplanation4": "
Includerea codului sursă al unui modul în soluţia dumneavoastră vă oferă libertate maximă de a personaliza modulul respectiv. Totuşi, atunci nu va fi posibilă actualizarea automată a modulului atunci când o nouă versiune este publicată.
Niciuna dintre licenţe nu include codul sursă al suitei ABP, care este un instrument extern care generează cod pentru dumneavoastră şi contribuie la dezvoltare.
Consultaţi preţurile pentru alte diferenţe între tipurile de licenţe.
",
+ "ChangingDevelopers": "Pe viitor, pot schimba dezvoltatorii ataşaţi organizaţiei mele?",
+ "ChangingDevelopersExplanation": "În plus faţă de adăugarea de noi dezvoltatori la licenţa dumneavoastră, puteţi schimba şi dezvoltatorii existenţi(puteţi elimina un dezvoltator şi adăuga unul nou în locul lui) fără costuri suplimentare.",
+ "WhatHappensWhenLicenseEnds": "Ce se întâmplă când se încheie perioada licenţei mele?",
+ "WhatHappensWhenLicenseEndsExplanation1": "Tipul de licenţă ABP Comercial este o licenţă perpetuă. După ce vă expiră licenţa, puteţi continua dezvoltarea proiectului dumneavoastră. Şi nu sunteţi obligat să vă reînnoiţi licenţa. Licenţa dumneavoastră vine la pachet cu actualizări şi plan de asistenţă valabile timp de un an. Pentru a continua să beneficiaţi de noi caracteristici, îmbunătăţiri de performanţe, corectarea erorilor, asistenţă şi să continuaţi să utilizaţi suita ABP, asiguraţi-vă că vă reînnoiţi licenţa anual. Când vă expiră licenţa, nu veţi mai beneficia de niciunul din beneficiile următoare;",
+ "WhatHappensWhenLicenseEndsExplanation2": "Nu puteţi crea noi soluţii folosind ABP Commercial, dar puteţi continua dezvoltarea aplicaţiilor existente oricând.",
+ "WhatHappensWhenLicenseEndsExplanation3": "You will be able to get updates for the modules and themes within your MAJOR version. For example; if you are using v3.2.0 of a module, you can still get updates for v3.x.x (v3.3.0, v3.5.2... etc.) of that module. But you cannot get updates for the next major version (like v4.x, v5.x)",
+ "WhatHappensWhenLicenseEndsExplanation4": "Nu puteţi instala noi module şi teme adăugate pe platforma ABP Comercial după ce se încheie licenţa dumneavoastră.",
+ "WhatHappensWhenLicenseEndsExplanation5": "Nu puteţi folosi suita ABP.",
+ "WhatHappensWhenLicenseEndsExplanation6": "Nu veţi mai avea parte de asistenţă premium.",
+ "WhatHappensWhenLicenseEndsExplanation7": "Puteţi să vă reînnoiţi abonamentul dacă vreţi să continuaţi să aveţi parte de aceste beneficii. Dacă vă reînnoiţi abonamentul în termen de o lună după ce vă expiră licenţa, vi se aplică un discount de 20%.",
+ "WhenShouldIRenewMyLicense": "Când ar trebui să-mi reînnoiesc licenţa?",
+ "WhenShouldIRenewMyLicenseExplanation1": "Dacă vă reînnoiţi licenţa în termen de 1 lună după ce vă expiră licenţa, se va aplica un discount de 20%.",
+ "WhenShouldIRenewMyLicenseExplanation2": "Dacă vă reînnoiţi licenţa la o lună după ce aceasta a expirat, preţul de reînnoire va fi acelaşi cu cel iniţial, şi nu va fi aplicat niciun discount pentru reînnoirea dumneavoastră.",
+ "TrialPlan": "Aveţi un plan de încercare?",
+ "TrialPlanExplanation": "Pentru moment, ABP Comercial nu include un plan de încercare. Pentru licenţa de Team oferim înapoirea banilor în termen de 30 de zile. Puteţi să solicitaţi o restituire în primele 30 de zile. Pentru licenţele de tip Business şi Enterprise, noi asigurăm restituirea a 60% din sumă în 30 de zile. Acest lucru se datorează faptului că licenţele de tip Business şi Enterprise includ codul sursă complet al tuturor modulelor şi temelor.",
+ "DoYouAcceptBankWireTransfer": "Acceptaţi transfer bancar?",
+ "DoYouAcceptBankWireTransferExplanation": "Da, acceptăm transfer bancar. După trimiterea taxei de licenţă prin transfer bancar, trimiteţi-ne pe e-mail la info@abp.io chitanţa dumneavoastră şi tipul de licenţă solicitat. Informaţiile despre contul bancar internaţional al nostru:",
+ "HowToUpgrade": "Cum se actualizează aplicaţiile existente atunci când este disponibilă o nouă versiune?",
+ "HowToUpgradeExplanation1": "Cand creaţi o nouă aplicaţie folosind ABP Commercial, toate modulele şi tema sunt folosite sub formă de pachete NuGet şi NPM. Astfel, puteţi cu uşurinţă să actualizaţi pachetele atunci când o versiune nouă este disponibilă.",
+ "HowToUpgradeExplanation2": "Pe lângă actualizările standard NuGet-NPM, ABP CLI furnizează o comandă de actualizare automată care identifică şi actualizează toate pachetele legate de ABP din soluţia dumneavoastră.",
+ "DatabaseSupport": "Ce sisteme de baze de date sunt suportate?",
+ "DatabaseSupportExplanation": "ABP Framework în sine este agnostic din punct de vedere al bazei de date, şi poate funcţiona cu orice furnizor de baze de date prin natura sa. Consultaţi documentul de acces la date pentru o listă a furnizorilor implementaţi până în clipa de faţă.",
+ "UISupport": "Ce UI frameworks sunt suportate?",
+ "Supported": "Suportat",
+ "UISupportExplanation": "ABP Framework în sine este agnostic din punct de vedere al UI framework şi poate funcţiona cu orice UI framework. Cu toate acestea, şabloanele de pornire, UI-urile modulelor şi temele nu au fost implementate pentru toate module UIs. Consultaţi documentul de început pentru lista actualizată a opţiunilor UI.",
+ "MicroserviceSupport": "Suportă arhitectura de micro-servicii?",
+ "MicroserviceSupportExplanation1": "Unul din scopurile principale ale ABP framework este să furnizeze o structură convenabilă pentru crearea soluţiilor micro-service. Consultaţi documentul arhitectura micro-service pentru a înţelege cum ajută la crearea sistemelor de micro-servicii.",
+ "MicroserviceSupportExplanation2": "Toate modulele ABP Commercial sunt dezvoltate pentru a suporta scenarii de implementare a micro-serviciilor (cu propriul API şi bază de date) prin respectarea celor mai bune practici de dezvoltare a modulelor.",
+ "MicroserviceSupportExplanation3": "Vă oferim soluţie demo de micro-servicii care demonstrează o implementare a arhitecturii de micro-servicii pentru a vă ajuta să vă creaţi propria soluţie.",
+ "MicroserviceSupportExplanation4": "Deci, răspunsul pe scurt este \"da, suportă o arhitectură de micro-service\".",
+ "MicroserviceSupportExplanation5": "Totuşi, un sistem de tip micro-service reprezintă o soluţie, şi fiecare soluţie va avea cerinţe diferite, topologie de reţea, scenarii de comunicare, posibilităţi de autentificare, separarea bazei de date/împărţirea deciziilor, configurări în timp real, integrări de sisteme terţe parte şi multe altele.",
+ "MicroserviceSupportExplanation6": "ABP Framework şi ABP Commercial furnizează infrastructura pentru scenarii de micro-servicii, module de micro-servicii compatibile, exemple şi documentaţie pentru a vă ajuta să vă construiţi propria soluţie. Dar nu vă aşteptaţi să descărcaţi direct soluţia visurilor dumneavoastră. Veţi fi nevoit(ă) să o întelegeţi şi să puneţi câteva piese cap la cap pe baza cerinţelor dumneavoastră.",
+ "WhereCanIDownloadSourceCode": "De unde pot descărca codul sursă?",
+ "WhereCanIDownloadSourceCodeExplanation": "Puteţi descărca codul sursă al tuturor modulelor ABP, pachetelor Angular şi al temelor prin suita ABP sau ABP CLI. Consultaţi Cum descarc codul sursă?",
+ "ComputerLimitation": "Pe câte calculatoare se poate autentifica un dezvoltator atunci când foloseşte ABP ABP?",
+ "ComputerLimitationExplanation": "Permitem în mod specific {0} staţii per dezvoltator individual/autorizat. Ori de câte ori este nevoie ca un dezvoltator să dezvolte produse ABP Commercial pe o altă staţie, un e-mail ar trebui să fie trimis la license@abp.io pentru a explica situaţia, şi atunci vom face alocarea corespunzătoare în sistemul nostru.",
+ "RefundPolicy": "Aveţi o politică de rambursare?",
+ "RefundPolicyExplanation": "Puteţi solicita un ramburs în decurs de 30 de zile de la cumpărarea licenţei. Licenţele de tip Business şi Enterprise au opţiune de descărcare a codului sursă, prin urmare rambursul nu este posibil pentru licenţele Business and Enterprise (şi pentru oricare altă licenţă care beneficiază de dreptul de a primi codul sursă). În plus, nu se fac rambursări pentru reînnoiri şi achiziţii de licenţe suplimentare.",
+ "HowCanIRefundVat": "Cum pot deduce TVA-ul?",
+ "HowCanIRefundVatExplanation1": "Dacă aţi făcut plata folosind 2Checkout, puteţi deduce TVA-ul în contul dumneavoastră 2Checkout:",
+ "HowCanIRefundVatExplanation2": "Autentificaţi-vă în contul dumneavoastră 2Checkout",
+ "HowCanIRefundVatExplanation3": "Găsiţi comanda respectivă şi apăsaţi pe \"Deducerea tardivă a TVA-ului \" (introduceţi CUI-ul dumneavoastră)",
+ "HowCanIGetMyInvoice": "Cum îmi pot obţine factura?",
+ "HowCanIGetMyInvoiceExplanation": "Există două procesatori de plăţi pentru cumpărarea unei licenţă: PayU şi 2Checkout. Dacă veţi cumpăra o licenţă prin procesatorul 2Checkout, vă va trimite chitanţa PDF pe adresa dumneavoastră de email, consultaţi facturarea 2Checkout. Dacă veţi cumpăra o licenţă prin procesatorul PayU gateway sau prin transfer bancar, vă vom pregăti chitanţa şi vă vom trimite. Puteţi solicita chitanţa dumneavoastră din pagina de gestionare a organizaţiei.",
+ "Forum": "Forum",
+ "SupportExplanation": "Licenţele ABP Commercial furnizează asistenţă premium pe forum din partea unei echipe alcătuite din experţi ai ABP.",
+ "PrivateTicket": "Tichet privat",
+ "PrivateTicketExplanation": "Licenţa de tip Enterprise include de asemenea şi asistenţă privată cu sisteme de e-mail şi tichete.",
+ "AbpSuiteExplanation1": "Suita ABP vă permite să construiţi pagini web în decurs de câteva minute. Este un instrument global .NET Core care poate fi instalat din linia de comandă.",
+ "AbpSuiteExplanation2": "Poate crea o nouă soluţie ABP, genera paginii CRUD începând de la baza de date şi până la front-end. Pentru o prezentare tehnică consultaţi documentul",
+ "FastEasy": "Rapid şi usor",
+ "AbpSuiteExplanation3": "Suita ABP vă permite să creaţi pagini CRUD cu uşurinţă. Trebuie doar să vă definiţi entitatea şi proprietăţile sale, şi să lăsaţi restul în seama suitei ABP! Suita ABP generează tot codul necesar pentru pagina dumneavoastră CRUD în câteva secunde. Suportă interfeţe de utilizator Angular, MVC şi Blazor.",
+ "RichOptions": "Opţiuni ample",
+ "AbpSuiteExplanation4": "Suita ABP suportă multiple opţiuni UI precum Pagini Razor şi Angular. Suportă de asemenea şi baze de date multiple, precum MongoDB şi toate bazele de date suportate de EntityFramework Core (MS SQL Server, Oracle, MySql, PostgreSQL şi altele).",
+ "AbpSuiteExplanation5": "Partea bună este că dumneavoastră nu trebuie să vă faceţi griji despre aceste opţiuni. Suita ABP înţelege tipul proiectului dumneavoastră şi generează cod pentru proiectul dumneavoastră şi îl plasează în locul potrivit din proiect.",
+ "SourceCode": "Cod sursă",
+ "AbpSuiteExplanation6": "Suita ABP generează codul sursă pentru dumneavoastră! Nu generează fişiere magice pentru a genera pagina web. Suita ABP generează codul sursă petnru Entity, Repository, Application Service, Code First Migration, JavaScript/TypeScript şi CSHTML/HTML şi interfeţele necesare de asemenea. Suita ABP generează de asemenea codul respectând Cele mai bune practici ale dezvoltării software, deci nu trebuie să vă faceţi griji în legătură cu calitatea codului generat.",
+ "AbpSuiteExplanation7": "Deoarece aveţi codul sursă al blocurilor de construcţie ale paginii CRUD generate în straturile de aplicaţie corecte, puteţi modifica cu uşurinţă codul sursă şi puteţi injecta logica personalizată/business a codului generat.",
+ "CrossPlatform": "Platformă transversală",
+ "AbpSuiteExplanation8": "Suita ABP este construită cu .NET Core şi este o platformă transversală. Se execută ca o aplicaţie web pe calculatorul dumneavoastră local. O puteţi rula pe Windows, Mac şi Linux",
+ "OtherFeatures": "Alte funcţionalităţi",
+ "OtherFeatures1": "Actualizeată pachetele NuGet şi NPM din soluţia dumneavoastră cu uşurinţă.",
+ "OtherFeatures2": "Regenerează paginile deja generate de la zero.",
+ "OtherFeatures3": "Crează noi soluţii",
+ "ThanksForCreatingProject": "Mulţumim pentru că v-aţi creat proiectul!",
+ "HotToRunSolution": "Cum să rulaţi soluţia dumneavoastră?",
+ "HotToRunSolutionExplanation": "Consultaţi documentul de noţiuni de bază pentru a învăţa cum să vă configuraţi şi rulaţi aplicaţia.",
+ "GettingStarted": "Noţiuni de bază",
+ "WebAppDevTutorial": "Tutorial Web App Dev",
+ "WebAppDevTutorialExplanation": "Consultaţi tutorialul de dezvoltare a aplicaţiilor web pentru un exemplu de dezvoltare pas cu pas.",
+ "Document": "Document",
+ "UsingABPSuiteToCURD": "Folosind suita ABp pentru generarea şi utilizarea paginilor CRUD",
+ "SeeABPSuiteDocument": "Consultaţi documentaţia suitei ABP pentru a învăţa utilizarea suitei ABP.",
+ "AskQuestionsOnSupport": "Puteţi adresa întrebări pe ABP Commercial Support.",
+ "Documentation": "Documentaţie",
+ "SeeModulesDocument": "Consultaţi documentul modulelor pentru lista tuturor modulelor comerciale (pro) şi documentele acestora.",
+ "Pricing": "Preţuri",
+ "PricingExplanation": "Alegeţi caracteristicile şi funcţionalitatea nevoilor afacerii dumneavoastră acum. Actualizaţi-le cu uşurinţă pe măsură ce afacerea dumneavoastră se dezvoltă.",
+ "Team": "Team",
+ "Business": "Business",
+ "Enterprise": "Enterprise",
+ "Custom": "Personalizat",
+ "IncludedDeveloperLicenses": "Licenţe de dezvoltator incluse",
+ "CustomLicenceOrAdditionalServices": "Aveţi nevoie de o licenţă personalizată sau de servicii suplimentare?",
+ "CustomOrVolumeLicense": "Licenţă personalizată sau de volum",
+ "LiveTrainingSupport": "Instruire şi asistenţă în timp real",
+ "AndMore": "şi multe altele",
+ "AdditionalDeveloperLicense": "Licenţă suplimentară de dezvoltator",
+ "ProjectCount": "Număr de proiecte",
+ "AllProModules": "Toate modulele pro",
+ "AllProThemes": "Toate temele pro",
+ "AllProStartupTemplates": "Toate şabloanele de pornire pro",
+ "SourceCodeOfAllModules": "Codul sursă al tuturor modulelor",
+ "SourceCodeOfAllThemes": "Codul sursă al tuturor temelor",
+ "PerpetualLicense": "Licenţă perpetuă",
+ "UnlimitedServerDeployment": "Implementări nelimitate a serverului",
+ "YearUpgrade": "actualizare de 1 an",
+ "YearPremiumForumSupport": "Asistenţă premium pe forum de 1 an",
+ "ForumSupportIncidentCountYear": "Asistenţă pe forum număr de incidente/an",
+ "PrivateTicketEmailSupport": "Tichet privat şi asistenţă pe email",
+ "BuyNow": "Cumpără acum",
+ "PayViaAmexCard": "Cum pot plăti folosind cardul meu AMEX?",
+ "PayViaAmexCardDescription": "Procesatorul implicit 'Iyzico' s-ar putea să refuze anumite carduri AMEX ca măsură de securitate. În acest caz, puteţi plăti prin procesatorul alternativ '2Checkout'.",
+ "ThankYou": "Vă mulţumim",
+ "InvalidReCaptchaErrorMessage": "A intervenit o eroare în verificarea reCAPTCHA. Vă rugăm să încercaţi din nou.",
+ "CompanyName": "Nume companie",
+ "YourCompanyName": "Numele companiei dumneavoastră",
+ "FirstName": "Nume",
+ "LastName": "Prenume",
+ "Optional": "Opţional",
+ "YourFirstName": "Numele dumneavoastră",
+ "YourLastName": "Prenumele dumneavoastră",
+ "SpecialOffer": "Ofertă specială",
+ "SpecialOfferMessage": "Grăbiţi-vă! Preţurile sunt disponibile pentru o perioadă limitată.",
+ "DiscountRequest": "Cerere de discount",
+ "DiscountRequestDescribeCustomerQuestion": "Care din următoarele vă descrie?",
+ "DiscountRequestStudentEmailMessage": "Adresa de email trebuie să conţină 'edu'.",
+ "DiscountRequestDeveloperCount": "Câţi dezvoltatori aveţi?",
+ "DiscountRequestDeveloperCountExceedMessage": "Nu furnizăm licenţe reduse pentru companii care au peste {0} dezvoltatori.",
+ "DiscountRequestOrganizationName": "Numele companiei/organizaţiei/şcolii",
+ "Website": "Site web",
+ "GithubUsername": "Nume de utilizator GitHub",
+ "PhoneNumber": "Număr de telefon",
+ "Country": "Ţara",
+ "DescribeABPCommercialUsage": "Descrieţi proiectul pe care folosiţi să-l dezvoltaţi pe baza APB Commercial",
+ "DiscountRequestCertifyInformationMessage": "Certific că toate informaţiile sunt adevărate şi corecte.",
+ "DiscountRequestReceived": "Am primit solicitarea dumneavoastră de reducere.",
+ "DiscountRequestStatusMessage": "Vă vom răspunde după verificarea informaţiilor pe care le-aţi furnizat.",
+ "MVCOrRazorPages": "MVC (Razor Pages)",
+ "Angular": "Angular",
+ "Blazor": "Blazor",
+ "New": "New",
+ "MongoDB": "MongoDB",
+ "EBookDDD": "E-Book Domain Driven Design",
+ "PracticalGuideForImplementingDDD": "Această carte reprezintă un ghid practic pentru implementarea proiectării bazate pe domeniu în ABP Framework.",
+ "IntroducingDDD": "Introducing Domain Driven Design",
+ "DDDLayersAndCleanArchitecture": "DDD Layers & Clean Architecture",
+ "LayeringOfADotnetSolution": "Layering of a .NET Solution",
+ "ImplementingDDDBuildingBlocks": "Implementing DDD Building Blocks",
+ "DomainVsApplicationLogic": "Domain Logic vs Application Logic",
+ "SamplesAndDiscussions": "Exemple & Discuţii",
+ "Free": "Gratuit",
+ "Download": "Descarcă",
+ "DDDEBook": "DDD E-book",
+ "ImplementingDDD": "Implementing Domain Driven Design",
+ "DDDBookExplanation": "Ghid practic pentru implementarea proiectării bazate pe domeniu în ABP Framework.",
+ "Overview": "Prezentare generală",
+ "DDDBookPracticalGuide": "Acesta este un ghid practic pentru implementarea proiectării bazate pe domeniu (PBD). În timp ce detaliile de implementare se bazeată pe infrastructura ABP, conceptele de bază, principiile şi modelele sunt aplicabile în orice fel de soluţie, chiar dacă nu este o soluţie .NET.",
+ "TableOfContents": "Cuprins",
+ "IntroductionToImplementingDDD": "Introducere în implementarea proiectării bazate pe domeniu",
+ "WhatIsDDD": "Ce este proiectarea bazată pe domeniu?",
+ "Implementation": "Implementare",
+ "TheBigPicture": "Imaginea de ansamblu",
+ "TheBuildingBlock": "The Building Block",
+ "ExampleUseCase": "Exemplu de utilizare",
+ "DomainAndApplicationLogic": "Domain Logic & Application Logic",
+ "Author": "Autor",
+ "PublishedOn": "Publicat în",
+ "Page": "Pagina",
+ "FreeEBook": "E-Book gratuit",
+ "EBookSignInForDownload": "Pentru a descărca e-book-ul trebuie să vă autentificaţi",
+ "SignIn": "Autentificare",
+ "Or": "Sau",
+ "TellUsAboutYourself": "Spuneţi-ne despre dumneavoastră",
+ "Surname": "Nume",
+ "DoYouAgreePrivacyPolicy": "Sunt de acord cu Termenii şi condiţiile şi Politica de confidenţialitate.",
+ "VolosoftMarketingInformationMessage": "Sunt de acord să primesc informaţii, sfaturi şi oferte despre soluţii pentru afaceri şi organizaţii şi alte produse şi servicii Volosoft.",
+ "VolosoftSharingInformationMessage": "Sunt de acord ca Volosoft să partajeze informaţiile mele cu partenerii selectaţi astfel încât să primesc informaţii relevante despre produsele şi serviciile lor.",
+ "WeWillSendYouADownloadLink": "Un link pentru descărcarea e-book-ului a fost trimis către {0}. Verificaţi-vă căsuţele de inbox / junk / spam!",
+ "InvalidFormInputs": "Vă rugăm să introduceţi informaţia validă specificată în formular.",
+ "DDDBookEmailBody": "Vă mulţumim. Pentru a descărca e-book-ul, click aici.",
+ "FreeDDDEBook": "DDD E-Book gratuit"
+ }
+}
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json
index 7e2143a9af..4b160bdb70 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json
@@ -106,7 +106,7 @@
"DarkBlueTheme": "Tmavomodrá téma",
"LightTheme": "Téma Light",
"ProudToWorkWith": "Hrdo spolupracujeme s",
- "OurConsumers": "Na ABP Commercial sa spoliehajú stovky podnikov a vývojárov vo viac ako 50 krajinách sveta.",
+ "OurConsumers": "Na ABP Commercial sa spoliehajú stovky podnikov a vývojárov vo viac ako 70 krajinách sveta.",
"JoinOurConsumers": "Pridajte sa k nim a jednoducho vytvorte úžasné produkty.",
"AdditionalServicesExplanation": "Potrebujete ďalšie alebo vlastné služby? My a naši partneri vám ich môžeme poskytnúť;",
"CustomProjectDevelopment": "Vývoj projektu na mieru",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
index 5f99be6ba8..ac5e247264 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
@@ -106,7 +106,7 @@
"DarkBlueTheme": "深蓝主题",
"LightTheme": "浅色主题",
"ProudToWorkWith": "荣幸与你合作",
- "OurConsumers": "全球50多个国家的数百家企业和开发商使用ABP商业版.",
+ "OurConsumers": "全球70多个国家的数百家企业和开发商使用ABP商业版.",
"JoinOurConsumers": "加它他们并快速构建令人惊叹的产品.",
"AdditionalServicesExplanation": "你是否需要额外或自定义的服务? 我们和我们的合作伙伴可以提供;",
"CustomProjectDevelopment": "自定义项目开发",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json
index a676aa9124..80fed13066 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json
@@ -104,7 +104,7 @@
"DarkBlueTheme": "深藍主題",
"LightTheme": "淺色主題",
"ProudToWorkWith": "榮幸與你合作",
- "OurConsumers": "全球50多個國家的數百家企業和開發商使用ABP商業版.",
+ "OurConsumers": "全球70多個國家的數百家企業和開發商使用ABP商業版.",
"JoinOurConsumers": "加它他們並快速構建令人驚嘆的產品.",
"AdditionalServicesExplanation": "你是否需要額外或自定義的服務? 我們和我們的合作夥伴可以提供;",
"CustomProjectDevelopment": "自定義項目開發",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json
new file mode 100644
index 0000000000..7b93754482
--- /dev/null
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json
@@ -0,0 +1,147 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "Permission:CommunityArticle": "Articol comunitar",
+ "Permission:Edit": "Modifică",
+ "Waiting": "În aşteptare",
+ "Approved": "Aprobat",
+ "Rejected": "Respins",
+ "Wait": "Pune în aşteptare",
+ "Approve": "Aprobă",
+ "Reject": "Respinge",
+ "ReadArticle": "Citeşte articolul",
+ "Status": "Starea",
+ "ContentSource": "Sursa conţinutului",
+ "Details": "Detalii",
+ "Url": "Url",
+ "Title": "Titlu",
+ "CreationTime": "Data creării",
+ "Save": "Salvează",
+ "SameUrlAlreadyExist": "Dacă doriţi să adăugaţi acest articol, ar trebui să schimbaţi adresa Url, întrucât aceeaşi adresa url există deja!",
+ "UrlIsNotValid": "Url-ul nu este valid.",
+ "UrlNotFound" : "Url nu a fost găsit.",
+ "UrlContentNotFound": "Conţinutul url-ului nu a fost găsit.",
+ "Summary": "Rezumat",
+ "MostRead": "Cele mai citite",
+ "Latest": "Recente",
+ "ContributeAbpCommunity": "Contribuiţi la comunitatea ABP",
+ "SubmitYourArticle": "Trimiteţi-vă postul",
+ "ContributionGuide": "Ghid de contribuţie",
+ "BugReport": "Raportează eroare",
+ "SeeAllArticles": "Vezi toate postările",
+ "WelcomeToABPCommunity!": "Bun venit în comunitatea ABP!",
+ "MyProfile": "Profilul meu",
+ "MyOrganizations": "Organizaţia mea",
+ "EmailNotValid": "Vă rugăm să introduceţi o adresa de email validă.",
+ "FeatureRequest": "Cerere de funcţionalitate",
+ "CreateArticleTitleInfo": "Titlul postării care va apărea în lista postărilor.",
+ "CreateArticleSummaryInfo": "Un scurt rezumat al postării care va apărea în lista postărilor.",
+ "CreateArticleCoverInfo": "Pentru crearea unei postări eficace, adăugaţi o poză de copertă. Încărcaţi imagini cu raport de aspect 16:9 pentru cea mai bună vizualizare. Dimensiunea maximă a fişierului: 1MB.",
+ "ThisExtensionIsNotAllowed": "Această extensie nu este permisă.",
+ "TheFileIsTooLarge": "Dimensiunea fişierului este prea mare.",
+ "GoToTheArticle": "Vezi articolul",
+ "Contribute": "Contribuie",
+ "OverallProgress": "Progres total",
+ "Done": "Gata",
+ "Open": "Deschide",
+ "Closed": "Închis",
+ "LatestQuestionOnThe": "Ultima întrebare de pe",
+ "Stackoverflow": "Stackoverflow",
+ "Votes": "voturi",
+ "Answer": "Răspunde",
+ "Views": "vizualizări",
+ "Answered": "Răspunse",
+ "WaitingForYourAnswer": "În aşteptarea răspunsului dumneavoastră",
+ "Asked": "întrebate",
+ "AllQuestions": "Toate întrebările",
+ "NextVersion": "Următoarea versiune",
+ "MilestoneErrorMessage": "Nu s-au putut obţine detaliile de referinţă actuale de pe Github.",
+ "QuestionItemErrorMessage": "Nu s-au putut obţine detaliile de referinţă actuale de pe Stackoverflow.",
+ "Oops": "Oops!",
+ "CreateArticleSuccessMessage": "Articolul a fost trimis cu succes. Va fi publicat după ce va fi revizuit de un administrator al site-ului.",
+ "ChooseCoverImage": "Alegeţi o poză de copertă...",
+ "CoverImage": "Poză de copertă",
+ "ShareYourExperiencesWithTheABPFramework": "Împărtăşiţi-vă experienţele cu ABP Framework!",
+ "Optional": "Opţional",
+ "UpdateUserWebSiteInfo": "Exemplu: https://johndoe.com",
+ "UpdateUserTwitterInfo": "Exemplu: johndoe",
+ "UpdateUserGithubInfo": "Exemplu: johndoe",
+ "UpdateUserLinkedinInfo": "Exemplu: https://www.linkedin.com/...",
+ "UpdateUserCompanyInfo": "Exemplu: Volosoft",
+ "UpdateUserJobTitleInfo": "Exemplu: Software Developer",
+ "UserName": "Nume de utilizator",
+ "Company": "Companie",
+ "PersonalWebsite": "Site web personal",
+ "RegistrationDate": "Data înregistrării",
+ "Social": "Social",
+ "Biography": "Biografie",
+ "HasNoPublishedArticlesYet": "nu a publicat niciun articol încă",
+ "Author": "Autor",
+ "LatestGithubAnnouncements": "Ultimele anunţuri de pe Github",
+ "SeeAllAnnouncements": "Vezi toate anunţurile",
+ "LatestBlogPost": "Ultima postare de pe blog",
+ "Edit": "Modifică",
+ "ProfileImageChange": "Schimbă poza de profil",
+ "BlogItemErrorMessage": "Nu s-au putut obţine detaliile ultimei postări de pe from ABP.",
+ "PlannedReleaseDate": "Data planificată de lansare",
+ "CommunityArticleRequestErrorMessage": "Nu s-a putut obţine ultima cerere de articol de pe Github.",
+ "ArticleRequestFromGithubIssue": "Momentan nu există cereri de articole.",
+ "LatestArticles": "Ultimele postări",
+ "ArticleRequests": "Cereri de articole",
+ "AllArticleRequests": "Vedeţi toate cererile de articole",
+ "SubscribeToTheNewsletter": "Abonaţi-vă la newsletter-ul nostru",
+ "NewsletterEmailDefinition": "Obţineţi informaţii despre evenimentele din ABP, cum ar fi lansări noi, surse gratuite, articole şi multe altele.",
+ "NoThanks": "Nu, mulţumesc",
+ "MaybeLater": "Poate mai târziu",
+ "JoinOurArticleNewsletter": "Abonaţi-vă la newsletter-ul nostru de articole",
+ "Community": "Comunitate",
+ "Marketing": "Marketing",
+ "CommunityPrivacyPolicyConfirmation": "Sunt de acord cu termenii şi condiţiile şi politica de confidenţialitate.",
+ "ArticleRequestMessageTitle": "Deschideţi o problemă pe GitHub pentru a solicita un articol/tutorial pe care doriţi să îl vedeţi pe acest site web.",
+ "ArticleRequestMessageBody": "Aici, lista articolelor solicitate de către comunitate. Doriţi să scrieţi un articol solicitat? Vă rugăm să daţi click pe cerere şi să vă alăturaţi discuţiei.",
+ "Language": "Limba",
+ "CreateArticleLanguageInfo": "Limba pentru conţinutul postării.",
+ "VideoPost": "Post video",
+ "Article": "Articol",
+ "Read": "Citeşte",
+ "CreateGithubArticleUrlInfo": "Adresa URL originală GitHub a articolului.",
+ "CreateVideoContentUrlInfo": "Adresa URL originală YouTube a articolului",
+ "CreateExternalArticleUrlInfo": "Adresa URL originală externă a articolului.",
+ "VideoContentForm": "Trimite videoclip pe YouTube",
+ "GithubPostForm": "Trimite articol pe GitHub",
+ "ExternalPostForm": "Trimite un conţinut extern",
+ "HowToPost": "Cum postez?",
+ "Posts": "Postări",
+ "VideoUrl": "Url Video",
+ "GithubArticleUrl": "Adresa Url articol Github",
+ "ExternalArticleUrl": "Adresa Url externă Article",
+ "CreatePostCoverInfo": "Pentru crearea unei postări eficace, adăugaţi o poză de copertă. Încărcaţi imagini cu raport de aspect 16:9 pentru cea mai bună vizualizare. Dimensiunea maximă a fişierului: 1MB.",
+ "ThankYouForContribution": "Vă mulţumim pentru că aţi contribuit la comunitatea ABP.",
+ "GithubArticle": "Articol GitHub",
+ "GithubArticleSubmitStepOne": "1. Scrieţi un articol pe orice repository GitHub folosind formatul Markup. exemplu",
+ "GithubArticleSubmitStepTwo": "2. Trimiteţi Url-ul articolului folosind formularul.",
+ "GithubArticleSubmitStepThree": "3. Articolul dumneavoastră va fi redat în acest site web.",
+ "YoutubeVideo": "Videoclip YouTube",
+ "YoutubeVideoSubmitStepOne": "1. Publicaţi-vă videoclipul pe YouTube.",
+ "YoutubeVideoSubmitStepTwo": "2. Trimieţi Url-ul videoclipului folosind formularul.",
+ "YoutubeVideoSubmitStepThree": "3. Vizitatorii vor putea să vă vizioneze conţinutul video direct de pe acest site web.",
+ "ExternalContent": "Conţinut extern",
+ "ExternalContentSubmitStepOne": "1. Creaţi conţinut pe orice platformă publică (mediu, blogul dumneavoastră sau oriunde doriţi).",
+ "ExternalContentSubmitStepTwo": "2. Trimiteţi-vă conţinutul URL folosind formularul.",
+ "ExternalContentSubmitStepThree": "3. Vizitatorii sunt redirecţionaţi către conţinutul de pe site-ul web original.",
+ "ChooseYourContentType": "Vă rugăm să alegeţi modalitatea pri ncare vreţi să vă adăugaţi conţinutul.",
+ "PostContentViaGithub": "Vreau să adaug articolul meu de pe GitHub conform cu regulile de reducere.",
+ "PostContentViaYoutube": "Vreau să distribui videoclipurile mele disponibile de pe YouTube aici.",
+ "PostContentViaExternalSource": "Vreau să adaug conţinutul pe care l-am publicat pe altă platformă aici.",
+ "GitHubUserNameValidationMessage": "Numele de utilizator al contului dumneavoastră de GitHub nu poate conţine spaţii goale, vă rugăm să verificaţi că numele de utilizator al contului dumneavoastră de GitHub este corect.",
+ "PersonalSiteUrlValidationMessage": "Url-ul site-ului dumneavoastră personal nu poate conţine spaţii goale, vă rugăm să verificaţi ca Url-ul site-ului dumneavoastră personal este corect.",
+ "TwitterUserNameValidationMessage": "Url-ul dumneavoastră de Twitter nu poate conţine spaţii goale, vă rugăm să verificaţi ca Url-ul de Twitter este corect.",
+ "LinkedinUrlValidationMessage": "Url-ul dumneavoastră de LinkedIn nu poate conţine spaţii goale, vă rugăm să verificaţi ca Url-ul de LinkedIn este corect.",
+ "NoPostsFound": "Nu s-au găsit postări!",
+ "SearchInPosts": "Caută în postări...",
+ "MinimumSearchContent": "Trebuie să introduceţi cel putin 3 caractere!",
+ "Volo.AbpIo.Domain:060001": "Sursa URL(\"{ArticleUrl}\") nu este URL GitHub",
+ "Volo.AbpIo.Domain:060002": "Conţinutul articolului nu este disponibil din resursa de pe GitHub(\"{ArticleUrl}\").",
+ "Volo.AbpIo.Domain:060003": "Nu a fost găsit conţinutul articolului!"
+ }
+}
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/ro-RO.json
new file mode 100644
index 0000000000..c5a76c1617
--- /dev/null
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/ro-RO.json
@@ -0,0 +1,5 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ }
+}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/ro-RO.json
new file mode 100644
index 0000000000..c5a76c1617
--- /dev/null
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/ro-RO.json
@@ -0,0 +1,5 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ }
+}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json
new file mode 100644
index 0000000000..8115eed091
--- /dev/null
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json
@@ -0,0 +1,278 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "GetStarted": "Începeţi - Şabloane de pornire",
+ "Create": "Creează",
+ "NewProject": "Proiect nou",
+ "DirectDownload": "Descărcare directă",
+ "ProjectName": "Nume proiect",
+ "ProjectType": "Tip proiect",
+ "DatabaseProvider": "Provider bază de date",
+ "DatabaseManagementSystem": "Sistem de administrare bază de date",
+ "NTier": "N-Tier",
+ "IncludeUserInterface": "Include interfaţa userului",
+ "CreateNow": "Creează acum",
+ "TheStartupProject": "Proiectul de pornire",
+ "Tutorial": "Tutorial",
+ "UsingCLI": "Folosind CLI",
+ "SeeDetails": "Vedeţi detalii",
+ "AbpShortDescription": "ABP Framework este o infrastructură completă pentru crearea aplicaţiilor moderne web prin folosirea celor mai bune practici şi convenţii de dezvoltare software.",
+ "SourceCodeUpper": "COD SURSĂ",
+ "LatestReleaseLogs": "Cele mai recente jurnale de lansare",
+ "Infrastructure": "Infrastructura",
+ "Architecture": "Arhitectura",
+ "Modular": "Modular",
+ "DontRepeatYourself": "Nu vă repetaţi",
+ "DeveloperFocused": "Axat pe dezvoltator",
+ "FullStackApplicationInfrastructure": "Infrastructură de aplicaţii full stack.",
+ "DomainDrivenDesign": "Domain Driven Design",
+ "DomainDrivenDesignExplanation": "Proiectat şi dezvoltat pe baza modelelor şi principiilor DDD. Oferă un model stratificat pentru aplicaţia dumneavoastră.",
+ "Authorization": "Autorizare",
+ "AuthorizationExplanation": "Autorizare avansată pe bază de utilizator, rol şi sistem de permisiuni. Construit pe biblioteca Microsoft Identity.",
+ "MultiTenancy": "Multi-Tenancz",
+ "MultiTenancyExplanationShort": "Aplicaţii SaaS simplificate! Multi-Tenancy integrată de la baza de date până la UI.",
+ "CrossCuttingConcerns": "Cross Cutting Concerns",
+ "CrossCuttingConcernsExplanationShort": "Infrastructură completă pentru autorizare, validare, gestionarea excepţiilor, stocarea în cache, înregistrarea auditului, gestionarea tranzacţiilor şi multe altele.",
+ "BuiltInBundlingMinification": "Grupare şi minificare incorporate",
+ "BuiltInBundlingMinificationExplanation": "Nu este nevoie să utilizaţi instrumente externe pentru grupare şi minificare. ABP oferă un mod mai simplu, dinamic, puternic, modular şi incorporat!",
+ "VirtualFileSystem": "Sistem de fişiere virtuale",
+ "VirtualFileSystemExplanation": "Încorporaţi view-uri, scripturi, stiluri, imagini... in pachete/librării şi refolosiţi-le în diferite aplicaţii.",
+ "Theming": "Tematică",
+ "ThemingExplanationShort": "Utilizaţi şi personalizaţi tema UI standard, bazată pe UI, sau creaţi-o pe a dumneavoastră.",
+ "BootstrapTagHelpersDynamicForms": "Bootstrap Tag Helpers & Dynamic Forms",
+ "BootstrapTagHelpersDynamicFormsExplanation": "În loc să scrieţi manual detaliile repetate ale componentelor bootstrap, utilizaţi tag helperele ABP pentru a simplifica şi profita de inteligenţă. Construiţi rapid formulare de interfaţă bazate pe un model C# utilizând ajutorul pentru formulare dinamice.",
+ "HTTPAPIsDynamicProxies": "HTTP APIs & Dynamic Proxies",
+ "HTTPAPIsDynamicProxiesExplanation": "Expuneţi automat serviciile aplicaţiilor sub formă de API-uri HTTP şi folosiţi-le cu JavaScript dinamic si proxy C#.",
+ "CompleteArchitectureInfo": "Arhitectură modernă pentru a crea soluţii software care pot fi întreţinute.",
+ "DomainDrivenDesignBasedLayeringModelExplanation": "Vă ajută să implementaţi o arhitectură stratificată DDD şi să construiţi o bază de cod uşor de întreţinut.",
+ "DomainDrivenDesignBasedLayeringModelExplanationCont": "Oferă şabloane de pornire, abstractizări, clase de bază, servicii, documentaţie şi ghiduri pentru a vă ajuta să vă dezvoltaţi aplicaţia bazându-vă pe principiile şi tiparele DDD.",
+ "MicroserviceCompatibleModelExplanation": "Framework-ul de bază şi modulele pre-construite sunt proiectate având în vedere arhitectura microservice.",
+ "MicroserviceCompatibleModelExplanationCont": "Oferă infrastructură, integrări, exemple şi documentaţie pentru a implementa mai uşor soluţiile de microservicii, în timp ce nu aduce complexitate suplimentară dacă doriţi o aplicaţie monolitică.",
+ "ModularInfo": "ABP oferă un sistem de module care vă permite să dezvoltaţi module de aplicaţie reutilizabile, să vă conectaţi la evenimentele din ciclul de viaţă ale aplicaţiei şi să exprimaţi dependenţe între părţile centrale ale sistemului dumneavoastră.",
+ "PreBuiltModulesThemes": "Module şi teme pro-construite.",
+ "PreBuiltModulesThemesExplanation": "Modulele şi temele open source sunt gata de utilizare în aplicaţia dumneavoastră.",
+ "NuGetNPMPackages": "Pachete NuGet & NPM",
+ "NuGetNPMPackagesExplanation": "Distribuite sub formă de pachete NuGet & NPM. Uşor de instalat şi actualizat.",
+ "ExtensibleReplaceable": "Extensibil/Înlocuibil",
+ "ExtensibleReplaceableExplanation": "Toate serviciile şi modulele sunt dezvoltate pentru extensibilitate. Puteţi înlocui servicii, pagini, stiluri şi componente.",
+ "CrossCuttingConcernsExplanation2": "Menţineţi baza codului redusă, astfel încât să vă puteţi concentra asupra codului care e specific afacerii dumneavoastră.",
+ "CrossCuttingConcernsExplanation3": "Nu pierdeţi timp implementând cerinţe comune de aplicaţie pentru mai multe proiecte.",
+ "AuthenticationAuthorization": "Autentificare & Autorizare",
+ "ExceptionHandling": "Tratarea excepţiilor",
+ "Validation": "Validare",
+ "DatabaseConnection": "Conectare la baza de date",
+ "TransactionManagement": "Administrarea tranzacţiilor",
+ "AuditLogging": "Audit Logging",
+ "Caching": "Caching",
+ "Multitenancy": "Multitenancy",
+ "DataFiltering": "Filtrarea datelor",
+ "ConventionOverConfiguration": "Convention Over Configuration",
+ "ConventionOverConfigurationExplanation": "ABP implementează convenţii de aplicaţii comune în mod implicit, cu o configuraţie minimă sau zero.",
+ "ConventionOverConfigurationExplanationList1": "Auto înregistrează serviciile cunoscute pentru injectarea dependinţei..",
+ "ConventionOverConfigurationExplanationList2": "Expune serviciile aplicaţiei ca API-uri HTTP prin convenţii de denumire.",
+ "ConventionOverConfigurationExplanationList3": "Creează proxy-uri dinamice HTTP client pentru C# şi JavaScript.",
+ "ConventionOverConfigurationExplanationList4": "Oferă repository-uri implicite pentru entităţile dumneavoastră.",
+ "ConventionOverConfigurationExplanationList5": "Gestionează unitatea de lucru pe request web sau metodă de serviciu a aplicaţiei.",
+ "ConventionOverConfigurationExplanationList6": "Publică crearea, actualizarea şi ştergerea evenimentelor pentru entităţile dumneavoastră.",
+ "BaseClasses": "Clase de bază",
+ "BaseClassesExplanation": "Clase de bază pre-construite pentru tipare comune de aplicaţie.",
+ "DeveloperFocusedExplanation": "ABP este pentru dezvoltatori.",
+ "DeveloperFocusedExplanationCont": "Aceasta îşi propune să vă simplifice dezvoltarea zilnică de software, fără a vă restricţiona să scrieţi cod de nivel scăzut.",
+ "SeeAllFeatures": "Vedeţi toate funcţionalităţile",
+ "CLI_CommandLineInterface": "CLI (Command Line Interface)",
+ "CLI_CommandLineInterfaceExplanation": "Include un CLI pentru a vă ajuta să automatizaţi crearea de noi proiecte şi adăugarea de noi module.",
+ "StartupTemplates": "Proiecte de lansare",
+ "StartupTemplatesExplanation": "Diverse proiecte de lansare furnizează o soluţie complet configurată pentru a vă începe dezvoltarea.",
+ "BasedOnFamiliarTools": "Bazat pe instrumente familiare",
+ "BasedOnFamiliarToolsExplanation": "Construit şi integrat cu instrumente populare pe care le ştiţi deja. Curbă de învăţare joasă, adaptare uşoară, dezvoltare confortabilă.",
+ "ORMIndependent": "ORM Independent",
+ "ORMIndependentExplanation": "Framework-ul de bază este independent de ORM/bază de date şi poate funcţiona cu orice sursă de date. Furnizorii Entity Framework Core şi MongoDB sunt deja disponibili.",
+ "Features": "Exploraţi caracteristicile framework-ului ABP Framework",
+ "ABPCLI": "ABP CLI",
+ "Modularity": "Modularitate",
+ "BootstrapTagHelpers": "Bootstrap Tag Helpers",
+ "DynamicForms": "Formulare dinamice",
+ "BundlingMinification": "Grupare & Minificare",
+ "BackgroundJobs": "Background Jobs",
+ "BackgroundJobsExplanation": "Definiţi clase simple pentru a executa task-uri în fundal, aşezate în coadă. Folosiţi managerul de taskuri încorporat sau integraţi-l pe al dumneavoastră. Integrările Hangfire & RabbitMQ sunt deja disponibile.",
+ "DDDInfrastructure": "Infrastructură DDD",
+ "DomainDrivenDesignInfrastructure": "Infrastructură Domain Driven Design",
+ "AutoRESTAPIs": "Auto REST APIs",
+ "DynamicClientProxies": "Dynamic Client Proxies",
+ "DistributedEventBus": "Distributed Event Bus",
+ "DistributedEventBusWithRabbitMQIntegration": "Distributed Event Bus with RabbitMQ Integration",
+ "TestInfrastructure": "Infrastructură de test",
+ "AuditLoggingEntityHistories": "Jurnalul de audit şi istoricul entităţilor",
+ "ObjectToObjectMapping": "Mapare obiect la obiect",
+ "ObjectToObjectMappingExplanation": "Abstractizarea mapării obiect la obiect cu integrare AutoMapper.",
+ "EmailSMSAbstractions": "Abstractizări Email & SMS",
+ "EmailSMSAbstractionsWithTemplatingSupport": "Abstractizări de Email & SMS cu asistenţă pentru modelare",
+ "Localization": "Localizare",
+ "SettingManagement": "Administrarea setărilor",
+ "ExtensionMethods": "Metode de extindere",
+ "ExtensionMethodsHelpers": "Metode de extindere & Ajutoare",
+ "AspectOrientedProgramming": "Programare orientată spre aspect",
+ "DependencyInjection": "Injectarea de dependinţe",
+ "DependencyInjectionByConventions": "Injectarea dependinţei prin convenţii",
+ "ABPCLIExplanation": "ABP CLI (Command Line Interface) este un instrument de linie de comandă pentru efectuarea câtorva operaţii comune pentru soluţiile bazate pe ABP.",
+ "ModularityExplanation": "ABP asigură o infrastructură completă pentru construirea modulelor aplicaţiei dumneavoastră, care pot avea entităţi, servicii, integrări cu baze de date, API-uri, componente UI şi aşa mai departe..",
+ "MultiTenancyExplanation": "ABP nu numai că acceptă dezvoltarea de aplicaţii multi-tenant, dar, de asemenea, face ca şi codul dumneavoastră să nu fie în mare parte conştient de multi-tenancy.",
+ "MultiTenancyExplanation2": "Poate detecta automat tenantul curent, izola datele unor tenanţi diferiţi unul de celălalt.",
+ "MultiTenancyExplanation3": "Acceptă o singură bază de date, bază de date per tenant şi abordări hibride.",
+ "MultiTenancyExplanation4": "Vă focusaţi pe codul dumneavoastră şi lăsaţi framework-ul să se ocupe de multi-tenancy pentru dumneavoastră.",
+ "BootstrapTagHelpersExplanation": "În loc să scrieţi manual detaliile repetate ale componentelor bootstrap, folosiţi tag helperele ABP pentru a simplifica şi profita de inteligenţă. Puteţi folosi cu siguranţă Bootstrap ori de câte ori aveţi nevoie de el.",
+ "DynamicFormsExplanation": "Formulare dinamice & tag helpere de intrare pot crea formularul complet dintr-o clasă C# ca model.",
+ "AuthenticationAuthorizationExplanation": "Opţiuni variate de autentificare şi autorizare integrate cu ASP.NET Core Identity & IdentityServer4. Furnizează un sistem de permisiuni extensibil şi detaliat.",
+ "CrossCuttingConcernsExplanation": "Nu vă repetaţi pentru a implementa din nou şi din nou toate aceste lucruri obişniuite. Concentraţi-vă pe codul dumneavoastră de business şi lăsaţi ABP să le automatizeze prin convenţii.",
+ "DatabaseConnectionTransactionManagement": "Conectare la baza de date & Gestionarea tranzacţiilor",
+ "CorrelationIdTracking": "Correlation-Id Tracking",
+ "BundlingMinificationExplanation": "ABP oferă un sistem simplu, dinamic, puternic, modular şi încorporat de grupare şi minimizare.",
+ "VirtualFileSystemnExplanation": "Sistemul fişierelor virtuale face posibilă administrare fişierelor care nu există fizic pe sistemul de fişiere (disk). Este folosit în principal pentru a încorpora fişiere (js, css, images, cshtml...) în ansambluri şi să le folosească sub formă de fişiere fizice în timpul rulării.",
+ "ThemingExplanation": "Sistemul de teme permite dezvoltarea aplicaţiei & modulelor independente de tema prin definirea unui set comun de librării şi aspecte de bază, bazate pe ultimul framework Bootstrap.",
+ "DomainDrivenDesignInfrastructureExplanation": "O infrastructură completă pentru construirea aplicaţiilor stratificate, bazată pe tipare & principii Domain Driven Design;",
+ "Specification": "Specificaţie",
+ "Repository": "Repository",
+ "DomainService": "Domain Service",
+ "ValueObject": "Value Object",
+ "ApplicationService": "Application Service",
+ "DataTransferObject": "Obiect de transfer de date",
+ "AggregateRootEntity": "Aggregate Root, Entity",
+ "AutoRESTAPIsExplanation": "ABP poate configura automat serviciile aplicaţiei sub formă de controllere API prin convenţie.",
+ "DynamicClientProxiesExplanation": "Folosiţi-vă cu uşurinţă API-urile din JavaScript şi clienţi C#.",
+ "DistributedEventBusWithRabbitMQIntegrationExplanation": "Publicaţi şi utilizaţi cu uşurinţă evenimentele distribuite utilizând Distributed Event Bus încorporat cu integrarea RabbitMQ disponibilă.",
+ "TestInfrastructureExplanation": "Framework-ul a fost dezvoltat cu testarea unităţii şi integrării în minte. Vă oferă clase de bază pentru a o uşura. Şabloanele de pornire sunt pre-configurate pentru testare.",
+ "AuditLoggingEntityHistoriesExplanation": "Jurnal de audit încorporat pentru aplicaţii critice pentru afaceri. Solicitare, serviciu, jurnal de audit la nivel de metodă şi istoric de entităţi cu detalii la nivel de proprietate.",
+ "EmailSMSAbstractionsWithTemplatingSupportExplanation": "Abstractizările IEmailSender şi ISmsSender decuplează logica aplicaţiei de infrastructură. Sistemul avansat de şabloane de email permite crearea şi localizarea şabloanelor de email şi utilizarea lor cu uşurinţă ori de câte ori este necesar.",
+ "LocalizationExplanation": "Sistemul de localizare vă permite să creaţi resurse în JSON simplu şi să le folosiţi pentru a vă localiza UI-ul dumneavoastră. Suportă sisteme avansate precum moştenirea, extinderea, şi integrarea cu JavaScript în timp ce e pe deplin compatibilă cu sistemul de localizare al AspNet Core.",
+ "SettingManagementExplanation": "Definiţi setări pentru aplicaţia dumneavoastră şi Define settings for your application and get values on runtime based on the current configuration, tenant and user.",
+ "ExtensionMethodsHelpersExplanation": "Don't repeat yourself even for trivial code parts. Extensions & helpers for standard types makes your code much cleaner and easy to write.",
+ "AspectOrientedProgrammingExplanation": "Furnizează o infrastructură confortabilă pentru crearea proxy-urilor dinamice şi implementarea programării orientată aspect. Interceptează orice clasă şi execută codul dumneavoastră înainte & după orice executare de metodă.",
+ "DependencyInjectionByConventionsExplanation": "Nu este nevoie să vă înregistraţi clasele pentru injectarea manuală a dependinţelor. Înregistrează în mod automat tipurile de servicii comune prin convenţie. Pentru alte tipuri de servicii, puteţi folosi interfeţe şi atribute pentru a o face mai uşor si pe loc.",
+ "DataFilteringExplanation": "Definiţi şi utilizaţi filtre de date care sunt aplicate automat atunci când interogaţi entităţi din baza de date. Filtre Soft Delete & MultiTenant sunt prevăzute în mod implicit atunci când implementaţi interfeţe simple.",
+ "PublishEvents": "Publicaţi evenimente",
+ "HandleEvents": "Gestionaţi evenimente",
+ "AndMore": "şi multe altele...",
+ "Code": "Cod",
+ "Result": "Rezultat",
+ "SeeTheDocumentForMoreInformation": "Consultaţi {0} documentul pentru mai multe informaţii",
+ "IndexPageHeroSection": "open sourceWeb Application Framework pentru asp.net core",
+ "UiFramework": "Framework UI",
+ "EmailAddress": "Adresă de email",
+ "Mobile": "Mobil",
+ "ReactNative": "React nativ",
+ "Strong": "Puternic",
+ "Complete": "Complet",
+ "BasedLayeringModel": "Based Layering Model",
+ "Microservice": "Microserviciu",
+ "Compatible": "Compatibil",
+ "MeeTTheABPCommunityInfo": "Misiunea noastră este de a crea un mediu în care dezvoltatorii să se ajute reciproc cu articole, tutoriale, studii de caz etc. şi să cunoască oameni cu aceleaşi idei.",
+ "JoinTheABPCommunityInfo": "Implicaţi-vă într-o comunitate vibrantă şi deveniţi un contribuitor la ABP Framework!",
+ "AllArticles": "Toate articolele",
+ "SubmitYourArticle": "Trimiteţi-vă articolul",
+ "DynamicClientProxyDocument": "Consultaţi documentaţia pentru client proxy dinamic pentru JavaScript & C#.",
+ "EmailSMSAbstractionsDocument": "Consultaţi documentele de emailing and trimiterea de SMS pentru mai multe informaţii.",
+ "CreateProjectWizard": "Acest formular crează un proiect nou începând cu şablonul de pornire, care este configurat corespunzător pentru a începe direct cu proiectul.",
+ "TieredOption": "Crează o soluţie pe mai multe niveluri în care straturile Web API şi HTTP sunt separate fizic. Dacă nu este bifată, creează o soluţie stratificată mai puţin complexă şi potrivită pentru majoritatea scenariilor.",
+ "SeparateIdentityServerOption": "Separă partea serverului în două aplicaţii: prima este pentru serverul de identitate, iar a doua pentru serverul dumneavoastră de HTTP API.",
+ "UseslatestPreVersion": "Foloseşte ultima versiune pre-lansare",
+ "ReadTheDocumentation": "Citiţi Documentaţia",
+ "Documentation": "Documentaţie",
+ "GettingStartedTutorial": "Tutorial de pornire",
+ "ApplicationDevelopmentTutorial": "Tutorial de dezvoltare a aplicaţiei",
+ "TheStartupTemplate": "Şablonul de pornire",
+ "InstallABPCLIInfo": "ABP CLI este cea mai rapidă metodă de a porni o soluţie nouă cu framework-ul ABP. Instalaţi ABP CLI folosind o fereastră de linii de comandă:",
+ "DifferentLevelOfNamespaces": "Puteţi folosi nivele diferite de spaţii de nume; e.g. BookStore, Acme.BookStore or Acme.Retail.BookStore.",
+ "ABPCLIExamplesInfo": "comanda new creează o aplicaţie stratificată MVC cu Entity Framework Core ca şi furnizor de baze de date. Totuşi, are şi alte opţiuni. Exemple:",
+ "SeeCliDocumentForMoreInformation": "Consultaţi documentul ABP CLI pentru mai multe opţiuni sau selectaţi tab-ul de \"Descărcare directă\" de deasupra.",
+ "Optional": "Opţional",
+ "LocalFrameworkRef": "Pastraţi referinţa proiectului local pentru pachetele framework-ului.",
+ "BlobStoring": "Depozitare BLOB",
+ "BlobStoringExplanation": "Sistemul de depozitare BLOB oferă o abstractizare pentru lucrul cu BLOB-uri. ABP oferă câteva integrări prestabilite pentru furnizorii de stocare (Azure, AWS, File System, Database, etc.) pe care le puteţi folosi cu uşurinţă în aplicaţiile dumneavoastră.",
+ "TextTemplating": "Modelare text",
+ "TextTemplatingExplanation": "Modelarea textului este folosită pentru a reda dinamic conţinuturile bazate pe un şablon şi un model (un obiect de date). De exemplu, o puteţi folosi pentru a crea conţinuturi dinamice de email cu un şablon predefinit.",
+ "MultipleUIOptions": "Opţiuni UI multiple",
+ "MultipleDBOptions": "Furnizori de baze de date multipli",
+ "MultipleUIOptionsExplanation": "Framework-ul de bază este conceput ca independent de UI şi poate funcţiona cu orice tip de sistem UI, în timp ce mai multe opţiuni pre-construite şi integrate sunt oferite din start.",
+ "MultipleDBOptionsExplanation": "Framework-ul poate lucra cu orice sursă de date, în timp ce furnizorii următori sunt dezvoltaţi şi acceptaţi oficial;",
+ "SelectLanguage": "Selectaţi limba",
+ "LatestArticleOnCommunity": "Ultimul articol de pe comunitatea ABP",
+ "Register": "Întregistrare",
+ "IsDownloadable": "Poate fi descărcat",
+ "DatabaseOptions": "Opţiunile bazei de date",
+ "BackToPackagesPage": "Înapoi la pagina pachetelor",
+ "HowToInstall": "Cum instalez",
+ "SeeOnNpm": "Vedeţi pe NPM",
+ "SeeOnNuget": "Vedeţi pe Nuget",
+ "MVCGulpCommandExplanation": "Dacă folosiţi MVC (Razor Pages) UI, atunci rulaţi comanda the \"gulp\" după instalarea pachetelor.",
+ "UsingABPCLI": "Folosind Abp CLI",
+ "WithoutABPCLI": "Fară ABP CLI",
+ "ABPCLIModuleDependency": "Abp Cli adaugă automat dependenţa modulelor.",
+ "AddModuleDependency": "Apoi adăugaţi dependenţa modulului",
+ "Packages": "Pachete",
+ "NugetPackages": "Pachete Nuget",
+ "NPMPackages": "Pachete NPM",
+ "SeeDocs": "Consultaţi documentele",
+ "None": "Niciuna",
+ "Application": "Aplicaţie",
+ "Module": "Module",
+ "PackageName": "Nume pachet",
+ "LicenseURL": "URL licenţă",
+ "License": "Licenţă",
+ "ProjectCreationSuccessMessage": "Proiectul dumneavoastră a fost creat cu succes",
+ "HowToRunSolution": "Cum vă rulaţi soluţia?",
+ "GettingStartedMessage": "Consultaţi documentul de pornire pentru a învăţa cum să vă configuraţi şi să rulaţi soluţia dumneavoastră.",
+ "WebAppDevTutorial": "Tutorial Web App Dev",
+ "WebAppDevTutorialMessage": "Consultaţi documentul de dezvoltare a aplicaţiilor web pentru un exemplu de dezvoltare pas cu pas.",
+ "CommunityArticles": "Articolele comunităţii",
+ "CommunityArticleMessage": "Verificaţi platforma comunităţii ABP pentru a citi articole utile pentru framework-ul ABP.",
+ "InvestigateSolutionDetails": "Investigaţi detaliile soluţiei",
+ "StartupTemplateDocumentationMessage": "Consultaţi documentul şablonului de pornire a aplicaţiei pentru a învăţa arhitectura şi strucutra soluţiei dumneavoastră.",
+ "ClientSideDevelopment": "Dezvoltarea clientului",
+ "ClientSideDevelopmentDocumentationMessage": "Consultaţi documentul {0} pentru a învăţa punctele cheie pentru dezvoltarea interfeţei de utilizator.",
+ "DatabaseProviderDocumentationMessage": "Consultaţi documentul {0} pentru a învăţa punctele cheie pentru dezvoltarea straturilor bazei de date.",
+ "ABPCommercialExplanationMessage": "ABP Commercial oferă module premium, teme, isntrumente şi asistenţă pentru framework-ul ABP.",
+ "ImplementingDDD": "Implementarea Domain Driven Design",
+ "DDDBookExplanation": "Un ghid practic pentru implementarea Domain Driven Design în framework-ul ABP.",
+ "Overview": "Prezentare generală",
+ "DDDBookPracticalGuide": "Acesta este un ghid practic pentru implementarea Domain Driven Design (DDD). În timp ce detaliile implementării se bazează pe infrastructura framework-ului ABP, conceptele de bază, principiile şi modelele pot fi aplicate oricărei soluţii, chiar dacă nu este una .NET.",
+ "TableOfContents": "Cuprins",
+ "IntroductionToImplementingDDD": "Introducere în Implementarea Domain Driven Design",
+ "WhatIsDDD": "Ce este Domain Driven Design?",
+ "Implementation": "Implementare",
+ "TheBigPicture": "Privire de ansamblu",
+ "TheBuildingBlock": "The Building Block",
+ "ExampleUseCase": "Exemplu de Use Case",
+ "DomainAndApplicationLogic": "Domain Logic & Application Logic",
+ "Author": "Autor",
+ "Pages": "Pagini",
+ "PublishedOn": "Publicat pe",
+ "FreeEBook": "E-Book gratuit",
+ "Download": "Descărcaţi",
+ "EBookSignInForDownload": "Pentru a descărca e-book-ul trebuie să vă autentificaţi",
+ "SignIn": "Autentificaţi-vă",
+ "Or": "Sau",
+ "TellUsAboutYourself": "Spuneţi-ne un pic despre dumneavoastră",
+ "Name": "Nume",
+ "Surname": "Nume",
+ "CompanyName": "Nume companie",
+ "DoYouAgreePrivacyPolicy": "Sunt de acord cu Termenii & condiţiile şi Politica de confidenţialitate.",
+ "Free": "Gratuit",
+ "DDDEBook": "E-book DDD",
+ "PracticalGuideForImplementingDDD": "Această carte este un ghid practic pentru implementarea Domain Driven Design în framework-ul ABP.",
+ "IntroducingDDD": "Introducere în Domain Driven Design",
+ "DDDLayersAndCleanArchitecture": "Straturile DDD & Arhitectură curată",
+ "LayeringOfADotnetSolution": "Stratificarea unei soluţii .NET",
+ "ImplementingDDDBuildingBlocks": "Implementând DDD Building Blocks",
+ "DomainVsApplicationLogic": "Domain Logic vs Application Logic",
+ "SamplesAndDiscussions": "Exemple & Discuţii",
+ "EmailNotValid": "Vă rugăm să introduceţi o adresa de email validă.",
+ "WeWillSendYouADownloadLink": "Un link care conţine e-book-ul a fost trimis către {0}. Verificaţi-vă folderele de inbox, junk sau spam!",
+ "GoHome": "Pagina principală",
+ "InvalidFormInputs": "Vă rugăm, introduceţi informaţia validă specificată în formular.",
+ "DDDBookEmailBody": "Vă mulţumim. Pentru a descărca cartea, click aici.",
+ "SubscribeToNewsletter": "Abonaţi-vă la newsletter pentru a primi informaţii despre evnimentele din platforma ABP.IO, precum noi lansări, articole, oferte şi multe altele.",
+ "FirstEdition": "Prima ediţie",
+ "ThankYou": "Vă mulţumim!",
+ "CheckboxMandatory": "Trebuie să bifaţi asta pentru a continua!"
+ }
+}
diff --git a/common.props b/common.props
index 36f1f352fa..6ce5cae828 100644
--- a/common.props
+++ b/common.props
@@ -1,7 +1,7 @@
latest
- 4.4.2
+ 5.0.0$(NoWarn);CS1591;CS0436https://abp.io/assets/abp_nupkg.pnghttps://abp.io/
diff --git a/docs/en/Background-Jobs-Hangfire.md b/docs/en/Background-Jobs-Hangfire.md
index cfa2e12a6b..a690d9d17b 100644
--- a/docs/en/Background-Jobs-Hangfire.md
+++ b/docs/en/Background-Jobs-Hangfire.md
@@ -79,3 +79,26 @@ After you have installed these NuGet packages, you need to configure your projec
}
````
+
+### Dashboard Authorization
+
+Hangfire Dashboard provides information about your background jobs, including method names and serialized arguments as well as gives you an opportunity to manage them by performing different actions – retry, delete, trigger, etc. So it is important to restrict access to the Dashboard.
+To make it secure by default, only local requests are allowed, however you can change this by following the [official documentation](http://docs.hangfire.io/en/latest/configuration/using-dashboard.html) of Hangfire.
+
+You can integrate the Hangfire dashboard to [ABP authorization system](Authorization.md) using the **AbpHangfireAuthorizationFilter**
+class. This class is defined in the `Volo.Abp.Hangfire` package. The following example, checks if the current user is logged in to the application:
+
+ app.UseHangfireDashboard("/hangfire", new DashboardOptions
+ {
+ AsyncAuthorization = new[] { new AbpHangfireAuthorizationFilter() }
+ });
+
+If you want to require an additional permission, you can pass it into the constructor as below:
+
+ app.UseHangfireDashboard("/hangfire", new DashboardOptions
+ {
+ AsyncAuthorization = new[] { new AbpHangfireAuthorizationFilter("MyHangFireDashboardPermissionName") }
+ });
+
+**Important**: `UseHangfireDashboard` should be called after the authentication middleware in your `Startup` class (probably at the last line). Otherwise,
+authorization will always fail!
diff --git a/docs/en/Blog-Posts/2020-10-15 v3_3_Preview/POST.md b/docs/en/Blog-Posts/2020-10-15 v3_3_Preview/POST.md
index 4e19a294c1..886e8a145d 100644
--- a/docs/en/Blog-Posts/2020-10-15 v3_3_Preview/POST.md
+++ b/docs/en/Blog-Posts/2020-10-15 v3_3_Preview/POST.md
@@ -213,7 +213,7 @@ There are some breaking changes with the Blazor UI. If you've built an applicati
When you create a new project, profile management doesn't work, you get an exception because it can't find the `/libs/cropperjs/css/cropper.min.css` file. To fix the issue;
* Add `"@volo/account": "^3.3.0-rc.1"` to the `package.json` in the `.Host` project.
-* Run `yarn` (or `npm install`), then `gulp` on a command line terminal in the root folder of the `.Host` project.
+* Run `yarn` (or `npm install`), then `abp install-libs` on a command line terminal in the root folder of the `.Host` project.
### Multi-Tenant Social Logins
diff --git a/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/POST.md b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/POST.md
new file mode 100644
index 0000000000..dff6d1af77
--- /dev/null
+++ b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/POST.md
@@ -0,0 +1,174 @@
+# ABP Platform 4.4 RC Has Been Released
+
+Today, we have released the [ABP Framework](https://abp.io/) and the [ABP Commercial](https://commercial.abp.io/) version 4.4 RC (Release Candidate). This blog post introduces the new features and important changes in this new version.
+
+> **The planned release date for the [4.4.0 final](https://github.com/abpframework/abp/milestone/53) version is July 13, 2021**.
+
+## Get Started with the 4.4 RC
+
+If you want to try the version 4.4.0 today, follow the steps below;
+
+1) **Upgrade** the ABP CLI to the version `4.4.0-rc.1` using a command line terminal:
+
+````bash
+dotnet tool update Volo.Abp.Cli -g --version 4.4.0-rc.1
+````
+
+**or install** if you haven't installed before:
+
+````bash
+dotnet tool install Volo.Abp.Cli -g --version 4.4.0-rc.1
+````
+
+2) Create a **new application** with the `--preview` option:
+
+````bash
+abp new BookStore --preview
+````
+
+See the [ABP CLI documentation](https://docs.abp.io/en/abp/latest/CLI) for all the available options.
+
+> You can also use the *Direct Download* tab on the [Get Started](https://abp.io/get-started) page by selecting the **Preview checkbox**.
+
+### Migration Notes
+
+There is **no breaking change** with this version. However, if you are using Entity Framework Core, you will need to run the `Add-Migration` command to add a new **database migration** since some changes done in the module database mappings.
+
+## What's new with the ABP Framework 4.4
+
+### Removed EntityFrameworkCore.DbMigrations Project
+
+With this version, we are doing an important change in the application startup solution template. The startup solution was containing an `EntityFrameworkCore.DbMigrations` project that contains a separate `DbContext` class which was responsible to unify the module database mappings and maintain the code-first database migrations. With the v4.4, we've removed that project from the solution. In the new structure, the `EntityFrameworkCore` integration project will be used for database migrations as well as on runtime.
+
+We'd published [a community article](https://community.abp.io/articles/unifying-dbcontexts-for-ef-core-removing-the-ef-core-migrations-project-nsyhrtna) about that change. Please see the article to understand the motivation behind the change.
+
+Beside the `DbContext` unification, we've also used the new `ReplaceDbContext` attribute and [replaced](https://github.com/abpframework/abp/blob/ea2205f0855f52015152ae066a5c239af4b8511f/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/EntityFrameworkCore/MyProjectNameDbContext.cs#L18-L19) the `IIdentityDbContext` and `ITenantManagementDbContext` interfaces to make it possible to perform join queries over repositories for these modules easily. In the next days, we will publish another community article to explain the problem and the solution. However, most of times, you don't need to know these details.
+
+### Dynamic Menu Management for the CMS Kit Module
+
+CMS Kit is a set of reusable *Content Management System* features packaged as an ABP application module. We had published the first usable version with the previous release. With this release, we are adding another feature to the CMS Kit module: You can now dynamically arrange the main menu on the UI, which is an essential feature for any kind of content management system. In this way, you can add pages or any kind of arbitrary URLs to the main menu from the UI.
+
+A screenshot from the menu management page (from the CMS Kit admin side):
+
+
+
+And the items rendered in a public website:
+
+
+
+Note that this feature is also available with the open source [CMS Kit module](https://docs.abp.io/en/abp/4.4/Modules/Cms-Kit/Index) (while the screenshots have been taken from the ABP Commercial).
+
+### Razor Engine Support for Text Templating
+
+[Text Templating](https://docs.abp.io/en/abp/4.4/Text-Templating) is a system to generate content on runtime by using a model (data) and a template. It was running on the [Scriban](https://github.com/scriban/scriban) templating engine. Beginning from this version, we have a second option: We can use the familiar **razor syntax** to build and render the templates. See the text templating [razor integration document](https://docs.abp.io/en/abp/4.4/Text-Templating-Razor) to get started with the new engine!
+
+### New Customization Points for DbContext/Entities
+
+Two new extension methods are added to `ObjectExtensionManager.Instance` to override EF Core mappings of [pre-built application modules](https://docs.abp.io/en/abp/latest/Modules/Index).
+
+**Example: Change mappings for the `IdentityDbContext` to override mappings for the `IdentityUser` entity**
+
+````csharp
+ObjectExtensionManager.Instance.MapEfCoreDbContext(modelBuilder =>
+{
+ modelBuilder.Entity(b =>
+ {
+ b.ToTable("MyUsers");
+ b.Property(x => x.Email).HasMaxLength(300);
+ });
+});
+````
+
+The startup template contains a class, like `YourProjectNameEfCoreEntityExtensionMappings`, that can be used to place that code.
+
+### New ABP CLI Commands
+
+There are new [ABP CLI](https://docs.abp.io/en/abp/4.4/CLI) commands introduced with the v4.4:
+
+* `abp install-libs` command is used for MVC / Razor Pages and Blazor Server applications to restore the `wwwroot/libs` folder. Previously we were running the `yarn` and `gulp` commands to restore that folder. While the `install-libs` command still uses yarn (if available), it is no longer needed to use `gulp`.
+* `abp prompt` command can be used to open a prompt for the ABP CLI and run multiple commands without needing to specify the `abp` command every time. For example, if you run `abp prompt`, then you can directly run `install-libs` instead of `abp install-libs`. Use `exit` to quit from the ABP prompt.
+* `abp batch` command can be used to run multiple ABP commands with one command. Prepare a text file, write each command as a line (without the `abp` command prefix), then execute `abp batch ` (ex: `abp batch your_commands.txt`) command to execute all the commands in that file.
+
+### appsettings.secrets.json
+
+Added `appsettings.secrets.json` to the startup template that can be used to set your sensitive/secret configuration values. You can ignore this file from source control (by adding to `.gitignore` if you're using git) and keep it only in developer/production machines.
+
+### Other ABP Framework Improvements
+
+* [#9350](https://github.com/abpframework/abp/pull/9350) Extracted `IRemoteServiceConfigurationProvider` to get remote service configurations. You can replace this service to get the configuration from any source.
+* [#8829](https://github.com/abpframework/abp/pull/8829) Implemented error handler and retry for distributed event bus.
+* [#9288](https://github.com/abpframework/abp/issues/9288) Use default CORS policy instead of a named one in the startup template. It is suggested to update your own solutions to make it simpler.
+* Translated the framework and module localization strings to Hindi, Italian, Finnish and French languages.
+
+Beside these, there are a lot of enhancements and bug fixes. See the [4.4-preview milestone](https://github.com/abpframework/abp/milestone/52?closed=1) for all issues and pull requests closed with this version.
+
+## What's new with the ABP Commercial 4.4
+
+### New Features for the SaaS Module
+
+We've implemented some important features to the [SaaS module](https://commercial.abp.io/modules/Volo.Saas):
+
+* Integrated to the [Payment module](https://commercial.abp.io/modules/Volo.Payment) and implemented **subscription system** for the SaaS module.
+* Allow to make a **tenant active/passive**. In this way, you can take a tenant to passive to prevent the users of that tenant from using the system. In addition, you can set a date to automatically make a tenant passive when the date comes.
+* Allow to **limit user count** for a tenant.
+* Allow to set **different connection strings** for a tenant for each database/module, which makes possible to create different databases for a tenant for each microservice in a microservice solution.
+
+### New ABP Suite Code Generation Features
+
+There are many improvements done for for [ABP Suite](https://commercial.abp.io/tools/suite), including CRUD page generation for the **[microservice solution](https://docs.abp.io/en/commercial/latest/startup-templates/microservice/index) template**.
+
+### Angular UI: Two Factor Authentication for the Resource Owner Password Flow
+
+In the previous version, we had implemented the resource owner password authentication flow for the Angular UI, which makes the login process easier for simpler applications. With this release, we've implemented two-factor authentication for that flow. Authorization code flow already supports 2FA.
+
+### Other ABP Commercial Improvements
+
+* Added web layers to microservices in the microservice solution. You can use them to create modular UI or override existing pages/components of pre-built modules (e.g. Identity and SaaS).
+* ABP Commercial license code has been moved to `appsettings.secrets.json` in the new startup templates.
+* Added new language options: Hindi, Italian, Arabic, Finnish, French.
+
+Beside these, there are many minor improvements and fixes done in the modules and themes.
+
+## Other News
+
+In this section, I will share some news that you may be interested in.
+
+### New Article: Using Elsa Workflow with ABP Framework
+
+We have been frequently asked how to use [Elsa Workflows](https://elsa-workflows.github.io/elsa-core/) with the ABP Framework. Finally, we have [created an article](https://community.abp.io/articles/using-elsa-workflow-with-the-abp-framework-773siqi9) to demonstrate it.
+
+
+
+You can [check it](https://community.abp.io/articles/using-elsa-workflow-with-the-abp-framework-773siqi9) to see how to integrate Elsa into an ABP based solution easily.
+
+### Free E-Book: Implementing Domain Driven Design
+
+We've published a free e-book for the ABP Community in the beginning of June. This is a practical guide for implementing Domain Driven Design (DDD). While the implementation details are based on the ABP Framework infrastructure, the basic concepts, principles and models can be applied to any solution, even if it is not a .NET solution.
+
+
+
+Thousands of copies are already downloaded. If you haven't seen it yet, [click here to get a free copy of that e-book](https://abp.io/books/implementing-domain-driven-design).
+
+### The LeptonX Theme
+
+We have been working on a new ABP theme, named the *LeptonX*, for a long time. The theme will be available for ABP Framework (free - lite version) and ABP Commercial (pro version). It is being finalized in the next weeks and we will release the first version in a short time.
+
+
+
+See [this blog post](https://volosoft.com/blog/introducing-the-lepton-theme-next-generation) to learn more about that project.
+
+### Volosoft & .NET Foundation
+
+[Volosoft](https://volosoft.com/), the company leads the ABP Framework project, has been a corporate sponsor of the [.NET Foundation](https://dotnetfoundation.org/). We are happy by taking our place among other great sponsors!
+
+
+
+We will continue to contribute to and support open source! See this [blog post for the announcement](https://volosoft.com/blog/Volosoft-Announces-the-NET-Foundation-Sponsorship).
+
+### Looking for Developer Advocate(s)
+
+We are actively looking for professional developer advocates for the ABP.IO platform. If you want to create content and touch to the ABP community, please check our [job post](https://github.com/volosoft/vs-home/issues/13).
+
+## About the Next Version
+
+The next version will be a major version: 5.0, which will be based on .NET 6.0. We are planning to release it in the end of 2021, short time after the .NET 6.0 release. We will release multiple preview/beta versions before the RC version. See the [road map](https://docs.abp.io/en/abp/latest/Road-Map) for details of the planned works for the version 5.0.
diff --git a/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/abp-44-cover.png b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/abp-44-cover.png
new file mode 100644
index 0000000000..1f231aac00
Binary files /dev/null and b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/abp-44-cover.png differ
diff --git a/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/ddd-book.png b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/ddd-book.png
new file mode 100644
index 0000000000..747fcc1d13
Binary files /dev/null and b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/ddd-book.png differ
diff --git a/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/dotnetfoundation-sponsor-volosoft.png b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/dotnetfoundation-sponsor-volosoft.png
new file mode 100644
index 0000000000..e1f70929f4
Binary files /dev/null and b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/dotnetfoundation-sponsor-volosoft.png differ
diff --git a/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/elsa-overview.gif b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/elsa-overview.gif
new file mode 100644
index 0000000000..ba589cabfc
Binary files /dev/null and b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/elsa-overview.gif differ
diff --git a/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/leptonx.png b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/leptonx.png
new file mode 100644
index 0000000000..46faaf13e6
Binary files /dev/null and b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/leptonx.png differ
diff --git a/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/menu-items-admin.png b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/menu-items-admin.png
new file mode 100644
index 0000000000..63075eed70
Binary files /dev/null and b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/menu-items-admin.png differ
diff --git a/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/menu-items-public.png b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/menu-items-public.png
new file mode 100644
index 0000000000..42c12c6801
Binary files /dev/null and b/docs/en/Blog-Posts/2021-06-28 v4_4 Preview/menu-items-public.png differ
diff --git a/docs/en/Blog-Posts/2021-07-08 Introducing_the_eShopOnAbp/POST.md b/docs/en/Blog-Posts/2021-07-08 Introducing_the_eShopOnAbp/POST.md
new file mode 100644
index 0000000000..efba693145
--- /dev/null
+++ b/docs/en/Blog-Posts/2021-07-08 Introducing_the_eShopOnAbp/POST.md
@@ -0,0 +1,52 @@
+# Introducing the eShopOnAbp Project
+
+We are happy to introduce the **eShopOnAbp** project as an example microservice solution built with the ABP Framework by the core ABP team. This solution demonstrates the strength of ABP Framework and using it in a real-life case. The goal of the project is to create a full-featured cloud-native microservices reference application. The project is inspired by the [eShopOnContainers](https://github.com/dotnet-architecture/eShopOnContainers) project and shows how it can be implemented with the ABP Framework.
+
+> **Project Status**: Currently, the project doesn't have any business logic. We've just brought ABP's pre-built modules (Identity, Tenant Management, IdentityServer, etc) together as a base solution. However, it is fully working and you can now take it as a base solution for your microservice project. From now on, we will build the example application functionalities / business logic on top of it.
+
+## Source Code
+
+The source code is available on [abpframework/eShopOnAbp](https://github.com/abpframework/eShopOnAbp) repository.
+
+## The Big Picture
+
+The project follows micro-service architecture and overall structure is presented below.
+
+
+
+## How to Run?
+
+You can either run in Visual Studio, or using [Microsoft Tye](https://github.com/dotnet/tye). Tye is a developer tool that makes developing, testing, and deploying micro-services and distributed applications easier.
+
+ ### Requirements
+
+- .NET 5.0+
+- Docker
+- Yarn
+
+### Instructions
+
+- Clone the repository ( [eShopOnAbp](https://github.com/abpframework/eShopOnAbp) )
+
+- Install Tye (*follow [these steps](https://github.com/dotnet/tye/blob/main/docs/getting_started.md#installing-tye)*)
+
+- Execute `run-tye.ps1`
+
+- Wait until all applications are up!
+
+ - You can check running application from tye dashboard ([localhost:8000](http://127.0.0.1:8000/))
+
+- After all your backend services are up, start the angular application:
+
+ ```bash
+ cd apps/angular
+ yarn start
+ ```
+
+## What's Next?
+
+We'll work on deployment & CI-CD processes as a next step and build the business logic on. First goal is deploying the entire application on [Kubernetes](https://kubernetes.io/).
+
+## Feedback
+
+Your comments and suggestions is important for us. You can ask your questions or post your feedback under [this discussion entry](https://github.com/abpframework/abp/discussions/9536).
diff --git a/docs/en/Blog-Posts/2021-07-08 Introducing_the_eShopOnAbp/overall-solution.png b/docs/en/Blog-Posts/2021-07-08 Introducing_the_eShopOnAbp/overall-solution.png
new file mode 100644
index 0000000000..e3ef175316
Binary files /dev/null and b/docs/en/Blog-Posts/2021-07-08 Introducing_the_eShopOnAbp/overall-solution.png differ
diff --git a/docs/en/Blog-Posts/2021-07-28-lepton-x-release/POST.md b/docs/en/Blog-Posts/2021-07-28-lepton-x-release/POST.md
new file mode 100644
index 0000000000..bc586fdeed
--- /dev/null
+++ b/docs/en/Blog-Posts/2021-07-28-lepton-x-release/POST.md
@@ -0,0 +1,216 @@
+# LeptonX Alpha Release
+
+We are excited to announce that the **alpha version** of the LeptonX theme has been released! As stated in [this blog post](https://volosoft.com/blog/introducing-the-lepton-theme-next-generation), LeptonX comes in different shapes. For this release, we introduce only ABP based projects with the Angular UI. So, if you are already using the ABP Framework and Angular as the frontend choice, you can integrate these packages into your project today.
+
+The theme has been deployed with two versions: LeptonX-lite (free) and LeptonX (commercial).
+
+> **Note that this theme currently only works for the *Angular UI*. Please keep waiting for other UI options.**
+
+## Open-Source
+
+This section shows how to replace the basic theme (that comes with open source ABP Framework startup template) with the new LeptonX-lite theme.
+
+To add `LeptonX-lite` into your project,
+
+* Install `@abp/ng.theme.lepton-x` NPM package
+
+`npm install @abp/ng.theme.lepton-x@preview` or
+
+`yarn add @abp/ng.theme.lepton-x@preview`
+
+* Then, we need to edit the styles array in `angular.json` to replace the existing style with the new one.
+
+Replace the following style
+
+```JSON
+{
+ "input": "node_modules/bootstrap/dist/css/bootstrap.min.css",
+ "inject": true,
+ "bundleName": "bootstrap-ltr.min"
+},
+```
+
+with
+
+```json
+"node_modules/@volo/ngx-lepton-x.lite/styles/sidemenu-layout.min.css",
+"node_modules/bootstrap-icons/font/bootstrap-icons.css",
+```
+
+* Finally, remove `ThemeBasicModule` from `app.module.ts` and `shared.module.ts`, and import the related modules in `app.module.ts`
+
+```js
+import { ThemeLeptonXModule } from '@abp/ng.theme.lepton-x';
+import { SideMenuLayoutModule } from '@abp/ng.theme.lepton-x/layouts';
+
+@NgModule({
+ imports: [
+ // ...
+ ThemeLeptonXModule.forRoot(),
+ SideMenuLayoutModule.forRoot(),
+ ],
+ // ...
+})
+export class AppModule {}
+```
+
+Note: If you employ [Resource Owner Password Flow](https://docs.abp.io/en/abp/latest/UI/Angular/Authorization#resource-owner-password-flow) for authorization, you should import the following module as well:
+
+```js
+import { AccountLayoutModule } from '@abp/ng.theme.lepton-x/account';
+
+@NgModule({
+ // ...
+ imports: [
+ // ...
+ AccountLayoutModule.forRoot(),
+ // ...
+ ],
+ // ...
+})
+export class AppModule {}
+```
+
+To change the logos and brand color of the `LeptonX`, simply add the following CSS to the `styles.scss`
+
+```css
+:root {
+ --lpx-logo: url('/assets/images/logo.png');
+ --lpx-logo-icon: url('/assets/images/logo-icon.png');
+ --lpx-brand: #edae53;
+}
+```
+
+- `--lpx-logo` is used to place the logo in the menu.
+- `--lpx-logo-icon` is a square icon used when the menu is collapsed.
+- `--lpx-brand` is a color used throughout the application, especially on active elements.
+
+
+
+
+
+## ABP Commercial
+
+This section shows how to replace the lepton theme (that comes with the ABP Commercial startup template) with the new LeptonX theme.
+
+To add `LeptonX` into your existing projects,
+
+* Firstly, install `@volosoft/abp.ng.theme.lepton-x` NPM package
+
+`npm install @volosoft/abp.ng.theme.lepton-x@preview` or
+
+`yarn add @volosoft/abp.ng.theme.lepton-x@preview`
+
+* Then, edit `angular.json` as follows:
+
+Remove the following config from the `styles` array since LeptonX provides bootstrap as embedded in its CSS.
+
+```JSON
+{
+ "input": "node_modules/bootstrap/dist/css/bootstrap.min.css",
+ "inject": true,
+ "bundleName": "bootstrap-ltr.min"
+},
+```
+
+Add the following ones into the `styles` array
+
+```JSON
+{
+ "input": "node_modules/@volosoft/ngx-lepton-x/styles/themes/dark.css",
+ "inject": false,
+ "bundleName": "lepton-x.dark"
+},
+{
+ "input": "node_modules/@volosoft/ngx-lepton-x/styles/themes/dim.css",
+ "inject": false,
+ "bundleName": "lepton-x.dim"
+},
+{
+ "input": "node_modules/@volosoft/ngx-lepton-x/styles/themes/light.css",
+ "inject": false,
+ "bundleName": "lepton-x.light"
+},
+"node_modules/@volosoft/ngx-lepton-x/styles/css/sidemenu-layout.min.css",
+"node_modules/bootstrap-icons/font/bootstrap-icons.css",
+```
+
+Three of them are related to the theming and will be loaded during runtime. That's why they are not injected into the `head` as a style. Hence, the `"inject": false`
+
+The fourth one depends on which layout you want to use. For now, there is only `sidemenu-layout` available. In the future, there will be many layouts to choose from.
+
+The last one is `bootstrap-icons` which are being used throughout the components.
+
+* At last, remove `ThemeLeptonModule` from `app.module.ts` and `shared.module.ts`, and import the following modules in `app.module.ts`
+
+```js
+import { ThemeLeptonXModule } from '@volosoft/abp.ng.theme.lepton-x';
+import { AbpSideMenuLayoutModule } from '@volosoft/abp.ng.theme.lepton-x/layouts';
+
+@NgModule({
+ // ...
+ imports: [
+ // ...
+ ThemeLeptonXModule.forRoot(),
+ AbpSideMenuLayoutModule.forRoot(), // depends on which layout you choose
+ // ...
+ ],
+ // ...
+})
+export class AppModule {}
+```
+
+Note: If you employ [Resource Owner Password Flow](https://docs.abp.io/en/abp/latest/UI/Angular/Authorization#resource-owner-password-flow) for authorization, you should import the following module as well:
+
+```js
+import { AccountLayoutModule } from '@volosoft/abp.ng.theme.lepton-x/account';
+
+@NgModule({
+ // ...
+ imports: [
+ // ...
+ AccountLayoutModule.forRoot({
+ layout: {
+ authLayoutImg: '/assets/images/login-bg.jpg',
+ },
+ }),
+ // ...
+ ],
+ // ...
+})
+export class AppModule {}
+```
+
+`authLayoutImg`: (Optional) If not given, a default image will be placed on the authentication pages.
+
+
+* At this point, `LeptonX` theme should be up and running within your application. However, you may need to overwrite some css variables based your needs for every theme available as follows:
+```scss
+:root {
+ .lpx-theme-dark {
+ --lpx-logo: url('/assets/images/logo/logo-light.svg');
+ --lpx-logo-icon: url('/assets/images/logo/logo-light-icon.svg');
+ --lpx-brand: #edae53;
+ }
+
+ .lpx-theme-dim {
+ --lpx-logo: url('/assets/images/logo/logo-light.svg');
+ --lpx-logo-icon: url('/assets/images/logo/logo-light-icon.svg');
+ --lpx-brand: #f15835;
+ }
+
+ .lpx-theme-light {
+ --lpx-logo: url('/assets/images/logo/logo-dark.svg');
+ --lpx-logo-icon: url('/assets/images/logo/logo-dark-icon.svg');
+ --lpx-brand: #69aada;
+ }
+}
+```
+
+When the user selects a theme, the corresponding CSS class is added to the `body`, so you can write specific CSS rules to each theme.
+
+## Conclusion
+
+In this blog post, I've explained how to use the alpha version of the new LeptonX theme for ABP-based solutions. Please, keep in mind that this is an alpha version, and we will continue to work on the LeptonX theme. The APIs are bound to change and breaking changes may be introduced in future versions.
+
+We would like you to try it out with the latest version of the ABP Framework and give us feedback at lepton@volosoft.com or open an issue on this repository: https://github.com/volosoft/lepton-theme
diff --git a/docs/en/Blog-Posts/2021-07-28-lepton-x-release/lepton-x-lite-dashboard.png b/docs/en/Blog-Posts/2021-07-28-lepton-x-release/lepton-x-lite-dashboard.png
new file mode 100644
index 0000000000..6c1ed170fc
Binary files /dev/null and b/docs/en/Blog-Posts/2021-07-28-lepton-x-release/lepton-x-lite-dashboard.png differ
diff --git a/docs/en/Blog-Posts/2021-07-28-lepton-x-release/lepton-x-lite-menu-collapsed.png b/docs/en/Blog-Posts/2021-07-28-lepton-x-release/lepton-x-lite-menu-collapsed.png
new file mode 100644
index 0000000000..36cc5014d3
Binary files /dev/null and b/docs/en/Blog-Posts/2021-07-28-lepton-x-release/lepton-x-lite-menu-collapsed.png differ
diff --git a/docs/en/Blog-Posts/2021-08-02 v4_4_Release_Stable/POST.md b/docs/en/Blog-Posts/2021-08-02 v4_4_Release_Stable/POST.md
new file mode 100644
index 0000000000..a2c812bb74
--- /dev/null
+++ b/docs/en/Blog-Posts/2021-08-02 v4_4_Release_Stable/POST.md
@@ -0,0 +1,42 @@
+# ABP.IO Platform 4.4 Final Has Been Released!
+
+[ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) 4.4 versions have been released today.
+
+## What's New With 4.4?
+
+Since all the new features are already explained in details with the 4.4 RC announcement posts, I will not repeat all the details again. See [the related blog post](https://blog.abp.io/abp/ABP-Platform-4-4-RC-Has-Been-Released) for all the features and enhancements.
+
+## How to Upgrade an Existing Solution
+
+### Install/Update the ABP CLI
+
+First of all, install the ABP CLI or upgrade to the latest version.
+
+If you haven't installed yet:
+
+```bash
+dotnet tool install -g Volo.Abp.Cli
+```
+
+To update an existing installation:
+
+```bash
+dotnet tool update -g Volo.Abp.Cli
+```
+
+### ABP UPDATE Command
+
+[ABP CLI](https://docs.abp.io/en/abp/latest/CLI) provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:
+
+```bash
+abp update
+```
+
+Run this command in the root folder of your solution.
+
+## The Road Map
+
+The next feature version will be 5.0. It is planned to release the 5.0 RC (Release Candidate) in November 2021. See the updated road maps;
+
+* [ABP Framework Road Map](https://docs.abp.io/en/abp/latest/Road-Map)
+* [ABP Commercial Road Map](https://docs.abp.io/en/commercial/latest/road-map)
\ No newline at end of file
diff --git a/docs/en/Community-Articles/2020-05-29-Real-Time-Messaging-In-A-Distributed-Architecture-Using-Abp-Framework-SingalR-RabbitMQ/POST.md b/docs/en/Community-Articles/2020-05-29-Real-Time-Messaging-In-A-Distributed-Architecture-Using-Abp-Framework-SingalR-RabbitMQ/POST.md
index 915d4ef5c1..eea0eaae46 100644
--- a/docs/en/Community-Articles/2020-05-29-Real-Time-Messaging-In-A-Distributed-Architecture-Using-Abp-Framework-SingalR-RabbitMQ/POST.md
+++ b/docs/en/Community-Articles/2020-05-29-Real-Time-Messaging-In-A-Distributed-Architecture-Using-Abp-Framework-SingalR-RabbitMQ/POST.md
@@ -168,7 +168,7 @@ namespace SignalRTieredDemo.Web
{
````
-Also, we need to add [@abp/signalr](https://www.npmjs.com/package/@abp/signalr) npm package to package.json in ***.Web** project, then run **yarn** and **gulp** commands.
+Also, we need to add [@abp/signalr](https://www.npmjs.com/package/@abp/signalr) npm package to package.json in ***.Web** project, then run **abp install-libs** command.
`````json
{
diff --git a/docs/en/Community-Articles/2020-08-18-Using-DevExtreme-Components-With-The-ABP-Framework/Using-DevExtreme-Components-With-The-ABP-Framework.md b/docs/en/Community-Articles/2020-08-18-Using-DevExtreme-Components-With-The-ABP-Framework/Using-DevExtreme-Components-With-The-ABP-Framework.md
index 93ed01d05c..fdaaefbea1 100644
--- a/docs/en/Community-Articles/2020-08-18-Using-DevExtreme-Components-With-The-ABP-Framework/Using-DevExtreme-Components-With-The-ABP-Framework.md
+++ b/docs/en/Community-Articles/2020-08-18-Using-DevExtreme-Components-With-The-ABP-Framework/Using-DevExtreme-Components-With-The-ABP-Framework.md
@@ -77,9 +77,11 @@ module.exports = {
};
```
-Open your `DevExtremeSample.Web` project folder with a command line and run the `gulp` command. This command will copy the needed library files into the ``/wwwroot/libs/devextreme/` folder.
+Open your `DevExtremeSample.Web` project folder with a command line and run the `abp install-libs` command. This command will copy the needed library files into the `/wwwroot/libs/devextreme/` folder.
-
+````bash
+abp install-libs
+````
You can see `devextreme` folder inside the `wwwroot/libs`:
diff --git a/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/POST.md b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/POST.md
index 8aeff16612..a53fec2e48 100644
--- a/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/POST.md
+++ b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/POST.md
@@ -91,7 +91,7 @@ You can install the latest version (3.1.13 will be old)
#### 3- Add resource Mapping
-We added SignalR to the `package.json` but it comes into your `node_modules` folder. We need to copy the related files to `wwwroot/libs` folder. To do this copy the content of the following file to your `abp.resourcemappings.js` file. It's in your root directory of Web folder. After you do this, go to your web directory and run `gulp` command. By doing this, it'll copy the related files into your `wwwroot/libs` folder.
+We added SignalR to the `package.json` but it comes into your `node_modules` folder. We need to copy the related files to `wwwroot/libs` folder. To do this copy the content of the following file to your `abp.resourcemappings.js` file. It's in your root directory of Web folder. After you do this, go to your web directory and run `abp install-libs` command. By doing this, it'll copy the related files into your `wwwroot/libs` folder.
[abp.resourcemappings.js](https://gist.github.com/ebicoglu/f7dc22cca2d353f8bf7f68a03e3395b8#file-abp-resourcemapping-js)
diff --git a/docs/en/Community-Articles/2021-05-24-Removing-EfCore-Migrations/POST.md b/docs/en/Community-Articles/2021-05-24-Removing-EfCore-Migrations/POST.md
index 15fbbc4678..d8fa243c3b 100644
--- a/docs/en/Community-Articles/2021-05-24-Removing-EfCore-Migrations/POST.md
+++ b/docs/en/Community-Articles/2021-05-24-Removing-EfCore-Migrations/POST.md
@@ -30,7 +30,7 @@ If you want to make it in your solution with today, follow the steps in this art
> There is one **drawback** with the new design (everything in software development is a trade-off). We need to remove the `AppUser` entity, because EF Core can't map two classes to single table without an inheritance relation. I will cover this later in this article and provide suggestions to deal with it.
-> If you are using **ABP Commercial**, ABP Suite code generation won't work correctly with the new design. In this case, we suggest to wait for the next version.
+> If you are using **ABP Commercial**, ABP Suite code generation won't work correctly before the version 4.4. Please upgrade to v4.4 if you are using a previous version.
## The Steps
diff --git a/docs/en/Modules/Docs.md b/docs/en/Modules/Docs.md
index 4c764ee2c6..f848789176 100644
--- a/docs/en/Modules/Docs.md
+++ b/docs/en/Modules/Docs.md
@@ -185,10 +185,11 @@ Open `package.json` and add `@abp/docs": "^2.9.0` as shown below:
}
```
- Then open the command line terminal in the `Acme.MyProject.Web` project folder and run the following command:
+Then open the command line terminal in the `Acme.MyProject.Web` project folder and run the following command:
- 1. `yarn`
- 2. `gulp`
+````bash
+abp install-libs
+````
### 4- Database Integration
diff --git a/docs/en/Modules/Virtual-File-Explorer.md b/docs/en/Modules/Virtual-File-Explorer.md
index bae87ba95a..1a22418937 100644
--- a/docs/en/Modules/Virtual-File-Explorer.md
+++ b/docs/en/Modules/Virtual-File-Explorer.md
@@ -60,8 +60,9 @@ Or you can also manually install nuget package to `Acme.MyProject.Web` project:
Then open the command line terminal in the `Acme.MyProject.Web` project folder and run the following command:
- 1. `yarn`
- 2. `gulp`
+````bash
+abp install-libs
+````
That's all,Now run the application and Navigate to `/VirtualFileExplorer`. You will see virtual file explorer page:
diff --git a/docs/en/SignalR-Integration.md b/docs/en/SignalR-Integration.md
index 29c37e30b2..7ebf4f6539 100644
--- a/docs/en/SignalR-Integration.md
+++ b/docs/en/SignalR-Integration.md
@@ -70,10 +70,10 @@ This will add the `@abp/signalr` to the dependencies in the `package.json` of yo
}
````
-Run the `gulp` in the root folder of your web project:
+Run the following [ABP CLI](CLI.md) command in the root folder of your web project:
````bash
-gulp
+abp install-libs
````
This will copy the SignalR JavaScript files into your project:
diff --git a/docs/en/UI/Angular/Settings.md b/docs/en/UI/Angular/Settings.md
index 0dd29025e5..69794d5d5b 100644
--- a/docs/en/UI/Angular/Settings.md
+++ b/docs/en/UI/Angular/Settings.md
@@ -2,7 +2,7 @@
You can get settings on the client-side using the [config state service](./Config-State.md) if they are allowed by their setting definition on the server-side.
-> This document only explains how settings work in the Angular UI projects. See the [settings document](../../../Settings.md) to understand the ABP setting system.
+> This document only explains how settings work in the Angular UI projects. See the [settings document](../../Settings.md) to understand the ABP setting system.
## Before Use
diff --git a/docs/en/UI/AspNetCore/Basic-Theme.md b/docs/en/UI/AspNetCore/Basic-Theme.md
index 34ea9ac849..e74799a423 100644
--- a/docs/en/UI/AspNetCore/Basic-Theme.md
+++ b/docs/en/UI/AspNetCore/Basic-Theme.md
@@ -15,7 +15,7 @@ The Basic Theme has RTL (Right-to-Left language) support.
* Install the [Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic) NuGet package to your web project.
* Add `AbpAspNetCoreMvcUiBasicThemeModule` into the `[DependsOn(...)]` attribute for your [module class](../../Module-Development-Basics.md) in the web project.
* Install the [@abp/aspnetcore.mvc.ui.theme.basic](https://www.npmjs.com/package/@abp/aspnetcore.mvc.ui.theme.basic) NPM package to your web project (e.g. `npm install @abp/aspnetcore.mvc.ui.theme.basic` or `yarn add @abp/aspnetcore.mvc.ui.theme.basic`).
-* Run `gulp` command in a command line terminal in the web project's folder.
+* Run `abp install-libs` command in a command line terminal in the web project's folder.
## Layouts
diff --git a/docs/en/UI/AspNetCore/Client-Side-Package-Management.md b/docs/en/UI/AspNetCore/Client-Side-Package-Management.md
index 645200a363..eaccc39119 100644
--- a/docs/en/UI/AspNetCore/Client-Side-Package-Management.md
+++ b/docs/en/UI/AspNetCore/Client-Side-Package-Management.md
@@ -18,7 +18,7 @@ To solve the versioning problem, we created a **standard set of packages** those
The benefit of a **standard package** is:
* It depends on a **standard version** of a package. Depending on this package is **safe** because all modules depend on the same version.
-* It contains the gulp task to copy library resources (js, css, img... files) from the **node_modules** folder to **wwwroot/libs** folder. See the *Mapping The Library Resources* section for more.
+* It contains the mappings copy library resources (js, css, img... files) from the **node_modules** folder to **wwwroot/libs** folder. See the *Mapping The Library Resources* section for more.
Depending on a standard package is easy. Just add it to your **package.json** file like you normally do. Example:
@@ -61,7 +61,7 @@ Using NPM packages and NPM/Yarn tool is the de facto standard for client side li
Next challenge is copying needed resources (js, css, img... files) from the `node_modules` into a folder inside the **wwwroot** folder to make it accessible to the clients/browsers.
-ABP defines a [Gulp](https://gulpjs.com/) based task to **copy resources** from **node_modules** to **wwwroot/libs** folder. Each **standard package** (see the *@ABP NPM Packages* section) defines the mapping for its own files. So, most of the time, you only configure dependencies.
+ABP CLI's `abp install-libs` command **copies resources** from **node_modules** to **wwwroot/libs** folder. Each **standard package** (see the *@ABP NPM Packages* section) defines the mapping for its own files. So, most of the time, you only configure dependencies.
The **startup templates** are already configured to work all these out of the box. This section will explain the configuration options.
@@ -100,17 +100,15 @@ mappings: {
}
````
-#### Using The Gulp
+#### install-libs Command
-Once you properly configure the `abp.resourcemapping.js` file, you can run the gulp command from the command line:
+Once you properly configure the `abp.resourcemapping.js` file, you can run the following ABP CLI command from the command line:
+````bash
+abp install-libs
````
-gulp
-````
-
-When you run the `gulp`, all packages will copy their own resources into the **wwwroot/libs** folder. Running `yarn & gulp` is only necessary if you make a change in your dependencies in the **package.json** file.
-> When you run the Gulp command, dependencies of the application are resolved using the package.json file. The Gulp task automatically discovers and maps all resources from all dependencies (recursively).
+When you run this command, all packages will copy their own resources into the **wwwroot/libs** folder. Running `abp install-libs` is only necessary if you make a change in your dependencies in the **package.json** file.
#### See Also
diff --git a/docs/en/Validation.md b/docs/en/Validation.md
index c4821adf65..1d24c5e2a6 100644
--- a/docs/en/Validation.md
+++ b/docs/en/Validation.md
@@ -149,8 +149,8 @@ Once ABP determines a validation error, it throws an exception of type `AbpValid
In addition to the automatic validation, you may want to manually validate an object. In this case, [inject](Dependency-Injection.md) and use the `IObjectValidator` service:
-* `Validate` method validates the given object based on the validation rules and throws an `AbpValidationException` if it is not in a valid state.
-* `GetErrors` doesn't throw an exception, but only returns the validation errors.
+* `ValidateAsync` method validates the given object based on the validation rules and throws an `AbpValidationException` if it is not in a valid state.
+* `GetErrorsAsync` doesn't throw an exception, but only returns the validation errors.
`IObjectValidator` is implemented by the `ObjectValidator` by default. `ObjectValidator` is extensible; you can implement `IObjectValidationContributor` interface to contribute a custom logic. Example:
@@ -158,13 +158,14 @@ In addition to the automatic validation, you may want to manually validate an ob
public class MyObjectValidationContributor
: IObjectValidationContributor, ITransientDependency
{
- public void AddErrors(ObjectValidationContext context)
+ public Task AddErrorsAsync(ObjectValidationContext context)
{
//Get the validating object
var obj = context.ValidatingObject;
//Add the validation errors if available
context.Errors.Add(...);
+ return Task.CompletedTask;
}
}
````
diff --git a/docs/en/Virtual-File-System.md b/docs/en/Virtual-File-System.md
index 307c6e92bc..6cdf9a7649 100644
--- a/docs/en/Virtual-File-System.md
+++ b/docs/en/Virtual-File-System.md
@@ -38,7 +38,7 @@ This configuration recursively adds all files under the **MyResources** folder o
Embedding a file in the project/assembly may cause problems if a file name contains some special chars. To overcome this limitation;
1. Add [Microsoft.Extensions.FileProviders.Embedded](https://www.nuget.org/packages/Microsoft.Extensions.FileProviders.Embedded) NuGet package to the project that contains the embedded resource(s).
-2. Add `true` into the `...` section of your `.csproj` file.
+2. Add `true` into the `...` section of your `.csproj` file.
> While these two steps are optional and ABP can work without these configuration, it is strongly suggested to make it.
@@ -193,4 +193,4 @@ So, if you need to replace a file of a module, just create the file in the exact
### Physical Files
-Physical files always override the virtual files. That means if you put a file under the `/wwwroot/my-folder/my-file.css`, it will override the file in the same location of the virtual file system. So, you need to know the file paths defined in the modules to override them.
\ No newline at end of file
+Physical files always override the virtual files. That means if you put a file under the `/wwwroot/my-folder/my-file.css`, it will override the file in the same location of the virtual file system. So, you need to know the file paths defined in the modules to override them.
diff --git a/docs/pt-BR/MongoDB.md b/docs/pt-BR/MongoDB.md
new file mode 100644
index 0000000000..bc4a7882a7
--- /dev/null
+++ b/docs/pt-BR/MongoDB.md
@@ -0,0 +1,466 @@
+# Integração do MongoDB
+
+Este documento explica como integrar e configurar o MongoDB como um provedor de banco de dados para aplicações baseadas no ABP.
+
+## Instalação
+
+`Volo.Abp.MongoDB` é o pacote nuget principal para a integração do MongoDB. Instale-o em seu projeto (para uma aplicação em camadas, será sua camada de dados ou infraestrutura):
+
+```
+Install-Package Volo.Abp.MongoDB
+```
+
+Então adicione a dependência de módulo `AbpMongoDbModule` para o seu [module](Module-Development-Basics.md):
+
+```c#
+using Volo.Abp.MongoDB;
+using Volo.Abp.Modularity;
+
+namespace MyCompany.MyProject
+{
+ [DependsOn(typeof(AbpMongoDbModule))]
+ public class MyModule : AbpModule
+ {
+ // ...
+ }
+}
+```
+
+## Criando um Mongo Db Context
+
+ABP apresenta o conceito **Mongo Db Context** (que é semelhante ao Entity Framework Core DbContext) para tornar mais fácil usar coleções e configurá-las. Um exemplo é mostrado abaixo:
+
+```c#
+public class MyDbContext : AbpMongoDbContext
+{
+ public IMongoCollection Questions => Collection();
+
+ public IMongoCollection Categories => Collection();
+
+ protected override void CreateModel(IMongoModelBuilder modelBuilder)
+ {
+ base.CreateModel(modelBuilder);
+
+ // Personalize a configuração para as suas collections.
+ }
+}
+```
+
+* É derivado da classe `AbpMongoDbContext`.
+* Adiciona uma propriedade pública `IMongoCollection` para cada mongo collection. Por padrão ABP usa essas propriedades para criar repositórios padrão.
+* Substituir o método `CreateModel` permite definir a configuração da collection.
+
+### Configurar o Mapeamento para uma Collection
+
+ABP registra automaticamente entidades MongoDB client library para todas propriedades `IMongoCollection` em seu DbContext. Para o exemplo acima, as entidades `Question` e `Category` são registradas automaticamente.
+
+Para cada entidade registrada, chama `AutoMap()` e configura propriedades conhecidas de sua entidade. Por exemplo, se sua entidade implementa uma interface `IHasExtraProperties` (que já está implementada para cada raiz agregada por padrão), ele configura automaticamente `ExtraProperties`.
+
+Portanto, na maioria das vezes, você não precisa configurar explicitamente o registro de suas entidades. No entanto, se você precisar, pode fazer isso sobrescrevendo o método `CreateModel` em seu DbContext. Exemplo:
+
+````csharp
+protected override void CreateModel(IMongoModelBuilder modelBuilder)
+{
+ base.CreateModel(modelBuilder);
+
+ modelBuilder.Entity(b =>
+ {
+ b.CollectionName = "MyQuestions"; // Define o nome da collection
+ b.BsonMap.UnmapProperty(x => x.MyProperty); // Ignora 'MyProperty'
+ });
+}
+````
+
+Este exemplo altera o nome da collection mapeada para 'MyQuestions' no banco de dados e ignora uma propriedade na classe `Question`.
+
+Se você só precisa configurar o nome da collection, você também pode usar o atributo `[MongoCollection]` para a collection em seu DbContext. Exemplo:
+
+````csharp
+[MongoCollection("MyQuestions")] // Define o nome da collection
+public IMongoCollection Questions => Collection();
+````
+
+### Configurar a Seleção da String de Conexão
+
+Se você tiver vários bancos de dados em seu aplicativo, você pode configurar o nome da string de conexão para o seu DbContext usando o atributo `[ConnectionStringName]`. Exemplo:
+
+````csharp
+[ConnectionStringName("MySecondConnString")]
+public class MyDbContext : AbpMongoDbContext
+{
+
+}
+````
+
+Se você não configurar, a string de conexão `Default` é usada. Se você configurar um nome de string de conexão, mas não definir este nome da string de conexão na configuração da aplicação, então ele retorna para a string de conexão `Default`.
+
+## Registrando DbContext para Injeção de Dependência
+
+Use o método `AddAbpDbContext` em seu module para registrar sua classe DbContext para o sistema de [injeção de dependência](Dependency-Injection.md).
+
+```c#
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.MongoDB;
+using Volo.Abp.Modularity;
+
+namespace MyCompany.MyProject
+{
+ [DependsOn(typeof(AbpMongoDbModule))]
+ public class MyModule : AbpModule
+ {
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ context.Services.AddMongoDbContext();
+
+ // ...
+ }
+ }
+}
+```
+
+### Adicionar Repositories Padrão
+
+O ABP pode criar automaticamente [repositories genéricas](Repositories.md) padrão para as entidades em seu DbContext. Basta usar a opção `AddDefaultRepositories()` no registro:
+
+````C#
+services.AddMongoDbContext(options =>
+{
+ options.AddDefaultRepositories();
+});
+````
+
+Isso criará uma repository para cada [aggregate root entity](Entities.md) (classes derivadas de `AggregateRoot`) por padrão. Se você quiser criar repositories para outras entidades também, em seguida defina `includeAllEntities` para `true`:
+
+```c#
+services.AddMongoDbContext(options =>
+{
+ options.AddDefaultRepositories(includeAllEntities: true);
+});
+```
+
+Então você pode injetar e usar `IRepository` nas suas services. Suponha que você tenha uma entidade `Book` com a chave primária `Guid`:
+
+```csharp
+public class Book : AggregateRoot
+{
+ public string Name { get; set; }
+
+ public BookType Type { get; set; }
+}
+```
+
+(`BookType` é um simples `enum` aqui) E você deseja criar uma nova entidade `Book` em uma [domain service](Domain-Services.md):
+
+```csharp
+public class BookManager : DomainService
+{
+ private readonly IRepository _bookRepository;
+
+ public BookManager(IRepository bookRepository) // injetar repositório padrão
+ {
+ _bookRepository = bookRepository;
+ }
+
+ public async Task CreateBook(string name, BookType type)
+ {
+ Check.NotNullOrWhiteSpace(name, nameof(name));
+
+ var book = new Book
+ {
+ Id = GuidGenerator.Create(),
+ Name = name,
+ Type = type
+ };
+
+ await _bookRepository.InsertAsync(book); // Use um método de repositório padrão
+
+ return book;
+ }
+}
+```
+
+Este exemplo usa o método `InsertAsync` para inserir uma nova entity no banco de dados.
+
+### Adicionar Repositories Personalizadas
+
+Repositories genéricas padrão são poderosas e suficiente na maioria dos casos (uma vez que implementam `IQueryable`). No entanto, pode ser necessário criar uma repository customizada para adicionar seus próprios métodos de repository.
+
+Suponha que você deseja excluir todos os books por type. É sugerido definir uma interface para sua repository personalizada:
+
+```csharp
+public interface IBookRepository : IRepository
+{
+ Task DeleteBooksByType(
+ BookType type,
+ CancellationToken cancellationToken = default(CancellationToken)
+ );
+}
+```
+
+Você geralmente vai querer derivar de `IRepository` para herdar métodos de repository padrão. No entanto, você não precisa. As interfaces de repository são definidas na camada de domínio de uma aplicação em camadas. Elas são implementadas na camada de dados ou infraestrutura (projeto `MongoDB` em um [startup template](https://abp.io/Templates)).
+
+Exemplo de implementação da interface `IBookRepository`:
+
+```csharp
+public class BookRepository :
+ MongoDbRepository,
+ IBookRepository
+{
+ public BookRepository(IMongoDbContextProvider dbContextProvider)
+ : base(dbContextProvider)
+ {
+ }
+
+ public async Task DeleteBooksByType(
+ BookType type,
+ CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var collection = await GetCollectionAsync(cancellationToken);
+ await collection.DeleteManyAsync(
+ Builders.Filter.Eq(b => b.Type, type),
+ cancellationToken
+ );
+ }
+}
+```
+
+Agora é possível [injetar](Dependency-Injection.md) a `IBookRepository` e usar o método `DeleteBooksByType` quando necessário.
+
+#### Substituir Repository Genérica Padrão
+
+Mesmo se você criar uma repository personalizada, você ainda pode injetar a repository genérica padrão (`IRepository` para este exemplo). A implementação da repository padrão não usará a classe que você criou.
+
+Se você querer substituir a implementação da repository padrão pela sua repository personalizada, faça dentro das opções `AddMongoDbContext`:
+
+```csharp
+context.Services.AddMongoDbContext(options =>
+{
+ options.AddDefaultRepositories();
+ options.AddRepository(); //Replaces IRepository
+});
+```
+
+Isso é especialmente importante quando você deseja dar **override em um método da base repository** para customizar. Por exemplo, você pode querer substituir o método `DeleteAsync` para excluir uma entidade de uma forma mais eficiente:
+
+```csharp
+public async override Task DeleteAsync(
+ Guid id,
+ bool autoSave = false,
+ CancellationToken cancellationToken = default)
+{
+ // TODO: Implementação customizada do método delete
+}
+```
+
+### Acesso à API MongoDB
+
+Na maioria dos casos, você vai querer ocultar APIs do MongoDB atrás de uma repository (este é o objetivo principal da repository). No entanto, se você quiser acessar a API MongoDB através da Repository, você pode usar os métodos de extensão `GetDatabaseAsync()`, `GetCollectionAsync()` ou `GetAggregateAsync()`. Exemplo:
+
+```csharp
+public class BookService
+{
+ private readonly IRepository _bookRepository;
+
+ public BookService(IRepository bookRepository)
+ {
+ _bookRepository = bookRepository;
+ }
+
+ public async Task FooAsync()
+ {
+ IMongoDatabase database = await _bookRepository.GetDatabaseAsync();
+ IMongoCollection books = await _bookRepository.GetCollectionAsync();
+ IAggregateFluent bookAggregate = await _bookRepository.GetAggregateAsync();
+ }
+}
+```
+
+> Importante: Você deve fazer referência ao pacote `Volo.Abp.MongoDB` do projeto que deseja acessar a API MongoDB. Isso quebra o encapsulamento, mas é o que você deseja nesse caso.
+
+### Transactions
+
+O MongoDB oferece suporte multi-document transactions a partir da versão 4.0 e o ABP Framework oferece suporte para isso. No entanto, o [startup template](Startup-templates/Index.md) **desativa** transactions por padrão. Se o seu **servidor** MongoDB suportar transactions, você pode habilitar esse recurso na classe *YourProjectMongoDbModule*:
+
+```csharp
+Configure(options =>
+{
+ options.TransactionBehavior = UnitOfWorkTransactionBehavior.Auto;
+});
+```
+
+> Ou você pode excluir este código, pois este já é o comportamento padrão.
+
+### Tópicos Avançados
+
+### Controlando o Multi-Tenancy
+
+Se sua solução for [multi-tenant](Multi-Tenancy.md), os tenants podem ter **bancos de dados separados**, você tem **múltiplas** classes `DbContext` em sua solução e algumas de suas classes `DbContext` devem ser utilizáveis **apenas do lado do host**, é recomendado adicionar o atributo `[IgnoreMultiTenancy]` em sua classe `DbContext`. Nesse caso, a ABP garante que o `DbContext` relacionado sempre usa a [connection string](Connection-Strings.md) do host, mesmo se você estiver em um tenant context.
+
+**Exemplo:**
+
+````csharp
+[IgnoreMultiTenancy]
+public class MyDbContext : AbpMongoDbContext
+{
+ ...
+}
+````
+
+Não use o atributo `[IgnoreMultiTenancy]` se qualquer uma de suas entidades em seu `DbContext` puder ser persistida em um outro banco de dados de um tenant.
+
+> When you use repositories, ABP already uses the host database for the entities don't implement the `IMultiTenant` interface. So, most of time you don't need to `[IgnoreMultiTenancy]` attribute if you are using the repositories to work with the database.
+
+#### Definir Classes Repository Padrão
+
+Repositories genéricas padrão são implementadas pela classe `MongoDbRepository` por padrão. Você pode criar sua própria implementação e usá-la para implementação da repository padrão.
+
+Primeiro, defina suas classes de repository assim:
+
+```csharp
+public class MyRepositoryBase
+ : MongoDbRepository
+ where TEntity : class, IEntity
+{
+ public MyRepositoryBase(IMongoDbContextProvider dbContextProvider)
+ : base(dbContextProvider)
+ {
+ }
+}
+
+public class MyRepositoryBase
+ : MongoDbRepository
+ where TEntity : class, IEntity
+{
+ public MyRepositoryBase(IMongoDbContextProvider dbContextProvider)
+ : base(dbContextProvider)
+ {
+ }
+}
+```
+
+O primeiro é para [entities com chaves compostas](Entities.md), o segundo é para entities com uma única chave primária.
+
+É sugerido herdar da classe `MongoDbRepository` e substituir os métodos, se necessário. Caso contrário, você terá que implementar todos os métodos de repository padrão manualmente.
+
+Agora, você pode usar a opção `SetDefaultRepositoryClasses`:
+
+```csharp
+context.Services.AddMongoDbContext(options =>
+{
+ options.SetDefaultRepositoryClasses(
+ typeof(MyRepositoryBase<,>),
+ typeof(MyRepositoryBase<>)
+ );
+ // ...
+});
+```
+
+#### Definir classe base MongoDbContext ou Interface para Repositories padrão
+
+Se seu MongoDbContext herda de outro MongoDbContext ou implementa uma interface, você pode usar essa classe base ou interface como o MongoDbContext para repositories padrão. Exemplo:
+
+```csharp
+public interface IBookStoreMongoDbContext : IAbpMongoDbContext
+{
+ Collection Books { get; }
+}
+```
+
+`IBookStoreMongoDbContext` é implementado pela classe `BookStoreMongoDbContext`. Então você pode usar sobrecarga genérica do `AddDefaultRepositories`:
+
+```csharp
+context.Services.AddMongoDbContext(options =>
+{
+ options.AddDefaultRepositories();
+ // ...
+});
+```
+
+Agora, seu `BookRepository` personalizado também pode usar a interface `IBookStoreMongoDbContext`:
+
+```csharp
+public class BookRepository
+ : MongoDbRepository,
+ IBookRepository
+{
+ // ...
+}
+```
+
+Uma vantagem de usar a interface para um MongoDbContext é que ela pode ser substituída por outra implementação.
+
+#### Substituir Outros DbContexts
+
+Depois de definir e usar adequadamente uma interface para um MongoDbContext, qualquer outra implementação pode usar as seguintes maneiras de substituí-lo:
+
+**ReplaceDbContextAttribute**
+
+```csharp
+[ReplaceDbContext(typeof(IBookStoreMongoDbContext))]
+public class OtherMongoDbContext : AbpMongoDbContext, IBookStoreMongoDbContext
+{
+ // ...
+}
+```
+
+**Opção ReplaceDbContext**
+
+```csharp
+context.Services.AddMongoDbContext(options =>
+{
+ // ...
+ options.ReplaceDbContext();
+});
+```
+
+Neste exemplo, `OtherMongoDbContext` implementa `IBookStoreMongoDbContext`. Este recurso permite que você tenha vários MongoDbContext (um por módulo) no desenvolvimento, mas um único MongoDbContext (implementa todas as interfaces de todos os MongoDbContexts) no tempo de execução.
+
+### Personalizar Operações em Massa
+
+Se você tiver uma lógica melhor ou usar uma biblioteca externa para operações em massa, pode substituir a lógica por meio da implementação de `IMongoDbBulkOperationProvider`.
+
+- Você pode usar o modelo de exemplo abaixo:
+
+```csharp
+public class MyCustomMongoDbBulkOperationProvider
+ : IMongoDbBulkOperationProvider, ITransientDependency
+{
+ public async Task DeleteManyAsync(
+ IMongoDbRepository repository,
+ IEnumerable entities,
+ IClientSessionHandle sessionHandle,
+ bool autoSave,
+ CancellationToken cancellationToken)
+ where TEntity : class, IEntity
+ {
+ // Sua lógica aqui.
+ }
+
+ public async Task InsertManyAsync(
+ IMongoDbRepository repository,
+ IEnumerable entities,
+ IClientSessionHandle sessionHandle,
+ bool autoSave,
+ CancellationToken cancellationToken)
+ where TEntity : class, IEntity
+ {
+ // Sua lógica aqui.
+ }
+
+ public async Task UpdateManyAsync(
+ IMongoDbRepository repository,
+ IEnumerable entities,
+ IClientSessionHandle sessionHandle,
+ bool autoSave,
+ CancellationToken cancellationToken)
+ where TEntity : class, IEntity
+ {
+ // Sua lógica aqui.
+ }
+}
+```
+
+## Veja Também
+
+* [Entities](Entities.md)
+* [Repositories](Repositories.md)
\ No newline at end of file
diff --git a/docs/zh-Hans/Modules/Docs.md b/docs/zh-Hans/Modules/Docs.md
index 1d09552e50..7b651fd821 100644
--- a/docs/zh-Hans/Modules/Docs.md
+++ b/docs/zh-Hans/Modules/Docs.md
@@ -186,8 +186,9 @@ ABP框架的[文档](docs.abp.io)也是使用的此模块.
然后在 `Acme.MyProject.Web` 项目目录打开命令行终端运行以下命令:
- 1. `yarn`
- 2. `gulp`
+````bash
+abp install-libs
+````
### 4- 数据库集成
diff --git a/docs/zh-Hans/Modules/Virtual-File-Explorer.md b/docs/zh-Hans/Modules/Virtual-File-Explorer.md
index 024b3d23df..e70306f13c 100644
--- a/docs/zh-Hans/Modules/Virtual-File-Explorer.md
+++ b/docs/zh-Hans/Modules/Virtual-File-Explorer.md
@@ -60,8 +60,9 @@
然后在 `Acme.MyProject.Web` 项目目录打开命令行终端运行以下命令:
- 1. `yarn`
- 2. `gulp`
+````bash
+abp install-libs
+````
这就是全部,运行应用程序导航到 `/VirtualFileExplorer`. 你会看到虚拟文件浏览器页面:
diff --git a/docs/zh-Hans/SignalR-Integration.md b/docs/zh-Hans/SignalR-Integration.md
index bdf4a7a786..7adc75daa4 100644
--- a/docs/zh-Hans/SignalR-Integration.md
+++ b/docs/zh-Hans/SignalR-Integration.md
@@ -70,10 +70,10 @@ yarn add @abp/signalr
}
````
-在你的Web项目的根文件夹中运行 `gulp`:
+在你的Web项目的根文件夹中运行 `abp install-libs`:
````bash
-gulp
+abp install-libs
````
它会将SignalR JavaScript文件拷贝到你的项目:
diff --git a/docs/zh-Hans/UI/AspNetCore/Client-Side-Package-Management.md b/docs/zh-Hans/UI/AspNetCore/Client-Side-Package-Management.md
index 2c50064be0..f11866404b 100644
--- a/docs/zh-Hans/UI/AspNetCore/Client-Side-Package-Management.md
+++ b/docs/zh-Hans/UI/AspNetCore/Client-Side-Package-Management.md
@@ -18,7 +18,7 @@ ABP是一个模块化平台. 每个开发人员都可以创建模块, 模块应
**标准包**的好处是:
* 它取决于包装的**标准版本**. 取决于此包是**安全**,因为所有模块都依赖于相同的版本.
-* 它包含将库资源(js,css,img...文件)从**node_modules**文件夹复制到**wwwroot/libs**文件夹的gulp任务. 有关更多信息, 请参阅 *映射库资源* 部分.
+* 它包含将库资源(js,css,img...文件)从**node_modules**文件夹复制到**wwwroot/libs**文件夹. 有关更多信息, 请参阅 *映射库资源* 部分.
依赖标准包装很容易. 只需像往常一样将它添加到**package.json**文件中. 例如:
@@ -61,7 +61,7 @@ yarn
下一个挑战是将所需的资源(js,css,img ...文件)从`node_modules`复制到**wwwroot**文件夹内的文件夹中,以使其可供客户端/浏览器访问.
-ABP将基于[Gulp](https://gulpjs.com/)的任务定义为**将资源**从**node_modules**复制到**wwwroot/libs**文件夹. 每个**标准包**(参见*@ABP NPM Packages*部分)定义了自己文件的映射. 因此, 大多数情况你只配置依赖项.
+ABP的 `install-libs` 命令**将资源**从**node_modules**复制到**wwwroot/libs**文件夹. 每个**标准包**(参见*@ABP NPM Packages*部分)定义了自己文件的映射. 因此, 大多数情况你只配置依赖项.
**启动模板**已经配置为开箱即用的所有这些. 本节将介绍配置选项.
@@ -97,17 +97,15 @@ mappings: {
}
````
-#### 使用 Gulp
+#### install-libs 命令
-正确配置`abp.resourcemapping.js`文件后, 可以从命令行运行gulp命令:
+正确配置`abp.resourcemapping.js`文件后, 可以从命令行运行ABP CLI命令:
+````bash
+abp install-libs
````
-gulp
-````
-
-当你运行`gulp`时,所有包都会将自己的资源复制到**wwwroot/libs**文件夹中. 只有在**package.json**文件中对依赖项进行更改时, 才需要运行`yarn&gulp`.
-> 运行Gulp命令时, 使用package.json文件解析应用程序的依赖关系. Gulp任务自动发现并映射来自所有依赖项的所有资源(递归).
+当你运行这个命令时,所有包都会将自己的资源复制到**wwwroot/libs**文件夹中. 只有在**package.json**文件中对依赖项进行更改时, 才需要运行`abp install-libs`.
#### 参见
diff --git a/docs/zh-Hans/Validation.md b/docs/zh-Hans/Validation.md
index f6b2daf31f..6e46b07aed 100644
--- a/docs/zh-Hans/Validation.md
+++ b/docs/zh-Hans/Validation.md
@@ -130,8 +130,8 @@ namespace Acme.BookStore
除了自动验证你可能需要手动验证对象,这种情况下[注入](Dependency-Injection.md)并使用 `IObjectValidator` 服务:
-* `Validate` 方法根据验证规则验证给定对象,如果对象没有被验证通过会抛出 `AbpValidationException` 异常.
-* `GetErrors` 不会抛出异常,只返回验证错误.
+* `ValidateAsync` 方法根据验证规则验证给定对象,如果对象没有被验证通过会抛出 `AbpValidationException` 异常.
+* `GetErrorsAsync` 不会抛出异常,只返回验证错误.
`IObjectValidator` 默认由 `ObjectValidator` 实现. `ObjectValidator`是可扩展的; 可以实现`IObjectValidationContributor`接口提供自定义逻辑.
示例 :
@@ -140,13 +140,14 @@ namespace Acme.BookStore
public class MyObjectValidationContributor
: IObjectValidationContributor, ITransientDependency
{
- public void AddErrors(ObjectValidationContext context)
+ public Task AddErrorsAsync(ObjectValidationContext context)
{
//Get the validating object
var obj = context.ValidatingObject;
//Add the validation errors if available
context.Errors.Add(...);
+ return Task.CompletedTask;
}
}
````
diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln
index 0605f5c103..8d5432f4c6 100644
--- a/framework/Volo.Abp.sln
+++ b/framework/Volo.Abp.sln
@@ -383,6 +383,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.TextTemplating.Scr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.MongoDB.Tests.SecondContext", "test\Volo.Abp.MongoDB.Tests.SecondContext\Volo.Abp.MongoDB.Tests.SecondContext.csproj", "{90B1866A-EF99-40B9-970E-B898E5AA523F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Threading.Tests", "test\Volo.Abp.Threading.Tests\Volo.Abp.Threading.Tests.csproj", "{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1141,6 +1143,10 @@ Global
{90B1866A-EF99-40B9-970E-B898E5AA523F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{90B1866A-EF99-40B9-970E-B898E5AA523F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{90B1866A-EF99-40B9-970E-B898E5AA523F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1334,6 +1340,7 @@ Global
{C996F458-98FB-483D-9306-4701290E2FC1} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{90B1866A-EF99-40B9-970E-B898E5AA523F} = {447C8A77-E5F0-4538-8687-7383196D04EA}
+ {7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B} = {447C8A77-E5F0-4538-8687-7383196D04EA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/JwtTokenMiddleware.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/ApplicationBuilderAbpJwtTokenMiddlewareExtension.cs
similarity index 100%
rename from framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/JwtTokenMiddleware.cs
rename to framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/ApplicationBuilderAbpJwtTokenMiddlewareExtension.cs
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Properties/launchSettings.json b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Properties/launchSettings.json
deleted file mode 100644
index f52562c96c..0000000000
--- a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Properties/launchSettings.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:53601/",
- "sslPort": 44330
- }
- },
- "profiles": {
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "Volo.Abp.AspNetCore.Authentication.OAuth": {
- "commandName": "Project",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- },
- "applicationUrl": "https://localhost:5001;http://localhost:5000"
- }
- }
-}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj
index 18e9a271dc..fc925f4a60 100644
--- a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj
@@ -13,6 +13,7 @@
falsetrueLibrary
+ true
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Volo.Abp.AspNetCore.Components.Server.Theming.csproj b/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Volo.Abp.AspNetCore.Components.Server.Theming.csproj
index 8f5984fe81..2810a113c4 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Volo.Abp.AspNetCore.Components.Server.Theming.csproj
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Volo.Abp.AspNetCore.Components.Server.Theming.csproj
@@ -7,6 +7,7 @@
net5.0trueLibrary
+ true
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj
index 86d870d2ca..09bf406c74 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj
@@ -7,6 +7,7 @@
net5.0trueLibrary
+ true
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs
index 58398b651a..91b672b073 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs
@@ -25,18 +25,19 @@ namespace Volo.Abp.AspNetCore.Components.Server
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
- context.Services.AddServerSideBlazor();
-
+ var serverSideBlazorBuilder = context.Services.AddServerSideBlazor();
+ context.Services.ExecutePreConfiguredActions(serverSideBlazorBuilder);
+
Configure(options =>
{
options.IgnoredUrls.AddIfNotContains("/_blazor");
});
-
+
Configure(options =>
{
options.IgnoredUrls.AddIfNotContains("/_blazor");
});
-
+
Configure(options =>
{
options.EndpointConfigureActions.Add(endpointContext =>
@@ -56,4 +57,4 @@ namespace Volo.Abp.AspNetCore.Components.Server
);
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpBlazorRouterOptions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpRouterOptions.cs
similarity index 100%
rename from framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpBlazorRouterOptions.cs
rename to framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpRouterOptions.cs
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/ComponentsWebAssemblyBundleContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/ComponentsComponentsBundleContributor.cs
similarity index 100%
rename from framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/ComponentsWebAssemblyBundleContributor.cs
rename to framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/ComponentsComponentsBundleContributor.cs
diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributerBase.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributorBase.cs
similarity index 100%
rename from framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributerBase.cs
rename to framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributorBase.cs
diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyOptionsExtensions.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/AbpMultiTenancyOptionsExtensions.cs
similarity index 100%
rename from framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancyOptionsExtensions.cs
rename to framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/MultiTenancy/AbpMultiTenancyOptionsExtensions.cs
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Properties/launchSettings.json b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Properties/launchSettings.json
deleted file mode 100644
index b9542fa082..0000000000
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Properties/launchSettings.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:53603/",
- "sslPort": 44305
- }
- },
- "profiles": {
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "Volo.Abp.AspNetCore.Mvc.Client": {
- "commandName": "Project",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- },
- "applicationUrl": "https://localhost:5001;http://localhost:5000"
- }
- }
-}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj
index aae260d7e8..e9cac92c0e 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj
@@ -13,6 +13,7 @@
falsetrueLibrary
+ true
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ObjectExtensionConfigurationDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ModuleExtensionDto.cs
similarity index 100%
rename from framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ObjectExtensionConfigurationDto.cs
rename to framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ModuleExtensionDto.cs
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/CssRelativePathAdjuster.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/CssRelativePath.cs
similarity index 100%
rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/CssRelativePathAdjuster.cs
rename to framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/CssRelativePath.cs
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/ro-RO.json b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/ro-RO.json
new file mode 100644
index 0000000000..e431f56838
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/ro-RO.json
@@ -0,0 +1,13 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "GivenTenantIsNotExist": "Tenantul {0} nu există",
+ "GivenTenantIsNotAvailable": "Tenantul {0} nu este disponibil",
+ "Tenant": "Tenant",
+ "Switch": "schimbă",
+ "Name": "Nume",
+ "SwitchTenantHint": "Lăsaţi câmpul de nume gol pentru a schimba pe host.",
+ "SwitchTenant": "Schimbă tenant",
+ "NotSelected": "Neselectat"
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JQueryFormScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JsTreeScriptContributor.cs
similarity index 100%
rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JQueryFormScriptContributor.cs
rename to framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JsTreeScriptContributor.cs
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/Demos/DropdownsDemo/DropDownDemoModel.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/Demos/DropdownsDemo/DropDownDemoDemoModel.cs
similarity index 100%
rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/Demos/DropdownsDemo/DropDownDemoModel.cs
rename to framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/Demos/DropdownsDemo/DropDownDemoDemoModel.cs
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs
index 7aea3cf9f2..ff20cb1b52 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs
@@ -37,6 +37,13 @@ namespace Volo.Abp.ObjectExtending
public static string GetInputFormatOrNull(this IBasicObjectExtensionPropertyInfo property)
{
+ var formatString = property.GetDataFormatStringOrNull();
+
+ if (!formatString.IsNullOrWhiteSpace())
+ {
+ return formatString;
+ }
+
if (property.IsDate())
{
return "{0:yyyy-MM-dd}";
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpDataAnnotationAutoLocalizationMetadataDetailsProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpDataAnnotationAutoLocalizationMetadataDetailsProvider.cs
index d9de135e7f..be088b0154 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpDataAnnotationAutoLocalizationMetadataDetailsProvider.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpDataAnnotationAutoLocalizationMetadataDetailsProvider.cs
@@ -54,7 +54,29 @@ namespace Volo.Abp.AspNetCore.Mvc
displayMetadata.DisplayName = () =>
{
- var localizedString = localizer[PropertyLocalizationKeyPrefix + context.Key.Name];
+ /*
+ * DisplayName:ClassName:PropertyName
+ * DisplayName:PropertyName
+ * ClassName:PropertyName
+ * PropertyName
+ */
+
+ LocalizedString localizedString = null;
+
+ if (context.Key.ContainerType != null)
+ {
+ localizedString = localizer[PropertyLocalizationKeyPrefix + context.Key.ContainerType.Name + ":" + context.Key.Name];
+ }
+
+ if (localizedString == null || localizedString.ResourceNotFound)
+ {
+ localizedString = localizer[PropertyLocalizationKeyPrefix + context.Key.Name];
+ }
+
+ if (localizedString.ResourceNotFound && context.Key.ContainerType != null)
+ {
+ localizedString = localizer[context.Key.ContainerType.Name + ":" + context.Key.Name];
+ }
if (localizedString.ResourceNotFound)
{
@@ -65,4 +87,4 @@ namespace Volo.Abp.AspNetCore.Mvc
};
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/AbpRemoteStreamContentModelBinder.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/AbpRemoteStreamContentModelBinder.cs
index 30161b77b1..2b1fc8c125 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/AbpRemoteStreamContentModelBinder.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/AbpRemoteStreamContentModelBinder.cs
@@ -108,14 +108,14 @@ namespace Volo.Abp.AspNetCore.Mvc.ContentFormatters
if (file.Name.Equals(modelName, StringComparison.OrdinalIgnoreCase))
{
- postedFiles.Add(new RemoteStreamContent(file.OpenReadStream())
- {
- ContentType = file.ContentType,
- FileName = file.FileName
- });
+ postedFiles.Add(new RemoteStreamContent(file.OpenReadStream(), file.FileName, file.ContentType, file.Length));
}
}
}
+ else if (bindingContext.IsTopLevelObject)
+ {
+ postedFiles.Add(new RemoteStreamContent(request.Body, null, request.ContentType, request.ContentLength));
+ }
}
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs
index 35e0922f36..50d65ce02d 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs
@@ -33,14 +33,9 @@ namespace Volo.Abp.AspNetCore.Mvc.ContentFormatters
context.HttpContext.Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();
}
- using (var stream = remoteStream.GetStream())
+ using (remoteStream)
{
- if (stream.CanSeek)
- {
- stream.Position = 0;
- }
-
- await stream.CopyToAsync(context.HttpContext.Response.Body);
+ await remoteStream.GetStream().CopyToAsync(context.HttpContext.Response.Body);
}
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DependencyInjection/AbpAspNetCoreMvcConventionalDependencyRegistrar.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DependencyInjection/AbpAspNetCoreMvcConventionalRegistrar.cs
similarity index 100%
rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DependencyInjection/AbpAspNetCoreMvcConventionalDependencyRegistrar.cs
rename to framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DependencyInjection/AbpAspNetCoreMvcConventionalRegistrar.cs
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtendingPropertyInfoExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoAspNetCoreMvcExtensions.cs
similarity index 79%
rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtendingPropertyInfoExtensions.cs
rename to framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoAspNetCoreMvcExtensions.cs
index 7daea2cad0..a03ef831f5 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtendingPropertyInfoExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoAspNetCoreMvcExtensions.cs
@@ -33,5 +33,13 @@ namespace Volo.Abp.ObjectExtending
.OfType()
.FirstOrDefault()?.DataType;
}
+
+ public static string GetDataFormatStringOrNull(this IBasicObjectExtensionPropertyInfo property)
+ {
+ return property
+ .Attributes
+ .OfType()
+ .FirstOrDefault()?.DataFormatString;
+ }
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Serilog/Properties/launchSettings.json b/framework/src/Volo.Abp.AspNetCore.Serilog/Properties/launchSettings.json
deleted file mode 100644
index afff9bb30b..0000000000
--- a/framework/src/Volo.Abp.AspNetCore.Serilog/Properties/launchSettings.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:53606/",
- "sslPort": 44319
- }
- },
- "profiles": {
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "Volo.Abp.AspNetCore.Serilog": {
- "commandName": "Project",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- },
- "applicationUrl": "https://localhost:5001;http://localhost:5000"
- }
- }
-}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Serilog/Volo.Abp.AspNetCore.Serilog.csproj b/framework/src/Volo.Abp.AspNetCore.Serilog/Volo.Abp.AspNetCore.Serilog.csproj
index f42418a107..538b3660c5 100644
--- a/framework/src/Volo.Abp.AspNetCore.Serilog/Volo.Abp.AspNetCore.Serilog.csproj
+++ b/framework/src/Volo.Abp.AspNetCore.Serilog/Volo.Abp.AspNetCore.Serilog.csproj
@@ -13,6 +13,7 @@
falsetrueLibrary
+ true
diff --git a/framework/src/Volo.Abp.AspNetCore.SignalR/Properties/launchSettings.json b/framework/src/Volo.Abp.AspNetCore.SignalR/Properties/launchSettings.json
deleted file mode 100644
index f5e00240d4..0000000000
--- a/framework/src/Volo.Abp.AspNetCore.SignalR/Properties/launchSettings.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:53611/",
- "sslPort": 44331
- }
- },
- "profiles": {
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "Volo.Abp.AspNetCore.SignalR": {
- "commandName": "Project",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- },
- "applicationUrl": "https://localhost:5001;http://localhost:5000"
- }
- }
-}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.SignalR/Volo.Abp.AspNetCore.SignalR.csproj b/framework/src/Volo.Abp.AspNetCore.SignalR/Volo.Abp.AspNetCore.SignalR.csproj
index 9fc69b34cc..54610a20a3 100644
--- a/framework/src/Volo.Abp.AspNetCore.SignalR/Volo.Abp.AspNetCore.SignalR.csproj
+++ b/framework/src/Volo.Abp.AspNetCore.SignalR/Volo.Abp.AspNetCore.SignalR.csproj
@@ -13,6 +13,7 @@
falsetrueLibrary
+ true
diff --git a/framework/src/Volo.Abp.AspNetCore.TestBase/Properties/launchSettings.json b/framework/src/Volo.Abp.AspNetCore.TestBase/Properties/launchSettings.json
deleted file mode 100644
index fca23e6182..0000000000
--- a/framework/src/Volo.Abp.AspNetCore.TestBase/Properties/launchSettings.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:53599/",
- "sslPort": 44358
- }
- },
- "profiles": {
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "Volo.Abp.AspNetCore.TestBase": {
- "commandName": "Project",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- },
- "applicationUrl": "https://localhost:5001;http://localhost:5000"
- }
- }
-}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj
index a73f2c6245..137c78ca90 100644
--- a/framework/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj
+++ b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj
@@ -13,6 +13,7 @@
falsetrueLibrary
+ true
diff --git a/framework/src/Volo.Abp.AspNetCore/Properties/launchSettings.json b/framework/src/Volo.Abp.AspNetCore/Properties/launchSettings.json
deleted file mode 100644
index 78196102ba..0000000000
--- a/framework/src/Volo.Abp.AspNetCore/Properties/launchSettings.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:53596/",
- "sslPort": 44300
- }
- },
- "profiles": {
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "Volo.Abp.AspNetCore": {
- "commandName": "Project",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- },
- "applicationUrl": "https://localhost:5001;http://localhost:5000"
- }
- }
-}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj b/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj
index b191872339..e8f290f294 100644
--- a/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj
+++ b/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj
@@ -13,6 +13,7 @@
falsetrueLibrary
+ true
diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAspNetCoreUnitOfWorkOptions.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAspNetCoreAuditingOptions.cs
similarity index 100%
rename from framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAspNetCoreUnitOfWorkOptions.cs
rename to framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAspNetCoreAuditingOptions.cs
diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Threading/HttpContextCancellationTokenProvider.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Threading/HttpContextCancellationTokenProvider.cs
index c7c961176c..ce722b1176 100644
--- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Threading/HttpContextCancellationTokenProvider.cs
+++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Threading/HttpContextCancellationTokenProvider.cs
@@ -6,13 +6,26 @@ using Volo.Abp.Threading;
namespace Volo.Abp.AspNetCore.Threading
{
[Dependency(ReplaceServices = true)]
- public class HttpContextCancellationTokenProvider : ICancellationTokenProvider, ITransientDependency
+ public class HttpContextCancellationTokenProvider : CancellationTokenProviderBase, ITransientDependency
{
- public CancellationToken Token => _httpContextAccessor.HttpContext?.RequestAborted ?? CancellationToken.None;
-
private readonly IHttpContextAccessor _httpContextAccessor;
- public HttpContextCancellationTokenProvider(IHttpContextAccessor httpContextAccessor)
+ public override CancellationToken Token
+ {
+ get
+ {
+ if (OverrideValue != null)
+ {
+ return OverrideValue.CancellationToken;
+ }
+ return _httpContextAccessor.HttpContext?.RequestAborted ?? CancellationToken.None;
+ }
+ }
+
+ public HttpContextCancellationTokenProvider(
+ IAmbientScopeProvider cancellationTokenOverrideScopeProvider,
+ IHttpContextAccessor httpContextAccessor)
+ : base(cancellationTokenOverrideScopeProvider)
{
_httpContextAccessor = httpContextAccessor;
}
diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Localization/ro-RO.json b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Localization/ro-RO.json
new file mode 100644
index 0000000000..e330581c69
--- /dev/null
+++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Localization/ro-RO.json
@@ -0,0 +1,10 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "Volo.Authorization:010001": "Autorizare eşuată! Politica dată nu a fost acordată.",
+ "Volo.Authorization:010002": "Autorizare eşuată! Politica dată nu a acordat: {PolicyName}",
+ "Volo.Authorization:010003": "Autorizare eşuată! Politica dată nu a fost acordată pentru resursa dată: {ResourceName}",
+ "Volo.Authorization:010004": "Autorizare eşuată! Cerinţa dată nu a fost acordată pentru resursa dată: {ResourceName}",
+ "Volo.Authorization:010005": "Autorizare eşuată! Cerinţele date nu au fost acordate pentru resursa dată: {ResourceName}"
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerAdapter.cs b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs
similarity index 98%
rename from framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerAdapter.cs
rename to framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs
index a37807e473..aa99434ed5 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerAdapter.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs
@@ -6,6 +6,7 @@ using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundWorkers.Quartz
{
+ [DisallowConcurrentExecution]
public class QuartzPeriodicBackgroundWorkerAdapter : QuartzBackgroundWorkerBase,
IQuartzBackgroundWorkerAdapter
where TWorker : IBackgroundWorker
diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerContext.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerContext.cs
similarity index 100%
rename from framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerContext.cs
rename to framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerContext.cs
diff --git a/framework/src/Volo.Abp.BlazoriseUI/AbpBlazoriseModule.cs b/framework/src/Volo.Abp.BlazoriseUI/AbpBlazoriseUIModule.cs
similarity index 100%
rename from framework/src/Volo.Abp.BlazoriseUI/AbpBlazoriseModule.cs
rename to framework/src/Volo.Abp.BlazoriseUI/AbpBlazoriseUIModule.cs
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliUrls.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliUrls.cs
index 1ecc5b1631..8d2b10d3ca 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliUrls.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliUrls.cs
@@ -10,9 +10,9 @@
public const string NuGetRootPath = NuGetRootPathDevelopment;
#else
public const string WwwAbpIo = WwwAbpIoProduction;
-
+
public const string AccountAbpIo = AccountAbpIoProduction;
-
+
public const string NuGetRootPath = NuGetRootPathProduction;
#endif
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand..cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand.cs
similarity index 100%
rename from framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand..cs
rename to framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand.cs
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs
index c8757e1252..c8bc508983 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs
@@ -26,24 +26,20 @@ using Volo.Abp.Threading;
namespace Volo.Abp.Cli.Commands
{
- public class NewCommand : IConsoleCommand, ITransientDependency
+ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransientDependency
{
- private readonly EfCoreMigrationManager _efCoreMigrationManager;
public ILogger Logger { get; set; }
protected TemplateProjectBuilder TemplateProjectBuilder { get; }
public ITemplateInfoProvider TemplateInfoProvider { get; }
- public ConnectionStringProvider ConnectionStringProvider { get; }
public NewCommand(TemplateProjectBuilder templateProjectBuilder
, ITemplateInfoProvider templateInfoProvider,
- EfCoreMigrationManager efCoreMigrationManager,
ConnectionStringProvider connectionStringProvider)
+ : base(connectionStringProvider)
{
- _efCoreMigrationManager = efCoreMigrationManager;
TemplateProjectBuilder = templateProjectBuilder;
TemplateInfoProvider = templateInfoProvider;
- ConnectionStringProvider = connectionStringProvider;
Logger = NullLogger.Instance;
}
@@ -79,257 +75,23 @@ namespace Volo.Abp.Cli.Commands
template = (await TemplateInfoProvider.GetDefaultAsync()).Name;
}
- var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long);
- if (version != null)
- {
- Logger.LogInformation("Version: " + version);
- }
-
var isTiered = commandLineArgs.Options.ContainsKey(Options.Tiered.Long);
if (isTiered)
{
Logger.LogInformation("Tiered: yes");
}
- var preview = commandLineArgs.Options.ContainsKey(Options.Preview.Long);
- if (preview)
- {
- Logger.LogInformation("Preview: yes");
- }
-
- var databaseProvider = GetDatabaseProvider(commandLineArgs);
- if (databaseProvider != DatabaseProvider.NotSpecified)
- {
- Logger.LogInformation("Database provider: " + databaseProvider);
- }
-
- var connectionString = GetConnectionString(commandLineArgs);
- if (connectionString != null)
- {
- Logger.LogInformation("Connection string: " + connectionString);
- }
-
- var databaseManagementSystem = GetDatabaseManagementSystem(commandLineArgs);
- if (databaseManagementSystem != DatabaseManagementSystem.NotSpecified)
- {
- Logger.LogInformation("DBMS: " + databaseManagementSystem);
- }
-
- var uiFramework = GetUiFramework(commandLineArgs);
- if (uiFramework != UiFramework.NotSpecified)
- {
- Logger.LogInformation("UI Framework: " + uiFramework);
- }
-
- var publicWebSite = uiFramework != UiFramework.None && commandLineArgs.Options.ContainsKey(Options.PublicWebSite.Long);
- if (publicWebSite)
- {
- Logger.LogInformation("Public Web Site: yes");
- }
-
- var mobileApp = GetMobilePreference(commandLineArgs);
- if (mobileApp != MobileApp.None)
- {
- Logger.LogInformation("Mobile App: " + mobileApp);
- }
-
- var gitHubAbpLocalRepositoryPath = commandLineArgs.Options.GetOrNull(Options.GitHubAbpLocalRepositoryPath.Long);
- if (gitHubAbpLocalRepositoryPath != null)
- {
- Logger.LogInformation("GitHub Abp Local Repository Path: " + gitHubAbpLocalRepositoryPath);
- }
-
- var gitHubVoloLocalRepositoryPath = commandLineArgs.Options.GetOrNull(Options.GitHubVoloLocalRepositoryPath.Long);
- if (gitHubVoloLocalRepositoryPath != null)
- {
- Logger.LogInformation("GitHub Volo Local Repository Path: " + gitHubVoloLocalRepositoryPath);
- }
-
- var templateSource = commandLineArgs.Options.GetOrNull(Options.TemplateSource.Short, Options.TemplateSource.Long);
- if (templateSource != null)
- {
- Logger.LogInformation("Template Source: " + templateSource);
- }
-
- var createSolutionFolder = GetCreateSolutionFolderPreference(commandLineArgs);
-
- var outputFolder = commandLineArgs.Options.GetOrNull(Options.OutputFolder.Short, Options.OutputFolder.Long);
-
- var outputFolderRoot =
- outputFolder != null ? Path.GetFullPath(outputFolder) : Directory.GetCurrentDirectory();
-
- SolutionName solutionName;
- if (MicroserviceServiceTemplateBase.IsMicroserviceServiceTemplate(template))
- {
- var microserviceSolutionName = FindMicroserviceSolutionName(outputFolderRoot);
-
- if (microserviceSolutionName == null)
- {
- throw new CliUsageException("This command should be run inside a folder that contains a microservice solution!");
- }
-
- solutionName = SolutionName.Parse(microserviceSolutionName, projectName);
- outputFolder = MicroserviceServiceTemplateBase.CalculateTargetFolder(outputFolderRoot, projectName);
- uiFramework = uiFramework == UiFramework.NotSpecified ? FindMicroserviceSolutionUiFramework(outputFolderRoot) : uiFramework;
- }
- else
- {
- solutionName = SolutionName.Parse(projectName);
-
- outputFolder = createSolutionFolder ?
- Path.Combine(outputFolderRoot, SolutionName.Parse(projectName).FullName) :
- outputFolderRoot;
- }
-
- Volo.Abp.IO.DirectoryHelper.CreateIfNotExists(outputFolder);
-
- Logger.LogInformation("Output folder: " + outputFolder);
-
- if (connectionString == null &&
- databaseManagementSystem != DatabaseManagementSystem.NotSpecified &&
- databaseManagementSystem != DatabaseManagementSystem.SQLServer)
- {
- connectionString = ConnectionStringProvider.GetByDbms(databaseManagementSystem, outputFolder);
- }
-
- commandLineArgs.Options.Add(CliConsts.Command, commandLineArgs.Command);
+ var projectArgs = GetProjectBuildArgs(commandLineArgs, template, projectName);
var result = await TemplateProjectBuilder.BuildAsync(
- new ProjectBuildArgs(
- solutionName,
- template,
- version,
- databaseProvider,
- databaseManagementSystem,
- uiFramework,
- mobileApp,
- publicWebSite,
- gitHubAbpLocalRepositoryPath,
- gitHubVoloLocalRepositoryPath,
- templateSource,
- commandLineArgs.Options,
- connectionString
- )
+ projectArgs
);
- using (var templateFileStream = new MemoryStream(result.ZipContent))
- {
- using (var zipInputStream = new ZipInputStream(templateFileStream))
- {
- var zipEntry = zipInputStream.GetNextEntry();
- while (zipEntry != null)
- {
- if (string.IsNullOrWhiteSpace(zipEntry.Name))
- {
- zipEntry = zipInputStream.GetNextEntry();
- continue;
- }
-
- var fullZipToPath = Path.Combine(outputFolder, zipEntry.Name);
- var directoryName = Path.GetDirectoryName(fullZipToPath);
-
- if (!string.IsNullOrEmpty(directoryName))
- {
- Directory.CreateDirectory(directoryName);
- }
-
- var fileName = Path.GetFileName(fullZipToPath);
- if (fileName.Length == 0)
- {
- zipEntry = zipInputStream.GetNextEntry();
- continue;
- }
-
- var buffer = new byte[4096]; // 4K is optimum
- using (var streamWriter = File.Create(fullZipToPath))
- {
- StreamUtils.Copy(zipInputStream, streamWriter, buffer);
- }
-
- zipEntry = zipInputStream.GetNextEntry();
- }
- }
- }
-
- Logger.LogInformation($"'{projectName}' has been successfully created to '{outputFolder}'");
-
-
- if (AppTemplateBase.IsAppTemplate(template))
- {
- var isCommercial = template == AppProTemplate.TemplateName;
- OpenThanksPage(uiFramework, databaseProvider, isTiered || commandLineArgs.Options.ContainsKey("separate-identity-server"), isCommercial);
- }
- else if (MicroserviceTemplateBase.IsMicroserviceTemplate(template))
- {
- OpenMicroserviceDocumentPage();
- }
- }
-
- private string FindMicroserviceSolutionName(string outputFolderRoot)
- {
- var slnFile = Directory.GetFiles(outputFolderRoot, "*.sln").FirstOrDefault();
-
- if (slnFile == null)
- {
- return null;
- }
-
- return Path.GetFileName(slnFile).RemovePostFix(".sln");
- }
-
- private UiFramework FindMicroserviceSolutionUiFramework(string outputFolderRoot)
- {
- if (Directory.Exists(Path.Combine(outputFolderRoot, "apps", "blazor")))
- {
- return UiFramework.Blazor;
- }
- if (Directory.Exists(Path.Combine(outputFolderRoot, "apps", "web")))
- {
- return UiFramework.Mvc;
- }
- if (Directory.Exists(Path.Combine(outputFolderRoot, "apps", "angular")))
- {
- return UiFramework.Angular;
- }
-
- return UiFramework.None;
- }
-
- private void OpenThanksPage(UiFramework uiFramework, DatabaseProvider databaseProvider, bool tiered, bool commercial)
- {
- uiFramework = uiFramework == UiFramework.NotSpecified || uiFramework == UiFramework.None ? UiFramework.Mvc : uiFramework;
- databaseProvider = databaseProvider == DatabaseProvider.NotSpecified ? DatabaseProvider.EntityFrameworkCore : databaseProvider;
-
- var urlPrefix = commercial ? "commercial" : "www";
- var tieredYesNo = tiered ? "yes" : "no";
- var url = $"https://{urlPrefix}.abp.io/project-created-success?ui={uiFramework:g}&db={databaseProvider:g}&tiered={tieredYesNo}";
-
- CmdHelper.OpenWebPage(url);
- }
-
- private void OpenMicroserviceDocumentPage()
- {
- var url = "https://docs.abp.io/en/commercial/latest/startup-templates/microservice/index";
+ ExtractProjectZip(result, projectArgs.OutputFolder);
- CmdHelper.OpenWebPage(url);
- }
-
- private bool GetCreateSolutionFolderPreference(CommandLineArgs commandLineArgs)
- {
- var longKey = commandLineArgs.Options.ContainsKey(Options.CreateSolutionFolder.Long);
-
- if (longKey == false)
- {
- return commandLineArgs.Options.ContainsKey(Options.CreateSolutionFolder.Short);
- }
-
- return longKey;
- }
+ Logger.LogInformation($"'{projectName}' has been successfully created to '{projectArgs.OutputFolder}'");
- private static string GetConnectionString(CommandLineArgs commandLineArgs)
- {
- var connectionString = commandLineArgs.Options.GetOrNull(Options.ConnectionString.Short, Options.ConnectionString.Long);
- return string.IsNullOrWhiteSpace(connectionString) ? null : connectionString;
+ OpenRelatedWebPage(projectArgs, template, isTiered, commandLineArgs);
}
public string GetUsageInfo()
@@ -389,174 +151,5 @@ namespace Volo.Abp.Cli.Commands
return "Generate a new solution based on the ABP startup templates.";
}
- protected virtual DatabaseProvider GetDatabaseProvider(CommandLineArgs commandLineArgs)
- {
- var optionValue = commandLineArgs.Options.GetOrNull(Options.DatabaseProvider.Short, Options.DatabaseProvider.Long);
- switch (optionValue)
- {
- case "ef":
- return DatabaseProvider.EntityFrameworkCore;
- case "mongodb":
- return DatabaseProvider.MongoDb;
- default:
- return DatabaseProvider.NotSpecified;
- }
- }
-
- protected virtual DatabaseManagementSystem GetDatabaseManagementSystem(CommandLineArgs commandLineArgs)
- {
- var optionValue = commandLineArgs.Options.GetOrNull(Options.DatabaseManagementSystem.Short, Options.DatabaseManagementSystem.Long);
-
- if (optionValue == null)
- {
- return DatabaseManagementSystem.NotSpecified;
- }
-
- switch (optionValue.ToLowerInvariant())
- {
- case "sqlserver":
- return DatabaseManagementSystem.SQLServer;
- case "mysql":
- return DatabaseManagementSystem.MySQL;
- case "postgresql":
- return DatabaseManagementSystem.PostgreSQL;
- case "oracle-devart":
- return DatabaseManagementSystem.OracleDevart;
- case "sqlite":
- return DatabaseManagementSystem.SQLite;
- case "oracle":
- return DatabaseManagementSystem.Oracle;
- default:
- return DatabaseManagementSystem.NotSpecified;
- }
- }
-
- protected virtual UiFramework GetUiFramework(CommandLineArgs commandLineArgs)
- {
- if (commandLineArgs.Options.ContainsKey("no-ui"))
- {
- return UiFramework.None;
- }
-
- var optionValue = commandLineArgs.Options.GetOrNull(Options.UiFramework.Short, Options.UiFramework.Long);
- switch (optionValue)
- {
- case "none":
- return UiFramework.None;
- case "mvc":
- return UiFramework.Mvc;
- case "angular":
- return UiFramework.Angular;
- case "blazor":
- return UiFramework.Blazor;
- case "blazor-server":
- return UiFramework.BlazorServer;
- default:
- return UiFramework.NotSpecified;
- }
- }
-
- protected virtual MobileApp GetMobilePreference(CommandLineArgs commandLineArgs)
- {
- var optionValue = commandLineArgs.Options.GetOrNull(Options.Mobile.Short, Options.Mobile.Long);
-
- switch (optionValue)
- {
- case "none":
- return MobileApp.None;
- case "react-native":
- return MobileApp.ReactNative;
- default:
- return MobileApp.None;
- }
- }
-
- public static class Options
- {
- public static class Template
- {
- public const string Short = "t";
- public const string Long = "template";
- }
-
- public static class DatabaseProvider
- {
- public const string Short = "d";
- public const string Long = "database-provider";
- }
-
- public static class DatabaseManagementSystem
- {
- public const string Short = "dbms";
- public const string Long = "database-management-system";
- }
-
- public static class OutputFolder
- {
- public const string Short = "o";
- public const string Long = "output-folder";
- }
-
- public static class GitHubAbpLocalRepositoryPath
- {
- public const string Long = "abp-path";
- }
-
- public static class GitHubVoloLocalRepositoryPath
- {
- public const string Long = "volo-path";
- }
-
- public static class Version
- {
- public const string Short = "v";
- public const string Long = "version";
- }
-
- public static class UiFramework
- {
- public const string Short = "u";
- public const string Long = "ui";
- }
-
- public static class Mobile
- {
- public const string Short = "m";
- public const string Long = "mobile";
- }
-
- public static class PublicWebSite
- {
- public const string Long = "with-public-website";
- }
-
- public static class TemplateSource
- {
- public const string Short = "ts";
- public const string Long = "template-source";
- }
-
- public static class ConnectionString
- {
- public const string Short = "cs";
- public const string Long = "connection-string";
- }
-
- public static class CreateSolutionFolder
- {
- public const string Short = "csf";
- public const string Long = "create-solution-folder";
- }
-
- public static class Tiered
- {
- public const string Long = "tiered";
- }
-
- public static class Preview
- {
- public const string Long = "preview";
- }
- }
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs
new file mode 100644
index 0000000000..927019f566
--- /dev/null
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs
@@ -0,0 +1,449 @@
+using System;
+using System.IO;
+using System.Linq;
+using ICSharpCode.SharpZipLib.Core;
+using ICSharpCode.SharpZipLib.Zip;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Volo.Abp.Cli.Args;
+using Volo.Abp.Cli.Commands.Services;
+using Volo.Abp.Cli.ProjectBuilding;
+using Volo.Abp.Cli.ProjectBuilding.Building;
+using Volo.Abp.Cli.ProjectBuilding.Templates.App;
+using Volo.Abp.Cli.ProjectBuilding.Templates.Microservice;
+using Volo.Abp.Cli.Utils;
+
+namespace Volo.Abp.Cli.Commands
+{
+ public abstract class ProjectCreationCommandBase
+ {
+ public ConnectionStringProvider ConnectionStringProvider { get; }
+ public ILogger Logger { get; set; }
+
+ public ProjectCreationCommandBase(ConnectionStringProvider connectionStringProvider)
+ {
+ ConnectionStringProvider = connectionStringProvider;
+
+ Logger = NullLogger.Instance;
+ }
+
+ protected ProjectBuildArgs GetProjectBuildArgs(CommandLineArgs commandLineArgs, string template, string projectName)
+ {
+ var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long);
+
+ if (version != null)
+ {
+ Logger.LogInformation("Version: " + version);
+ }
+
+ var preview = commandLineArgs.Options.ContainsKey(Options.Preview.Long);
+ if (preview)
+ {
+ Logger.LogInformation("Preview: yes");
+ }
+
+ var databaseProvider = GetDatabaseProvider(commandLineArgs);
+ if (databaseProvider != DatabaseProvider.NotSpecified)
+ {
+ Logger.LogInformation("Database provider: " + databaseProvider);
+ }
+
+ var connectionString = GetConnectionString(commandLineArgs);
+ if (connectionString != null)
+ {
+ Logger.LogInformation("Connection string: " + connectionString);
+ }
+
+ var databaseManagementSystem = GetDatabaseManagementSystem(commandLineArgs);
+ if (databaseManagementSystem != DatabaseManagementSystem.NotSpecified)
+ {
+ Logger.LogInformation("DBMS: " + databaseManagementSystem);
+ }
+
+ var uiFramework = GetUiFramework(commandLineArgs);
+ if (uiFramework != UiFramework.NotSpecified)
+ {
+ Logger.LogInformation("UI Framework: " + uiFramework);
+ }
+
+ var publicWebSite = uiFramework != UiFramework.None && commandLineArgs.Options.ContainsKey(Options.PublicWebSite.Long);
+ if (publicWebSite)
+ {
+ Logger.LogInformation("Public Web Site: yes");
+ }
+
+ var mobileApp = GetMobilePreference(commandLineArgs);
+ if (mobileApp != MobileApp.None)
+ {
+ Logger.LogInformation("Mobile App: " + mobileApp);
+ }
+
+ var gitHubAbpLocalRepositoryPath = commandLineArgs.Options.GetOrNull(Options.GitHubAbpLocalRepositoryPath.Long);
+ if (gitHubAbpLocalRepositoryPath != null)
+ {
+ Logger.LogInformation("GitHub Abp Local Repository Path: " + gitHubAbpLocalRepositoryPath);
+ }
+
+ var gitHubVoloLocalRepositoryPath = commandLineArgs.Options.GetOrNull(Options.GitHubVoloLocalRepositoryPath.Long);
+ if (gitHubVoloLocalRepositoryPath != null)
+ {
+ Logger.LogInformation("GitHub Volo Local Repository Path: " + gitHubVoloLocalRepositoryPath);
+ }
+
+ var templateSource = commandLineArgs.Options.GetOrNull(Options.TemplateSource.Short, Options.TemplateSource.Long);
+ if (templateSource != null)
+ {
+ Logger.LogInformation("Template Source: " + templateSource);
+ }
+
+ var createSolutionFolder = GetCreateSolutionFolderPreference(commandLineArgs);
+
+ var outputFolder = commandLineArgs.Options.GetOrNull(Options.OutputFolder.Short, Options.OutputFolder.Long);
+
+ var outputFolderRoot =
+ outputFolder != null ? Path.GetFullPath(outputFolder) : Directory.GetCurrentDirectory();
+
+ SolutionName solutionName;
+ if (MicroserviceServiceTemplateBase.IsMicroserviceServiceTemplate(template))
+ {
+ var microserviceSolutionName = FindMicroserviceSolutionName(outputFolderRoot);
+
+ if (microserviceSolutionName == null)
+ {
+ throw new CliUsageException("This command should be run inside a folder that contains a microservice solution!");
+ }
+
+ solutionName = SolutionName.Parse(microserviceSolutionName, projectName);
+ outputFolder = MicroserviceServiceTemplateBase.CalculateTargetFolder(outputFolderRoot, projectName);
+ uiFramework = uiFramework == UiFramework.NotSpecified ? FindMicroserviceSolutionUiFramework(outputFolderRoot) : uiFramework;
+ }
+ else
+ {
+ solutionName = SolutionName.Parse(projectName);
+
+ outputFolder = createSolutionFolder ?
+ Path.Combine(outputFolderRoot, SolutionName.Parse(projectName).FullName) :
+ outputFolderRoot;
+ }
+
+ IO.DirectoryHelper.CreateIfNotExists(outputFolder);
+
+ Logger.LogInformation("Output folder: " + outputFolder);
+
+ if (connectionString == null &&
+ databaseManagementSystem != DatabaseManagementSystem.NotSpecified &&
+ databaseManagementSystem != DatabaseManagementSystem.SQLServer)
+ {
+ connectionString = ConnectionStringProvider.GetByDbms(databaseManagementSystem, outputFolder);
+ }
+
+ commandLineArgs.Options.Add(CliConsts.Command, commandLineArgs.Command);
+
+ return new ProjectBuildArgs(
+ solutionName,
+ template,
+ version,
+ outputFolder,
+ databaseProvider,
+ databaseManagementSystem,
+ uiFramework,
+ mobileApp,
+ publicWebSite,
+ gitHubAbpLocalRepositoryPath,
+ gitHubVoloLocalRepositoryPath,
+ templateSource,
+ commandLineArgs.Options,
+ connectionString
+ );
+ }
+
+ protected void ExtractProjectZip(ProjectBuildResult project, string outputFolder)
+ {
+ using (var templateFileStream = new MemoryStream(project.ZipContent))
+ {
+ using (var zipInputStream = new ZipInputStream(templateFileStream))
+ {
+ var zipEntry = zipInputStream.GetNextEntry();
+ while (zipEntry != null)
+ {
+ if (string.IsNullOrWhiteSpace(zipEntry.Name))
+ {
+ zipEntry = zipInputStream.GetNextEntry();
+ continue;
+ }
+
+ var fullZipToPath = Path.Combine(outputFolder, zipEntry.Name);
+ var directoryName = Path.GetDirectoryName(fullZipToPath);
+
+ if (!string.IsNullOrEmpty(directoryName))
+ {
+ Directory.CreateDirectory(directoryName);
+ }
+
+ var fileName = Path.GetFileName(fullZipToPath);
+ if (fileName.Length == 0)
+ {
+ zipEntry = zipInputStream.GetNextEntry();
+ continue;
+ }
+
+ var buffer = new byte[4096]; // 4K is optimum
+ using (var streamWriter = File.Create(fullZipToPath))
+ {
+ StreamUtils.Copy(zipInputStream, streamWriter, buffer);
+ }
+
+ zipEntry = zipInputStream.GetNextEntry();
+ }
+ }
+ }
+ }
+
+ protected void OpenRelatedWebPage(ProjectBuildArgs projectArgs,
+ string template,
+ bool isTiered,
+ CommandLineArgs commandLineArgs)
+ {
+ if (AppTemplateBase.IsAppTemplate(template))
+ {
+ var isCommercial = template == AppProTemplate.TemplateName;
+ OpenThanksPage(projectArgs.UiFramework, projectArgs.DatabaseProvider, isTiered || commandLineArgs.Options.ContainsKey("separate-identity-server"), isCommercial);
+ }
+ else if (MicroserviceTemplateBase.IsMicroserviceTemplate(template))
+ {
+ OpenMicroserviceDocumentPage();
+ }
+ }
+
+ protected string FindMicroserviceSolutionName(string outputFolderRoot)
+ {
+ var slnFile = Directory.GetFiles(outputFolderRoot, "*.sln").FirstOrDefault();
+
+ if (slnFile == null)
+ {
+ return null;
+ }
+
+ return Path.GetFileName(slnFile).RemovePostFix(".sln");
+ }
+
+ protected UiFramework FindMicroserviceSolutionUiFramework(string outputFolderRoot)
+ {
+ if (Directory.Exists(Path.Combine(outputFolderRoot, "apps", "blazor")))
+ {
+ return UiFramework.Blazor;
+ }
+ if (Directory.Exists(Path.Combine(outputFolderRoot, "apps", "web")))
+ {
+ return UiFramework.Mvc;
+ }
+ if (Directory.Exists(Path.Combine(outputFolderRoot, "apps", "angular")))
+ {
+ return UiFramework.Angular;
+ }
+
+ return UiFramework.None;
+ }
+
+ protected void OpenThanksPage(UiFramework uiFramework, DatabaseProvider databaseProvider, bool tiered, bool commercial)
+ {
+ uiFramework = uiFramework == UiFramework.NotSpecified || uiFramework == UiFramework.None ? UiFramework.Mvc : uiFramework;
+ databaseProvider = databaseProvider == DatabaseProvider.NotSpecified ? DatabaseProvider.EntityFrameworkCore : databaseProvider;
+
+ var urlPrefix = commercial ? "commercial" : "www";
+ var tieredYesNo = tiered ? "yes" : "no";
+ var url = $"https://{urlPrefix}.abp.io/project-created-success?ui={uiFramework:g}&db={databaseProvider:g}&tiered={tieredYesNo}";
+
+ CmdHelper.OpenWebPage(url);
+ }
+
+ protected void OpenMicroserviceDocumentPage()
+ {
+ var url = "https://docs.abp.io/en/commercial/latest/startup-templates/microservice/index";
+
+ CmdHelper.OpenWebPage(url);
+ }
+
+ protected bool GetCreateSolutionFolderPreference(CommandLineArgs commandLineArgs)
+ {
+ return commandLineArgs.Options.ContainsKey(Options.CreateSolutionFolder.Long)
+ || commandLineArgs.Options.ContainsKey(Options.CreateSolutionFolder.Short);
+ }
+
+ protected static string GetConnectionString(CommandLineArgs commandLineArgs)
+ {
+ var connectionString = commandLineArgs.Options.GetOrNull(Options.ConnectionString.Short, Options.ConnectionString.Long);
+ return string.IsNullOrWhiteSpace(connectionString) ? null : connectionString;
+ }
+
+ protected virtual DatabaseProvider GetDatabaseProvider(CommandLineArgs commandLineArgs)
+ {
+ var optionValue = commandLineArgs.Options.GetOrNull(Options.DatabaseProvider.Short, Options.DatabaseProvider.Long);
+ switch (optionValue)
+ {
+ case "ef":
+ return DatabaseProvider.EntityFrameworkCore;
+ case "mongodb":
+ return DatabaseProvider.MongoDb;
+ default:
+ return DatabaseProvider.NotSpecified;
+ }
+ }
+
+ protected virtual DatabaseManagementSystem GetDatabaseManagementSystem(CommandLineArgs commandLineArgs)
+ {
+ var optionValue = commandLineArgs.Options.GetOrNull(Options.DatabaseManagementSystem.Short, Options.DatabaseManagementSystem.Long);
+
+ if (optionValue == null)
+ {
+ return DatabaseManagementSystem.NotSpecified;
+ }
+
+ switch (optionValue.ToLowerInvariant())
+ {
+ case "sqlserver":
+ return DatabaseManagementSystem.SQLServer;
+ case "mysql":
+ return DatabaseManagementSystem.MySQL;
+ case "postgresql":
+ return DatabaseManagementSystem.PostgreSQL;
+ case "oracle-devart":
+ return DatabaseManagementSystem.OracleDevart;
+ case "sqlite":
+ return DatabaseManagementSystem.SQLite;
+ case "oracle":
+ return DatabaseManagementSystem.Oracle;
+ default:
+ return DatabaseManagementSystem.NotSpecified;
+ }
+ }
+
+ protected virtual MobileApp GetMobilePreference(CommandLineArgs commandLineArgs)
+ {
+ var optionValue = commandLineArgs.Options.GetOrNull(Options.Mobile.Short, Options.Mobile.Long);
+
+ switch (optionValue)
+ {
+ case "none":
+ return MobileApp.None;
+ case "react-native":
+ return MobileApp.ReactNative;
+ default:
+ return MobileApp.None;
+ }
+ }
+
+ protected virtual UiFramework GetUiFramework(CommandLineArgs commandLineArgs)
+ {
+ if (commandLineArgs.Options.ContainsKey("no-ui"))
+ {
+ return UiFramework.None;
+ }
+
+ var optionValue = commandLineArgs.Options.GetOrNull(Options.UiFramework.Short, Options.UiFramework.Long);
+ switch (optionValue)
+ {
+ case "none":
+ return UiFramework.None;
+ case "mvc":
+ return UiFramework.Mvc;
+ case "angular":
+ return UiFramework.Angular;
+ case "blazor":
+ return UiFramework.Blazor;
+ case "blazor-server":
+ return UiFramework.BlazorServer;
+ default:
+ return UiFramework.NotSpecified;
+ }
+ }
+
+ public static class Options
+ {
+ public static class Template
+ {
+ public const string Short = "t";
+ public const string Long = "template";
+ }
+
+ public static class DatabaseProvider
+ {
+ public const string Short = "d";
+ public const string Long = "database-provider";
+ }
+
+ public static class DatabaseManagementSystem
+ {
+ public const string Short = "dbms";
+ public const string Long = "database-management-system";
+ }
+
+ public static class OutputFolder
+ {
+ public const string Short = "o";
+ public const string Long = "output-folder";
+ }
+
+ public static class GitHubAbpLocalRepositoryPath
+ {
+ public const string Long = "abp-path";
+ }
+
+ public static class GitHubVoloLocalRepositoryPath
+ {
+ public const string Long = "volo-path";
+ }
+
+ public static class Version
+ {
+ public const string Short = "v";
+ public const string Long = "version";
+ }
+
+ public static class UiFramework
+ {
+ public const string Short = "u";
+ public const string Long = "ui";
+ }
+
+ public static class Mobile
+ {
+ public const string Short = "m";
+ public const string Long = "mobile";
+ }
+
+ public static class PublicWebSite
+ {
+ public const string Long = "with-public-website";
+ }
+
+ public static class TemplateSource
+ {
+ public const string Short = "ts";
+ public const string Long = "template-source";
+ }
+
+ public static class ConnectionString
+ {
+ public const string Short = "cs";
+ public const string Long = "connection-string";
+ }
+
+ public static class CreateSolutionFolder
+ {
+ public const string Short = "csf";
+ public const string Long = "create-solution-folder";
+ }
+
+ public static class Tiered
+ {
+ public const string Long = "tiered";
+ }
+
+ public static class Preview
+ {
+ public const string Long = "preview";
+ }
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs
index 56e5c0a03b..a228068b45 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs
@@ -42,6 +42,7 @@ namespace Volo.Abp.Cli.Commands.Services
SolutionName.Parse(moduleName),
moduleName,
version,
+ outputFolder,
DatabaseProvider.NotSpecified,
DatabaseManagementSystem.NotSpecified,
UiFramework.NotSpecified,
@@ -106,7 +107,8 @@ namespace Volo.Abp.Cli.Commands.Services
new ProjectBuildArgs(
SolutionName.Parse(packageName),
packageName,
- version
+ version,
+ outputFolder
)
);
@@ -156,7 +158,8 @@ namespace Volo.Abp.Cli.Commands.Services
new ProjectBuildArgs(
SolutionName.Parse(packageName),
packageName,
- version
+ version,
+ outputFolder
)
);
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuildArgs.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuildArgs.cs
index 71ccf96f7a..01b21bf858 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuildArgs.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuildArgs.cs
@@ -37,6 +37,9 @@ namespace Volo.Abp.Cli.ProjectBuilding
[CanBeNull]
public string ConnectionString { get; set; }
+ [NotNull]
+ public string OutputFolder { get; set; }
+
[NotNull]
public Dictionary ExtraProperties { get; set; }
@@ -44,6 +47,7 @@ namespace Volo.Abp.Cli.ProjectBuilding
[NotNull] SolutionName solutionName,
[CanBeNull] string templateName = null,
[CanBeNull] string version = null,
+ string outputFolder = null,
DatabaseProvider databaseProvider = DatabaseProvider.NotSpecified,
DatabaseManagementSystem databaseManagementSystem = DatabaseManagementSystem.NotSpecified,
UiFramework uiFramework = UiFramework.NotSpecified,
@@ -58,6 +62,7 @@ namespace Volo.Abp.Cli.ProjectBuilding
SolutionName = Check.NotNull(solutionName, nameof(solutionName));
TemplateName = templateName;
Version = version;
+ OutputFolder = outputFolder;
DatabaseProvider = databaseProvider;
DatabaseManagementSystem = databaseManagementSystem;
UiFramework = uiFramework;
diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/Hosting/AbpHostingHostBuilderExtensions.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/Hosting/AbpHostingHostBuilderExtensions.cs
new file mode 100644
index 0000000000..e2f55142e7
--- /dev/null
+++ b/framework/src/Volo.Abp.Core/Microsoft/Extensions/Hosting/AbpHostingHostBuilderExtensions.cs
@@ -0,0 +1,25 @@
+using Microsoft.Extensions.Configuration;
+
+namespace Microsoft.Extensions.Hosting
+{
+ public static class AbpHostingHostBuilderExtensions
+ {
+ public const string AppSettingsSecretJsonPath = "appsettings.secrets.json";
+
+ public static IHostBuilder AddAppSettingsSecretsJson(
+ this IHostBuilder hostBuilder,
+ bool optional = true,
+ bool reloadOnChange = true,
+ string path = AppSettingsSecretJsonPath)
+ {
+ return hostBuilder.ConfigureAppConfiguration((_, builder) =>
+ {
+ builder.AddJsonFile(
+ path: AppSettingsSecretJsonPath,
+ optional: optional,
+ reloadOnChange: reloadOnChange
+ );
+ });
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpCoreStringLocalizerFactoryExtensions.cs
similarity index 100%
rename from framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs
rename to framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpCoreStringLocalizerFactoryExtensions.cs
diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Content/IRemoteStreamContent.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Content/IRemoteStreamContent.cs
index 0145305f09..ba564df18e 100644
--- a/framework/src/Volo.Abp.Core/Volo/Abp/Content/IRemoteStreamContent.cs
+++ b/framework/src/Volo.Abp.Core/Volo/Abp/Content/IRemoteStreamContent.cs
@@ -1,15 +1,16 @@
-using System.IO;
+using System;
+using System.IO;
namespace Volo.Abp.Content
{
- public interface IRemoteStreamContent
+ public interface IRemoteStreamContent : IDisposable
{
+ string FileName { get; }
+
string ContentType { get; }
long? ContentLength { get; }
- string FileName { get; }
-
Stream GetStream();
}
}
diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Content/RemoteStreamContent.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Content/RemoteStreamContent.cs
index f24b4d83bd..4b301a3ad0 100644
--- a/framework/src/Volo.Abp.Core/Volo/Abp/Content/RemoteStreamContent.cs
+++ b/framework/src/Volo.Abp.Core/Volo/Abp/Content/RemoteStreamContent.cs
@@ -5,28 +5,40 @@ namespace Volo.Abp.Content
public class RemoteStreamContent : IRemoteStreamContent
{
private readonly Stream _stream;
+ private readonly bool _disposeStream;
+ private bool _disposed;
- public RemoteStreamContent(Stream stream)
+ public virtual string FileName { get; }
+
+ public virtual string ContentType { get; } = "application/octet-stream";
+
+ public virtual long? ContentLength { get; }
+
+ public RemoteStreamContent(Stream stream, string fileName = null, string contentType = null, long? readOnlyLength = null, bool disposeStream = true)
{
_stream = stream;
- }
- public RemoteStreamContent(Stream stream, string fileName)
- : this(stream)
- {
FileName = fileName;
- ContentType = "application/octet-stream";
+ if (contentType != null)
+ {
+ ContentType = contentType;
+ }
+ ContentLength = readOnlyLength ?? (_stream.CanSeek ? _stream.Length - _stream.Position : null);
+ _disposeStream = disposeStream;
}
- public virtual string ContentType { get; set; }
-
- public virtual long? ContentLength => GetStream().Length;
-
- public virtual string FileName { get; set; }
-
public virtual Stream GetStream()
{
return _stream;
}
+
+ public virtual void Dispose()
+ {
+ if (!_disposed && _disposeStream)
+ {
+ _disposed = true;
+ _stream?.Dispose();
+ }
+ }
}
}
diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IServiceExposingArgs.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IOnServiceExposingContext.cs
similarity index 100%
rename from framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IServiceExposingArgs.cs
rename to framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IOnServiceExposingContext.cs
diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/OnServiceExposingArgs.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/OnServiceExposingContext.cs
similarity index 100%
rename from framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/OnServiceExposingArgs.cs
rename to framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/OnServiceExposingContext.cs
diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLifecycleContributerBase.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLifecycleContributorBase.cs
similarity index 100%
rename from framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLifecycleContributerBase.cs
rename to framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLifecycleContributorBase.cs
diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/ConcurrencyStampExtensions.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/ConcurrencyStampExtensions.cs
new file mode 100644
index 0000000000..0d97d3a68a
--- /dev/null
+++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/ConcurrencyStampExtensions.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using Volo.Abp.Domain.Entities;
+using JetBrains.Annotations;
+
+namespace Volo.Abp.Data
+{
+ public static class ConcurrencyStampExtensions
+ {
+ public static void SetConcurrencyStampIfNotNull(this IHasConcurrencyStamp entity, [CanBeNull] string concurrencyStamp)
+ {
+ if (!concurrencyStamp.IsNullOrEmpty())
+ {
+ entity.ConcurrencyStamp = concurrencyStamp;
+ }
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/IConnectionStringResolverExtensions.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/ConnectionStringResolverExtensions.cs
similarity index 100%
rename from framework/src/Volo.Abp.Data/Volo/Abp/Data/IConnectionStringResolverExtensions.cs
rename to framework/src/Volo.Abp.Data/Volo/Abp/Data/ConnectionStringResolverExtensions.cs
diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/ro-RO.json b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/ro-RO.json
new file mode 100644
index 0000000000..1daa63ea0e
--- /dev/null
+++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/ro-RO.json
@@ -0,0 +1,6 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "MaxResultCountExceededExceptionMessage": "{0} nu poate fi mai mare decât {1}! Măriţi {2}.{3} pe partea de server pentru a permite mai multe rezultate."
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/BasicAggregateRoot.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/BasicAggregateRoot.cs
index 42b0ba1320..a4a90d1504 100644
--- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/BasicAggregateRoot.cs
+++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/BasicAggregateRoot.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+using Volo.Abp.Uow;
namespace Volo.Abp.Domain.Entities
{
@@ -9,15 +10,15 @@ namespace Volo.Abp.Domain.Entities
IAggregateRoot,
IGeneratesDomainEvents
{
- private readonly ICollection
+
diff --git a/framework/src/Volo.Abp.HangFire/Volo/Abp/Hangfire/AbpHangfireAuthorizationFilter.cs b/framework/src/Volo.Abp.HangFire/Volo/Abp/Hangfire/AbpHangfireAuthorizationFilter.cs
new file mode 100644
index 0000000000..15fbb4f60c
--- /dev/null
+++ b/framework/src/Volo.Abp.HangFire/Volo/Abp/Hangfire/AbpHangfireAuthorizationFilter.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Threading.Tasks;
+using Hangfire.Dashboard;
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.Authorization.Permissions;
+using Volo.Abp.Users;
+
+namespace Volo.Abp.Hangfire
+{
+ public class AbpHangfireAuthorizationFilter : IDashboardAsyncAuthorizationFilter
+ {
+ private readonly string _requiredPermissionName;
+
+ public AbpHangfireAuthorizationFilter(string requiredPermissionName = null)
+ {
+ _requiredPermissionName = requiredPermissionName;
+ }
+
+ public async Task AuthorizeAsync(DashboardContext context)
+ {
+ if (!IsLoggedIn(context))
+ {
+ return false;
+ }
+
+ if (_requiredPermissionName.IsNullOrEmpty())
+ {
+ return true;
+ }
+
+ return await IsPermissionGrantedAsync(context, _requiredPermissionName);
+ }
+
+ private static bool IsLoggedIn(DashboardContext context)
+ {
+ var currentUser = context.GetHttpContext().RequestServices.GetRequiredService();
+ return currentUser.IsAuthenticated;
+ }
+
+ private static async Task IsPermissionGrantedAsync(DashboardContext context, string requiredPermissionName)
+ {
+ var permissionChecker = context.GetHttpContext().RequestServices.GetRequiredService();
+ return await permissionChecker.IsGrantedAsync(requiredPermissionName);
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.HangFire/Volo/Abp/Hangfire/AbpHangfireModule.cs b/framework/src/Volo.Abp.HangFire/Volo/Abp/Hangfire/AbpHangfireModule.cs
index d69edb0b5d..1628d2f37f 100644
--- a/framework/src/Volo.Abp.HangFire/Volo/Abp/Hangfire/AbpHangfireModule.cs
+++ b/framework/src/Volo.Abp.HangFire/Volo/Abp/Hangfire/AbpHangfireModule.cs
@@ -1,10 +1,12 @@
using Hangfire;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
+using Volo.Abp.Authorization;
using Volo.Abp.Modularity;
namespace Volo.Abp.Hangfire
{
+ [DependsOn(typeof(AbpAuthorizationAbstractionsModule))]
public class AbpHangfireModule : AbpModule
{
private BackgroundJobServer _backgroundJobServer;
diff --git a/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Properties/launchSettings.json b/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Properties/launchSettings.json
deleted file mode 100644
index c5f82293b3..0000000000
--- a/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Properties/launchSettings.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:53610/",
- "sslPort": 44304
- }
- },
- "profiles": {
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "Volo.Abp.Http.Client.IdentityModel.Web": {
- "commandName": "Project",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- },
- "applicationUrl": "https://localhost:5001;http://localhost:5000"
- }
- }
-}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Volo.Abp.Http.Client.IdentityModel.Web.csproj b/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Volo.Abp.Http.Client.IdentityModel.Web.csproj
index 81a3d0ab9e..af28fdfba8 100644
--- a/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Volo.Abp.Http.Client.IdentityModel.Web.csproj
+++ b/framework/src/Volo.Abp.Http.Client.IdentityModel.Web/Volo.Abp.Http.Client.IdentityModel.Web.csproj
@@ -13,6 +13,7 @@
falsetrueLibrary
+ true
diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs
index fa963aef5e..cce91cb5d7 100644
--- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs
+++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs
@@ -37,7 +37,11 @@ namespace Volo.Abp.Http.Client.DynamicProxying
CancellationTokenProvider = NullCancellationTokenProvider.Instance;
}
- public async Task FindActionAsync(HttpClient client, string baseUrl, Type serviceType, MethodInfo method)
+ public async Task FindActionAsync(
+ HttpClient client,
+ string baseUrl,
+ Type serviceType,
+ MethodInfo method)
{
var apiDescription = await GetApiDescriptionAsync(client, baseUrl);
@@ -114,7 +118,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
- return (ApplicationApiDescriptionModel)result;
+ return result;
}
protected virtual void AddHeaders(HttpRequestMessage requestMessage)
diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs
index b94a5a339d..b1763d8825 100644
--- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs
+++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs
@@ -113,12 +113,11 @@ namespace Volo.Abp.Http.Client.DynamicProxying
/* returning a class that holds a reference to response
* content just to be sure that GC does not dispose of
* it before we finish doing our work with the stream */
- return (T)(object)new RemoteStreamContent(await responseContent.ReadAsStreamAsync())
- {
- ContentType = responseContent.Headers.ContentType?.ToString(),
- FileName = responseContent.Headers?.ContentDisposition?.FileNameStar ??
- RemoveQuotes(responseContent.Headers?.ContentDisposition?.FileName).ToString()
- };
+ return (T) (object) new RemoteStreamContent(
+ await responseContent.ReadAsStreamAsync(),
+ responseContent.Headers?.ContentDisposition?.FileNameStar ?? RemoveQuotes(responseContent.Headers?.ContentDisposition?.FileName).ToString(),
+ responseContent.Headers?.ContentType?.ToString(),
+ responseContent.Headers?.ContentLength);
}
var stringContent = await responseContent.ReadAsStringAsync();
@@ -174,7 +173,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
var response = await client.SendAsync(
requestMessage,
HttpCompletionOption.ResponseHeadersRead /*this will buffer only the headers, the content will be used as a stream*/,
- GetCancellationToken()
+ GetCancellationToken(invocation)
);
if (!response.IsSuccessStatusCode)
@@ -306,8 +305,18 @@ namespace Volo.Abp.Http.Client.DynamicProxying
return input;
}
- protected virtual CancellationToken GetCancellationToken()
+ protected virtual CancellationToken GetCancellationToken(IAbpMethodInvocation invocation)
{
+ var cancellationTokenArg = invocation.Arguments.LastOrDefault(x => x is CancellationToken);
+ if (cancellationTokenArg != null)
+ {
+ var cancellationToken = (CancellationToken) cancellationTokenArg;
+ if (cancellationToken != default)
+ {
+ return cancellationToken;
+ }
+ }
+
return CancellationTokenProvider.Token;
}
}
diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/RequestPayloadBuilder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/RequestPayloadBuilder.cs
index b121852c2c..d83b319b28 100644
--- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/RequestPayloadBuilder.cs
+++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/RequestPayloadBuilder.cs
@@ -82,16 +82,12 @@ namespace Volo.Abp.Http.Client.DynamicProxying
if (value is IRemoteStreamContent remoteStreamContent)
{
var stream = remoteStreamContent.GetStream();
- if (stream.CanSeek)
- {
- stream.Position = 0;
- }
var streamContent = new StreamContent(stream);
if (!remoteStreamContent.ContentType.IsNullOrWhiteSpace())
{
streamContent.Headers.ContentType = new MediaTypeHeaderValue(remoteStreamContent.ContentType);
-
}
+ streamContent.Headers.ContentLength = remoteStreamContent.ContentLength;
formData.Add(streamContent, parameter.Name, remoteStreamContent.FileName ?? parameter.Name);
}
else if (value is IEnumerable remoteStreamContents)
@@ -99,15 +95,12 @@ namespace Volo.Abp.Http.Client.DynamicProxying
foreach (var content in remoteStreamContents)
{
var stream = content.GetStream();
- if (stream.CanSeek)
- {
- stream.Position = 0;
- }
var streamContent = new StreamContent(stream);
if (!content.ContentType.IsNullOrWhiteSpace())
{
streamContent.Headers.ContentType = new MediaTypeHeaderValue(content.ContentType);
}
+ streamContent.Headers.ContentLength = content.ContentLength;
formData.Add(streamContent, parameter.Name, content.FileName ?? parameter.Name);
}
}
diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs
index 4d77423c7f..2a990c70d6 100644
--- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs
+++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs
@@ -132,14 +132,14 @@ namespace Volo.Abp.Http.Client.DynamicProxying
return true;
}
- private static string ConvertValueToString([NotNull] object value)
+ private static string ConvertValueToString([CanBeNull] object value)
{
if (value is DateTime dateTimeValue)
{
return dateTimeValue.ToUniversalTime().ToString("O");
}
- return value.ToString();
+ return value?.ToString();
}
}
}
diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/ro-RO.json b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/ro-RO.json
new file mode 100644
index 0000000000..0444f908b3
--- /dev/null
+++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/ro-RO.json
@@ -0,0 +1,19 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "DisplayName:Abp.Ldap.ServerHost": "Server host",
+ "Description:Abp.Ldap.ServerHost": "Server host",
+
+ "DisplayName:Abp.Ldap.ServerPort": "Server port",
+ "Description:Abp.Ldap.ServerPort": "Server port",
+
+ "DisplayName:Abp.Ldap.BaseDc": "Componenta domeniului de bază",
+ "Description:Abp.Ldap.BaseDc": "Componenta domeniului de bază",
+
+ "DisplayName:Abp.Ldap.UserName": "Nume de utilizator",
+ "Description:Abp.Ldap.UserName": "Nume de utilizator",
+
+ "DisplayName:Abp.Ldap.Password": "Parola",
+ "Description:Abp.Ldap.Password": "Parola"
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/StringLocalizerHelper.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpInternalLocalizationHelper.cs
similarity index 100%
rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/StringLocalizerHelper.cs
rename to framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpInternalLocalizationHelper.cs
diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/ro-RO.json b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/ro-RO.json
new file mode 100644
index 0000000000..2201b39e0b
--- /dev/null
+++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/ro-RO.json
@@ -0,0 +1,7 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "DisplayName:Abp.Localization.DefaultLanguage": "Limba implicită",
+ "Description:Abp.Localization.DefaultLanguage": "Limba implicită a aplicaţiei."
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs
index b915e968ca..cf3479de67 100644
--- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs
+++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs
@@ -12,6 +12,7 @@ using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Guids;
using Volo.Abp.MemoryDb;
+using Volo.Abp.Uow;
namespace Volo.Abp.Domain.Repositories.MemoryDb
{
@@ -65,7 +66,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
return ApplyDataFilters((await GetCollectionAsync()).AsQueryable());
}
- protected virtual async Task TriggerDomainEventsAsync(object entity)
+ protected virtual void TriggerDomainEvents(object entity)
{
var generatesDomainEventsEntity = entity as IGeneratesDomainEvents;
if (generatesDomainEventsEntity == null)
@@ -78,7 +79,13 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
{
foreach (var localEvent in localEvents)
{
- await LocalEventBus.PublishAsync(localEvent.GetType(), localEvent);
+ UnitOfWorkManager.Current?.AddOrReplaceLocalEvent(
+ new UnitOfWorkEventRecord(
+ localEvent.EventData.GetType(),
+ localEvent.EventData,
+ localEvent.EventOrder
+ )
+ );
}
generatesDomainEventsEntity.ClearLocalEvents();
@@ -89,7 +96,13 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
{
foreach (var distributedEvent in distributedEvents)
{
- await DistributedEventBus.PublishAsync(distributedEvent.GetType(), distributedEvent);
+ UnitOfWorkManager.Current?.AddOrReplaceDistributedEvent(
+ new UnitOfWorkEventRecord(
+ distributedEvent.EventData.GetType(),
+ distributedEvent.EventData,
+ distributedEvent.EventOrder
+ )
+ );
}
generatesDomainEventsEntity.ClearDistributedEvents();
@@ -143,37 +156,37 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
AuditPropertySetter.SetDeletionProperties(entity);
}
- protected virtual async Task TriggerEntityCreateEvents(TEntity entity)
+ protected virtual void TriggerEntityCreateEvents(TEntity entity)
{
- await EntityChangeEventHelper.TriggerEntityCreatedEventOnUowCompletedAsync(entity);
- await EntityChangeEventHelper.TriggerEntityCreatingEventAsync(entity);
+ EntityChangeEventHelper.PublishEntityCreatingEvent(entity);
+ EntityChangeEventHelper.PublishEntityCreatedEvent(entity);
}
- protected virtual async Task TriggerEntityUpdateEventsAsync(TEntity entity)
+ protected virtual void TriggerEntityUpdateEvents(TEntity entity)
{
- await EntityChangeEventHelper.TriggerEntityUpdatedEventOnUowCompletedAsync(entity);
- await EntityChangeEventHelper.TriggerEntityUpdatingEventAsync(entity);
+ EntityChangeEventHelper.PublishEntityUpdatingEvent(entity);
+ EntityChangeEventHelper.PublishEntityUpdatedEvent(entity);
}
- protected virtual async Task TriggerEntityDeleteEventsAsync(TEntity entity)
+ protected virtual void TriggerEntityDeleteEvents(TEntity entity)
{
- await EntityChangeEventHelper.TriggerEntityDeletedEventOnUowCompletedAsync(entity);
- await EntityChangeEventHelper.TriggerEntityDeletingEventAsync(entity);
+ EntityChangeEventHelper.PublishEntityDeletingEvent(entity);
+ EntityChangeEventHelper.PublishEntityDeletedEvent(entity);
}
- protected virtual async Task ApplyAbpConceptsForAddedEntityAsync(TEntity entity)
+ protected virtual void ApplyAbpConceptsForAddedEntity(TEntity entity)
{
CheckAndSetId(entity);
SetCreationAuditProperties(entity);
- await TriggerEntityCreateEvents(entity);
- await TriggerDomainEventsAsync(entity);
+ TriggerEntityCreateEvents(entity);
+ TriggerDomainEvents(entity);
}
- protected virtual async Task ApplyAbpConceptsForDeletedEntityAsync(TEntity entity)
+ protected virtual void ApplyAbpConceptsForDeletedEntity(TEntity entity)
{
SetDeletionAuditProperties(entity);
- await TriggerEntityDeleteEventsAsync(entity);
- await TriggerDomainEventsAsync(entity);
+ TriggerEntityDeleteEvents(entity);
+ TriggerDomainEvents(entity);
}
public override async Task FindAsync(
@@ -199,7 +212,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
bool autoSave = false,
CancellationToken cancellationToken = default)
{
- await ApplyAbpConceptsForAddedEntityAsync(entity);
+ ApplyAbpConceptsForAddedEntity(entity);
(await GetCollectionAsync()).Add(entity);
@@ -216,14 +229,14 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
if (entity is ISoftDelete softDeleteEntity && softDeleteEntity.IsDeleted)
{
SetDeletionAuditProperties(entity);
- await TriggerEntityDeleteEventsAsync(entity);
+ TriggerEntityDeleteEvents(entity);
}
else
{
- await TriggerEntityUpdateEventsAsync(entity);
+ TriggerEntityUpdateEvents(entity);
}
- await TriggerDomainEventsAsync(entity);
+ TriggerDomainEvents(entity);
(await GetCollectionAsync()).Update(entity);
@@ -235,7 +248,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
bool autoSave = false,
CancellationToken cancellationToken = default)
{
- await ApplyAbpConceptsForDeletedEntityAsync(entity);
+ ApplyAbpConceptsForDeletedEntity(entity);
if (entity is ISoftDelete softDeleteEntity && !IsHardDeleted(entity))
{
diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs
index 99e732cf9c..a40117e0ff 100644
--- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs
+++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs
@@ -17,6 +17,7 @@ using Volo.Abp.EventBus.Local;
using Volo.Abp.Guids;
using Volo.Abp.MongoDB;
using Volo.Abp.MultiTenancy;
+using Volo.Abp.Uow;
namespace Volo.Abp.Domain.Repositories.MongoDB
{
@@ -182,14 +183,14 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
if (entity is ISoftDelete softDeleteEntity && softDeleteEntity.IsDeleted)
{
SetDeletionAuditProperties(entity);
- await TriggerEntityDeleteEventsAsync(entity);
+ TriggerEntityDeleteEvents(entity);
}
else
{
- await TriggerEntityUpdateEventsAsync(entity);
+ TriggerEntityUpdateEvents(entity);
}
- await TriggerDomainEventsAsync(entity);
+ TriggerDomainEvents(entity);
var oldConcurrencyStamp = SetNewConcurrencyStamp(entity);
ReplaceOneResult result;
@@ -235,14 +236,14 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
if (isSoftDeleteEntity)
{
SetDeletionAuditProperties(entity);
- await TriggerEntityDeleteEventsAsync(entity);
+ TriggerEntityDeleteEvents(entity);
}
else
{
- await TriggerEntityUpdateEventsAsync(entity);
+ TriggerEntityUpdateEvents(entity);
}
- await TriggerDomainEventsAsync(entity);
+ TriggerDomainEvents(entity);
SetNewConcurrencyStamp(entity);
}
@@ -295,7 +296,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)) && !IsHardDeleted(entity))
{
((ISoftDelete)entity).IsDeleted = true;
- await ApplyAbpConceptsForDeletedEntityAsync(entity);
+ ApplyAbpConceptsForDeletedEntity(entity);
ReplaceOneResult result;
@@ -324,7 +325,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
}
else
{
- await ApplyAbpConceptsForDeletedEntityAsync(entity);
+ ApplyAbpConceptsForDeletedEntity(entity);
DeleteResult result;
@@ -374,7 +375,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
hardDeletedEntities.Add(entity);
}
- await ApplyAbpConceptsForDeletedEntityAsync(entity);
+ ApplyAbpConceptsForDeletedEntity(entity);
}
var dbContext = await GetDbContextAsync(cancellationToken);
@@ -573,33 +574,33 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
{
CheckAndSetId(entity);
SetCreationAuditProperties(entity);
- await TriggerEntityCreateEvents(entity);
- await TriggerDomainEventsAsync(entity);
+ TriggerEntityCreateEvents(entity);
+ TriggerDomainEvents(entity);
}
- private async Task TriggerEntityCreateEvents(TEntity entity)
+ private void TriggerEntityCreateEvents(TEntity entity)
{
- await EntityChangeEventHelper.TriggerEntityCreatedEventOnUowCompletedAsync(entity);
- await EntityChangeEventHelper.TriggerEntityCreatingEventAsync(entity);
+ EntityChangeEventHelper.PublishEntityCreatingEvent(entity);
+ EntityChangeEventHelper.PublishEntityCreatedEvent(entity);
}
- protected virtual async Task TriggerEntityUpdateEventsAsync(TEntity entity)
+ protected virtual void TriggerEntityUpdateEvents(TEntity entity)
{
- await EntityChangeEventHelper.TriggerEntityUpdatedEventOnUowCompletedAsync(entity);
- await EntityChangeEventHelper.TriggerEntityUpdatingEventAsync(entity);
+ EntityChangeEventHelper.PublishEntityUpdatingEvent(entity);
+ EntityChangeEventHelper.PublishEntityUpdatedEvent(entity);
}
- protected virtual async Task ApplyAbpConceptsForDeletedEntityAsync(TEntity entity)
+ protected virtual void ApplyAbpConceptsForDeletedEntity(TEntity entity)
{
SetDeletionAuditProperties(entity);
- await TriggerEntityDeleteEventsAsync(entity);
- await TriggerDomainEventsAsync(entity);
+ TriggerEntityDeleteEvents(entity);
+ TriggerDomainEvents(entity);
}
- protected virtual async Task TriggerEntityDeleteEventsAsync(TEntity entity)
+ protected virtual void TriggerEntityDeleteEvents(TEntity entity)
{
- await EntityChangeEventHelper.TriggerEntityDeletedEventOnUowCompletedAsync(entity);
- await EntityChangeEventHelper.TriggerEntityDeletingEventAsync(entity);
+ EntityChangeEventHelper.PublishEntityDeletingEvent(entity);
+ EntityChangeEventHelper.PublishEntityDeletedEvent(entity);
}
protected virtual void CheckAndSetId(TEntity entity)
@@ -639,7 +640,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
AuditPropertySetter.SetDeletionProperties(entity);
}
- protected virtual async Task TriggerDomainEventsAsync(object entity)
+ protected virtual void TriggerDomainEvents(object entity)
{
var generatesDomainEventsEntity = entity as IGeneratesDomainEvents;
if (generatesDomainEventsEntity == null)
@@ -652,7 +653,13 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
{
foreach (var localEvent in localEvents)
{
- await LocalEventBus.PublishAsync(localEvent.GetType(), localEvent);
+ UnitOfWorkManager.Current?.AddOrReplaceLocalEvent(
+ new UnitOfWorkEventRecord(
+ localEvent.EventData.GetType(),
+ localEvent.EventData,
+ localEvent.EventOrder
+ )
+ );
}
generatesDomainEventsEntity.ClearLocalEvents();
@@ -663,7 +670,13 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
{
foreach (var distributedEvent in distributedEvents)
{
- await DistributedEventBus.PublishAsync(distributedEvent.GetType(), distributedEvent);
+ UnitOfWorkManager.Current?.AddOrReplaceDistributedEvent(
+ new UnitOfWorkEventRecord(
+ distributedEvent.EventData.GetType(),
+ distributedEvent.EventData,
+ distributedEvent.EventOrder
+ )
+ );
}
generatesDomainEventsEntity.ClearDistributedEvents();
diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContextOptions.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContextOptions.cs
index aaee9571cd..0cd282ec68 100644
--- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContextOptions.cs
+++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContextOptions.cs
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
+using System.Threading.Tasks;
+using MongoDB.Driver;
namespace Volo.Abp.MongoDB
{
@@ -7,11 +9,13 @@ namespace Volo.Abp.MongoDB
{
internal Dictionary DbContextReplacements { get; }
+ public Action MongoClientSettingsConfigurer { get; set; }
+
public AbpMongoDbContextOptions()
{
DbContextReplacements = new Dictionary();
}
-
+
internal Type GetReplacedTypeOrSelf(Type dbContextType)
{
var replacementType = dbContextType;
@@ -26,7 +30,7 @@ namespace Volo.Abp.MongoDB
dbContextType.AssemblyQualifiedName
);
}
-
+
replacementType = foundType;
}
else
@@ -36,4 +40,4 @@ namespace Volo.Abp.MongoDB
}
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs
index 2a3842441f..671a676726 100644
--- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs
+++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs
@@ -29,7 +29,7 @@ namespace Volo.Abp.Uow.MongoDB
IUnitOfWorkManager unitOfWorkManager,
IConnectionStringResolver connectionStringResolver,
ICancellationTokenProvider cancellationTokenProvider,
- ICurrentTenant currentTenant,
+ ICurrentTenant currentTenant,
IOptions options)
{
_unitOfWorkManager = unitOfWorkManager;
@@ -124,7 +124,7 @@ namespace Volo.Abp.Uow.MongoDB
private TMongoDbContext CreateDbContext(IUnitOfWork unitOfWork, MongoUrl mongoUrl, string databaseName)
{
- var client = new MongoClient(mongoUrl);
+ var client = CreateMongoClient(mongoUrl);
var database = client.GetDatabase(databaseName);
if (unitOfWork.Options.IsTransactional)
@@ -144,7 +144,7 @@ namespace Volo.Abp.Uow.MongoDB
string databaseName,
CancellationToken cancellationToken = default)
{
- var client = new MongoClient(mongoUrl);
+ var client = CreateMongoClient(mongoUrl);
var database = client.GetDatabase(databaseName);
if (unitOfWork.Options.IsTransactional)
@@ -273,6 +273,14 @@ namespace Volo.Abp.Uow.MongoDB
return _connectionStringResolver.Resolve(dbContextType);
}
+ private MongoClient CreateMongoClient(MongoUrl mongoUrl)
+ {
+ var mongoClientSettings = MongoClientSettings.FromUrl(mongoUrl);
+ _options.MongoClientSettingsConfigurer?.Invoke(mongoClientSettings);
+
+ return new MongoClient(mongoClientSettings);
+ }
+
protected virtual CancellationToken GetCancellationToken(CancellationToken preferredValue = default)
{
return _cancellationTokenProvider.FallbackToProvider(preferredValue);
diff --git a/framework/src/Volo.Abp.MultiTenancy/System/Security/Principal/AbpClaimsIdentityExtensions.cs b/framework/src/Volo.Abp.MultiTenancy/System/Security/Principal/AbpMultiTenancyClaimsIdentityExtensions.cs
similarity index 100%
rename from framework/src/Volo.Abp.MultiTenancy/System/Security/Principal/AbpClaimsIdentityExtensions.cs
rename to framework/src/Volo.Abp.MultiTenancy/System/Security/Principal/AbpMultiTenancyClaimsIdentityExtensions.cs
diff --git a/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/IgnoreMultiTenancy.cs b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/IgnoreMultiTenancyAttribute.cs
similarity index 100%
rename from framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/IgnoreMultiTenancy.cs
rename to framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/IgnoreMultiTenancyAttribute.cs
diff --git a/framework/src/Volo.Abp.Sms.Aliyun/Volo.Abp.Sms.Aliyun.csproj b/framework/src/Volo.Abp.Sms.Aliyun/Volo.Abp.Sms.Aliyun.csproj
index cae6301daf..83cea09848 100644
--- a/framework/src/Volo.Abp.Sms.Aliyun/Volo.Abp.Sms.Aliyun.csproj
+++ b/framework/src/Volo.Abp.Sms.Aliyun/Volo.Abp.Sms.Aliyun.csproj
@@ -18,6 +18,7 @@
+
diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/CancellationTokenOverride.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/CancellationTokenOverride.cs
new file mode 100644
index 0000000000..371e3d6652
--- /dev/null
+++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/CancellationTokenOverride.cs
@@ -0,0 +1,14 @@
+using System.Threading;
+
+namespace Volo.Abp.Threading
+{
+ public class CancellationTokenOverride
+ {
+ public CancellationToken CancellationToken { get; }
+
+ public CancellationTokenOverride(CancellationToken cancellationToken)
+ {
+ CancellationToken = cancellationToken;
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/CancellationTokenProviderBase.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/CancellationTokenProviderBase.cs
new file mode 100644
index 0000000000..20101a95da
--- /dev/null
+++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/CancellationTokenProviderBase.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Threading;
+
+namespace Volo.Abp.Threading
+{
+ public abstract class CancellationTokenProviderBase : ICancellationTokenProvider
+ {
+ public const string CancellationTokenOverrideContextKey = "Volo.Abp.Threading.CancellationToken.Override";
+
+ public abstract CancellationToken Token { get; }
+
+ protected IAmbientScopeProvider CancellationTokenOverrideScopeProvider { get; }
+
+ protected CancellationTokenOverride OverrideValue => CancellationTokenOverrideScopeProvider.GetValue(CancellationTokenOverrideContextKey);
+
+ protected CancellationTokenProviderBase(IAmbientScopeProvider cancellationTokenOverrideScopeProvider)
+ {
+ CancellationTokenOverrideScopeProvider = cancellationTokenOverrideScopeProvider;
+ }
+
+ public IDisposable Use(CancellationToken cancellationToken)
+ {
+ return CancellationTokenOverrideScopeProvider.BeginScope(CancellationTokenOverrideContextKey, new CancellationTokenOverride(cancellationToken));
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/ICancellationTokenProvider.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/ICancellationTokenProvider.cs
index 24e303adde..06dc008d52 100644
--- a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/ICancellationTokenProvider.cs
+++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/ICancellationTokenProvider.cs
@@ -1,9 +1,12 @@
-using System.Threading;
+using System;
+using System.Threading;
namespace Volo.Abp.Threading
{
public interface ICancellationTokenProvider
{
CancellationToken Token { get; }
+
+ IDisposable Use(CancellationToken cancellationToken);
}
}
diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/NullCancellationTokenProvider.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/NullCancellationTokenProvider.cs
index ab6320546c..6c2b4d364c 100644
--- a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/NullCancellationTokenProvider.cs
+++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/NullCancellationTokenProvider.cs
@@ -2,15 +2,15 @@
namespace Volo.Abp.Threading
{
- public class NullCancellationTokenProvider : ICancellationTokenProvider
+ public class NullCancellationTokenProvider : CancellationTokenProviderBase
{
public static NullCancellationTokenProvider Instance { get; } = new NullCancellationTokenProvider();
- public CancellationToken Token { get; } = CancellationToken.None;
+ public override CancellationToken Token => OverrideValue?.CancellationToken ?? CancellationToken.None;
private NullCancellationTokenProvider()
+ : base(new AmbientDataContextAmbientScopeProvider(new AsyncLocalAmbientDataContext()))
{
-
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Localization/ro-RO.json b/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Localization/ro-RO.json
new file mode 100644
index 0000000000..08716f8f5f
--- /dev/null
+++ b/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Localization/ro-RO.json
@@ -0,0 +1,7 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "DisplayName:Abp.Timing.Timezone": "Fus orar",
+ "Description:Abp.Timing.Timezone": "Fusul orar al aplicaţiei"
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/ro-RO.json b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/ro-RO.json
new file mode 100644
index 0000000000..fc7069e2f9
--- /dev/null
+++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/ro-RO.json
@@ -0,0 +1,6 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "Menu:Administration": "Administrare"
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json
new file mode 100644
index 0000000000..b7562858d6
--- /dev/null
+++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json
@@ -0,0 +1,52 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "Languages": "Limbi",
+ "AreYouSure": "Sunteţi sigur(ă)?",
+ "Cancel": "Anulează",
+ "Clear": "Goleşte",
+ "Yes": "Da",
+ "No": "Nu",
+ "Ok": "Ok",
+ "Close": "Închide",
+ "Save": "Salvează",
+ "SavingWithThreeDot": "Se salvează...",
+ "Actions": "Acţiuni",
+ "Delete": "Şterge",
+ "Edit": "Editează",
+ "Refresh": "Reîncarcă",
+ "Language": "Limba",
+ "LoadMore": "Încarcă mai multe",
+ "ProcessingWithThreeDot": "Se procesează...",
+ "LoadingWithThreeDot": "Se încarcă...",
+ "Welcome": "Bun venit",
+ "Login": "Autentificare",
+ "Register": "Înregistrare",
+ "Logout": "Delogare",
+ "Submit": "Trimite",
+ "Back": "Înapoi",
+ "PagerSearch": "Caută",
+ "PagerNext": "Următorul",
+ "PagerPrevious": "Anterior",
+ "PagerFirst": "Primul",
+ "PagerLast": "Ultimul",
+ "PagerInfo": "Afişate _START_ to _END_ of _TOTAL_ înregistrări",
+ "PagerInfo{0}{1}{2}": "Afişate {0} to {1} of {2} înregistrări",
+ "PagerInfoEmpty": "Afişate 0 to 0 of 0 înregistrări",
+ "PagerInfoFiltered": "(filtrate de la _MAX_ înregistrări totale)",
+ "NoDataAvailableInDatatable": "Nicio informaţie disponibilă",
+ "Total": "total",
+ "Selected": "selectate",
+ "PagerShowMenuEntries": "Arată _MENU_ intrări",
+ "DatatableActionDropdownDefaultText": "Acţiuni",
+ "ChangePassword": "Schimbă parola",
+ "PersonalInfo": "Profilul meu",
+ "AreYouSureYouWantToCancelEditingWarningMessage": "Aveţi modificări nesalvate.",
+ "GoHomePage": "Pagina principală",
+ "GoBack": "Înapoi",
+ "Search": "Caută",
+ "ItemWillBeDeletedMessageWithFormat": "{0} va fi şters!",
+ "ItemWillBeDeletedMessage": "Acest articol va fi şters!",
+ "ManageYourAccount": "Administraţi-vă contul"
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AmbientUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AmbientUnitOfWork.cs
index 7b3a45b20c..3418b1d897 100644
--- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AmbientUnitOfWork.cs
+++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AmbientUnitOfWork.cs
@@ -19,5 +19,18 @@ namespace Volo.Abp.Uow
{
_currentUow.Value = unitOfWork;
}
+
+ public IUnitOfWork GetCurrentByChecking()
+ {
+ var uow = UnitOfWork;
+
+ //Skip reserved unit of work
+ while (uow != null && (uow.IsReserved || uow.IsDisposed || uow.IsCompleted))
+ {
+ uow = uow.Outer;
+ }
+
+ return uow;
+ }
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs
index 882c8d6a70..1f7b07f1c5 100644
--- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs
+++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs
@@ -76,6 +76,20 @@ namespace Volo.Abp.Uow
_parent.OnCompleted(handler);
}
+ public void AddOrReplaceLocalEvent(
+ UnitOfWorkEventRecord eventRecord,
+ Predicate replacementSelector = null)
+ {
+ _parent.AddOrReplaceLocalEvent(eventRecord, replacementSelector);
+ }
+
+ public void AddOrReplaceDistributedEvent(
+ UnitOfWorkEventRecord eventRecord,
+ Predicate replacementSelector = null)
+ {
+ _parent.AddOrReplaceDistributedEvent(eventRecord, replacementSelector);
+ }
+
public IDatabaseApi FindDatabaseApi(string key)
{
return _parent.FindDatabaseApi(key);
diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/EventOrderGenerator.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/EventOrderGenerator.cs
new file mode 100644
index 0000000000..feb5dbfd08
--- /dev/null
+++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/EventOrderGenerator.cs
@@ -0,0 +1,14 @@
+using System.Threading;
+
+namespace Volo.Abp.Uow
+{
+ public static class EventOrderGenerator
+ {
+ private static long _lastOrder;
+
+ public static long GetNext()
+ {
+ return Interlocked.Increment(ref _lastOrder);
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IAmbientUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IAmbientUnitOfWork.cs
index b613ccec59..524a92e63d 100644
--- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IAmbientUnitOfWork.cs
+++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IAmbientUnitOfWork.cs
@@ -2,6 +2,6 @@
{
public interface IAmbientUnitOfWork : IUnitOfWorkAccessor
{
-
+ IUnitOfWork GetCurrentByChecking();
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs
index ee5baa58bc..0b8a96297e 100644
--- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs
+++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs
@@ -42,5 +42,15 @@ namespace Volo.Abp.Uow
Task RollbackAsync(CancellationToken cancellationToken = default);
void OnCompleted(Func handler);
+
+ void AddOrReplaceLocalEvent(
+ UnitOfWorkEventRecord eventRecord,
+ Predicate replacementSelector = null
+ );
+
+ void AddOrReplaceDistributedEvent(
+ UnitOfWorkEventRecord eventRecord,
+ Predicate replacementSelector = null
+ );
}
}
diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs
new file mode 100644
index 0000000000..a060d2903e
--- /dev/null
+++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Volo.Abp.Uow
+{
+ public interface IUnitOfWorkEventPublisher
+ {
+ Task PublishLocalEventsAsync(IEnumerable localEvents);
+
+ Task PublishDistributedEventsAsync(IEnumerable distributedEvents);
+ }
+}
diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkEventPublisher.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkEventPublisher.cs
new file mode 100644
index 0000000000..533695f902
--- /dev/null
+++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkEventPublisher.cs
@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+
+namespace Volo.Abp.Uow
+{
+ public class NullUnitOfWorkEventPublisher : IUnitOfWorkEventPublisher, ISingletonDependency
+ {
+ public Task PublishLocalEventsAsync(IEnumerable localEvents)
+ {
+ return Task.CompletedTask;
+ }
+
+ public Task PublishDistributedEventsAsync(IEnumerable distributedEvents)
+ {
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs
index 7b4f8fda33..520fa69392 100644
--- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs
+++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
@@ -33,11 +34,14 @@ namespace Volo.Abp.Uow
public string ReservationName { get; set; }
protected List> CompletedHandlers { get; } = new List>();
+ protected List DistributedEvents { get; } = new List();
+ protected List LocalEvents { get; } = new List();
public event EventHandler Failed;
public event EventHandler Disposed;
public IServiceProvider ServiceProvider { get; }
+ protected IUnitOfWorkEventPublisher UnitOfWorkEventPublisher { get; }
[NotNull]
public Dictionary Items { get; }
@@ -50,9 +54,13 @@ namespace Volo.Abp.Uow
private bool _isCompleting;
private bool _isRolledback;
- public UnitOfWork(IServiceProvider serviceProvider, IOptions options)
+ public UnitOfWork(
+ IServiceProvider serviceProvider,
+ IUnitOfWorkEventPublisher unitOfWorkEventPublisher,
+ IOptions options)
{
ServiceProvider = serviceProvider;
+ UnitOfWorkEventPublisher = unitOfWorkEventPublisher;
_defaultOptions = options.Value;
_databaseApis = new Dictionary();
@@ -103,12 +111,12 @@ namespace Volo.Abp.Uow
}
}
- public IReadOnlyList GetAllActiveDatabaseApis()
+ public virtual IReadOnlyList GetAllActiveDatabaseApis()
{
return _databaseApis.Values.ToImmutableList();
}
- public IReadOnlyList GetAllActiveTransactionApis()
+ public virtual IReadOnlyList GetAllActiveTransactionApis()
{
return _transactionApis.Values.ToImmutableList();
}
@@ -126,6 +134,30 @@ namespace Volo.Abp.Uow
{
_isCompleting = true;
await SaveChangesAsync(cancellationToken);
+
+ while (LocalEvents.Any() || DistributedEvents.Any())
+ {
+ if (LocalEvents.Any())
+ {
+ var localEventsToBePublished = LocalEvents.OrderBy(e => e.EventOrder).ToArray();
+ LocalEvents.Clear();
+ await UnitOfWorkEventPublisher.PublishLocalEventsAsync(
+ localEventsToBePublished
+ );
+ }
+
+ if (DistributedEvents.Any())
+ {
+ var distributedEventsToBePublished = DistributedEvents.OrderBy(e => e.EventOrder).ToArray();
+ DistributedEvents.Clear();
+ await UnitOfWorkEventPublisher.PublishDistributedEventsAsync(
+ distributedEventsToBePublished
+ );
+ }
+
+ await SaveChangesAsync(cancellationToken);
+ }
+
await CommitTransactionsAsync();
IsCompleted = true;
await OnCompletedAsync();
@@ -149,12 +181,12 @@ namespace Volo.Abp.Uow
await RollbackAllAsync(cancellationToken);
}
- public IDatabaseApi FindDatabaseApi(string key)
+ public virtual IDatabaseApi FindDatabaseApi(string key)
{
return _databaseApis.GetOrDefault(key);
}
- public void AddDatabaseApi(string key, IDatabaseApi api)
+ public virtual void AddDatabaseApi(string key, IDatabaseApi api)
{
Check.NotNull(key, nameof(key));
Check.NotNull(api, nameof(api));
@@ -167,7 +199,7 @@ namespace Volo.Abp.Uow
_databaseApis.Add(key, api);
}
- public IDatabaseApi GetOrAddDatabaseApi(string key, Func factory)
+ public virtual IDatabaseApi GetOrAddDatabaseApi(string key, Func factory)
{
Check.NotNull(key, nameof(key));
Check.NotNull(factory, nameof(factory));
@@ -175,14 +207,14 @@ namespace Volo.Abp.Uow
return _databaseApis.GetOrAdd(key, factory);
}
- public ITransactionApi FindTransactionApi(string key)
+ public virtual ITransactionApi FindTransactionApi(string key)
{
Check.NotNull(key, nameof(key));
return _transactionApis.GetOrDefault(key);
}
- public void AddTransactionApi(string key, ITransactionApi api)
+ public virtual void AddTransactionApi(string key, ITransactionApi api)
{
Check.NotNull(key, nameof(key));
Check.NotNull(api, nameof(api));
@@ -195,7 +227,7 @@ namespace Volo.Abp.Uow
_transactionApis.Add(key, api);
}
- public ITransactionApi GetOrAddTransactionApi(string key, Func factory)
+ public virtual ITransactionApi GetOrAddTransactionApi(string key, Func factory)
{
Check.NotNull(key, nameof(key));
Check.NotNull(factory, nameof(factory));
@@ -203,11 +235,48 @@ namespace Volo.Abp.Uow
return _transactionApis.GetOrAdd(key, factory);
}
- public void OnCompleted(Func handler)
+ public virtual void OnCompleted(Func handler)
{
CompletedHandlers.Add(handler);
}
+ public virtual void AddOrReplaceLocalEvent(
+ UnitOfWorkEventRecord eventRecord,
+ Predicate replacementSelector = null)
+ {
+ AddOrReplaceEvent(LocalEvents, eventRecord, replacementSelector);
+ }
+
+ public virtual void AddOrReplaceDistributedEvent(
+ UnitOfWorkEventRecord eventRecord,
+ Predicate replacementSelector = null)
+ {
+ AddOrReplaceEvent(DistributedEvents, eventRecord, replacementSelector);
+ }
+
+ public virtual void AddOrReplaceEvent(
+ List eventRecords,
+ UnitOfWorkEventRecord eventRecord,
+ Predicate replacementSelector = null)
+ {
+ if (replacementSelector == null)
+ {
+ eventRecords.Add(eventRecord);
+ }
+ else
+ {
+ var foundIndex = eventRecords.FindIndex(replacementSelector);
+ if (foundIndex < 0)
+ {
+ eventRecords.Add(eventRecord);
+ }
+ else
+ {
+ eventRecords[foundIndex] = eventRecord;
+ }
+ }
+ }
+
protected virtual async Task OnCompletedAsync()
{
foreach (var handler in CompletedHandlers)
diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkEventRecord.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkEventRecord.cs
new file mode 100644
index 0000000000..11ae4920cd
--- /dev/null
+++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkEventRecord.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+
+namespace Volo.Abp.Uow
+{
+ public class UnitOfWorkEventRecord
+ {
+ public object EventData { get; }
+
+ public Type EventType { get; }
+
+ public long EventOrder { get; }
+
+ ///
+ /// Extra properties can be used if needed.
+ ///
+ public Dictionary Properties { get; } = new Dictionary();
+
+ public UnitOfWorkEventRecord(
+ Type eventType,
+ object eventData,
+ long eventOrder)
+ {
+ EventType = eventType;
+ EventData = eventData;
+ EventOrder = eventOrder;
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManager.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManager.cs
index de0d8daa0a..9a9b3c7b38 100644
--- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManager.cs
+++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManager.cs
@@ -10,7 +10,7 @@ namespace Volo.Abp.Uow
[Obsolete("This will be removed in next versions.")]
public static AsyncLocal DisableObsoleteDbContextCreationWarning { get; } = new AsyncLocal();
- public IUnitOfWork Current => GetCurrentUnitOfWork();
+ public IUnitOfWork Current => _ambientUnitOfWork.GetCurrentByChecking();
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly IAmbientUnitOfWork _ambientUnitOfWork;
@@ -86,19 +86,6 @@ namespace Volo.Abp.Uow
return true;
}
- private IUnitOfWork GetCurrentUnitOfWork()
- {
- var uow = _ambientUnitOfWork.UnitOfWork;
-
- //Skip reserved unit of work
- while (uow != null && (uow.IsReserved || uow.IsDisposed || uow.IsCompleted))
- {
- uow = uow.Outer;
- }
-
- return uow;
- }
-
private IUnitOfWork CreateNewUnitOfWork()
{
var scope = _serviceScopeFactory.CreateScope();
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/DataAnnotationObjectValidationContributor.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/DataAnnotationObjectValidationContributor.cs
index 912f68e4af..15e367cefc 100644
--- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/DataAnnotationObjectValidationContributor.cs
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/DataAnnotationObjectValidationContributor.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
+using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
@@ -26,9 +27,10 @@ namespace Volo.Abp.Validation
Options = options.Value;
}
- public void AddErrors(ObjectValidationContext context)
+ public Task AddErrorsAsync(ObjectValidationContext context)
{
ValidateObjectRecursively(context.Errors, context.ValidatingObject, currentDepth: 1);
+ return Task.CompletedTask;
}
protected virtual void ValidateObjectRecursively(List errors, object validatingObject, int currentDepth)
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IMethodInvocationValidator.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IMethodInvocationValidator.cs
index fd413bc498..89eec62116 100644
--- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IMethodInvocationValidator.cs
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IMethodInvocationValidator.cs
@@ -1,7 +1,9 @@
-namespace Volo.Abp.Validation
+using System.Threading.Tasks;
+
+namespace Volo.Abp.Validation
{
public interface IMethodInvocationValidator
{
- void Validate(MethodInvocationValidationContext context);
+ Task ValidateAsync(MethodInvocationValidationContext context);
}
}
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IObjectValidationContributor.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IObjectValidationContributor.cs
index ca50901bcd..45d0ddcd9b 100644
--- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IObjectValidationContributor.cs
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IObjectValidationContributor.cs
@@ -1,7 +1,9 @@
-namespace Volo.Abp.Validation
+using System.Threading.Tasks;
+
+namespace Volo.Abp.Validation
{
public interface IObjectValidationContributor
{
- void AddErrors(ObjectValidationContext context);
+ Task AddErrorsAsync(ObjectValidationContext context);
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IObjectValidator.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IObjectValidator.cs
index 0ce723bab8..1b7c5881ee 100644
--- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IObjectValidator.cs
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IObjectValidator.cs
@@ -1,20 +1,21 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
+using System.Threading.Tasks;
namespace Volo.Abp.Validation
{
public interface IObjectValidator
{
- void Validate(
+ Task ValidateAsync(
object validatingObject,
string name = null,
bool allowNull = false
);
- List GetErrors(
+ Task> GetErrorsAsync(
object validatingObject,
string name = null,
bool allowNull = false
);
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ro-RO.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ro-RO.json
new file mode 100644
index 0000000000..ce03ecb52b
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ro-RO.json
@@ -0,0 +1,34 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "'{0}' and '{1}' do not match.": "'{0}' şi '{1}' nu se potrivesc.",
+ "The {0} field is not a valid credit card number.": "Câmpul {0} nu este un număr valid de card de credit.",
+ "{0} is not valid.": "{0} nu este valid.",
+ "The {0} field is not a valid e-mail address.": "Câmpul {0} nu este o adresa de e-mail validă.",
+ "The {0} field only accepts files with the following extensions: {1}": "Câmpul {0} acceptă doar fişiere cu următoarele extensii: {1}",
+ "The field {0} must be a string or array type with a maximum length of '{1}'.": "Câmpul field {0} trebuie să fie de tipul string sau array cu lungimea maximă de '{1}'.",
+ "The field {0} must be a string or array type with a minimum length of '{1}'.": "Câmpul field {0} trebuie să fie de tipul string sau array cu lungimea minimă de '{1}'.",
+ "The {0} field is not a valid phone number.": "Câmpul {0} nu este un număr de telefon valid.",
+ "The field {0} must be between {1} and {2}.": "Câmpul {0} trebuie să fie între {1} şi {2}.",
+ "The field {0} must match the regular expression '{1}'.": "Câmpul {0} nu corespunde formatului solicitat.",
+ "The {0} field is required.": "Câmpul {0} este obligatoriu.",
+ "The field {0} must be a string with a maximum length of {1}.": "Câmpul {0} trebuie să fie un string cu lungimea maximă de {1}.",
+ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Câmpul {0} trebuie să fie un string cu lungimea minimă de {2} şi lungimea maximă de {1}.",
+ "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Câmpul {0} nu este o adresă validă complet http, https sau ftp.",
+ "The field {0} is invalid.": "Câmpul {0} este invalid.",
+ "ThisFieldIsNotAValidCreditCardNumber.": "Acest câmp nu este un număr de card de credit valid.",
+ "ThisFieldIsNotValid.": "Acest câmp nu este valid.",
+ "ThisFieldIsNotAValidEmailAddress.": "Acest câmp nu este o adresă de e-mail validă.",
+ "ThisFieldOnlyAcceptsFilesWithTheFollowingExtensions:{0}": "Acest câmp acceptă doar fişiere cu următoarele extensii: {0}",
+ "ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthOf{0}": "Acest câmp trebuie să fie de tipul string sau array cu lungimea maximă de '{0}'.",
+ "ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf{0}": "Acest câmp trebuie să fie de tipul string sau arraz cu lungimea minimă de '{0}'.",
+ "ThisFieldIsNotAValidPhoneNumber.": "Acest câmp nu este un număr de telefon valid.",
+ "ThisFieldMustBeBetween{0}And{1}": "Acest câmp trebuie să fie între {0} şi {1}.",
+ "ThisFieldMustMatchTheRegularExpression{0}": "Acest câmp trebuie să se potrivească cu expresia uzuală '{0}'.",
+ "ThisFieldIsRequired.": "Acest câmp este obligatoriu.",
+ "ThisFieldMustBeAStringWithAMaximumLengthOf{0}": "Acest câmp trebuie să fie un string cu lungimea maximă de {0}.",
+ "ThisFieldMustBeAStringWithAMinimumLengthOf{1}AndAMaximumLengthOf{0}": "Acest câmp trebuie să fie un string cu lungimea minimă de {1} şi lungimea maximă de {0}.",
+ "ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "Acest câmp nu este o adresă validă http, https sau ftp.",
+ "ThisFieldIsInvalid.": "Acest câmp este invalid."
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/MethodInvocationValidator.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/MethodInvocationValidator.cs
index 584f787a6e..3aeaf57fc7 100644
--- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/MethodInvocationValidator.cs
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/MethodInvocationValidator.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Reflection;
@@ -16,7 +17,7 @@ namespace Volo.Abp.Validation
_objectValidator = objectValidator;
}
- public virtual void Validate(MethodInvocationValidationContext context)
+ public virtual async Task ValidateAsync(MethodInvocationValidationContext context)
{
Check.NotNull(context, nameof(context));
@@ -46,7 +47,7 @@ namespace Volo.Abp.Validation
ThrowValidationError(context);
}
- AddMethodParameterValidationErrors(context);
+ await AddMethodParameterValidationErrorsAsync(context);
if (context.Errors.Any())
{
@@ -60,7 +61,7 @@ namespace Volo.Abp.Validation
{
return false;
}
-
+
if (ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(context.Method) != null)
{
return true;
@@ -82,22 +83,22 @@ namespace Volo.Abp.Validation
);
}
- protected virtual void AddMethodParameterValidationErrors(MethodInvocationValidationContext context)
+ protected virtual async Task AddMethodParameterValidationErrorsAsync(MethodInvocationValidationContext context)
{
for (var i = 0; i < context.Parameters.Length; i++)
{
- AddMethodParameterValidationErrors(context, context.Parameters[i], context.ParameterValues[i]);
+ await AddMethodParameterValidationErrorsAsync(context, context.Parameters[i], context.ParameterValues[i]);
}
}
- protected virtual void AddMethodParameterValidationErrors(IAbpValidationResult context, ParameterInfo parameterInfo, object parameterValue)
+ protected virtual async Task AddMethodParameterValidationErrorsAsync(IAbpValidationResult context, ParameterInfo parameterInfo, object parameterValue)
{
var allowNulls = parameterInfo.IsOptional ||
parameterInfo.IsOut ||
TypeHelper.IsPrimitiveExtended(parameterInfo.ParameterType, includeEnums: true);
context.Errors.AddRange(
- _objectValidator.GetErrors(
+ await _objectValidator.GetErrorsAsync(
parameterValue,
parameterInfo.Name,
allowNulls
@@ -105,4 +106,4 @@ namespace Volo.Abp.Validation
);
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ObjectValidator.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ObjectValidator.cs
index d8e0c60b65..8e13d72938 100644
--- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ObjectValidator.cs
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ObjectValidator.cs
@@ -2,6 +2,7 @@ using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
+using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
@@ -18,9 +19,9 @@ namespace Volo.Abp.Validation
Options = options.Value;
}
- public virtual void Validate(object validatingObject, string name = null, bool allowNull = false)
+ public virtual async Task ValidateAsync(object validatingObject, string name = null, bool allowNull = false)
{
- var errors = GetErrors(validatingObject, name, allowNull);
+ var errors = await GetErrorsAsync(validatingObject, name, allowNull);
if (errors.Any())
{
@@ -31,7 +32,7 @@ namespace Volo.Abp.Validation
}
}
- public virtual List GetErrors(object validatingObject, string name = null, bool allowNull = false)
+ public virtual async Task> GetErrorsAsync(object validatingObject, string name = null, bool allowNull = false)
{
if (validatingObject == null)
{
@@ -58,7 +59,7 @@ namespace Volo.Abp.Validation
{
var contributor = (IObjectValidationContributor)
scope.ServiceProvider.GetRequiredService(contributorType);
- contributor.AddErrors(context);
+ await contributor.AddErrorsAsync(context);
}
}
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationInterceptor.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationInterceptor.cs
index b4ce642471..0a0f4fcf5f 100644
--- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationInterceptor.cs
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationInterceptor.cs
@@ -15,13 +15,13 @@ namespace Volo.Abp.Validation
public override async Task InterceptAsync(IAbpMethodInvocation invocation)
{
- Validate(invocation);
+ await ValidateAsync(invocation);
await invocation.ProceedAsync();
}
- protected virtual void Validate(IAbpMethodInvocation invocation)
+ protected virtual async Task ValidateAsync(IAbpMethodInvocation invocation)
{
- _methodInvocationValidator.Validate(
+ await _methodInvocationValidator.ValidateAsync(
new MethodInvocationValidationContext(
invocation.TargetObject,
invocation.Method,
diff --git a/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/IDynamicFileManager.cs b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/IDynamicFileProvider.cs
similarity index 100%
rename from framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/IDynamicFileManager.cs
rename to framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/IDynamicFileProvider.cs
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/LocalizationTestController.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/LocalizationTestController.cs
index 1defcf4809..ff26083a83 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/LocalizationTestController.cs
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/LocalizationTestController.cs
@@ -21,12 +21,20 @@ namespace Volo.Abp.AspNetCore.App
public class PersonModel
{
- //[Display(Name = nameof(BirthDate))]
public string BirthDate { get; set; }
+ public string BirthDate1 { get; set; }
+
+ public string BirthDate2 { get; set; }
+
+ public string BirthDate3 { get; set; }
+
public PersonModel()
{
BirthDate = DateTime.Now.ToString("yyyy-MM-dd");
+ BirthDate1 = BirthDate;
+ BirthDate2 = BirthDate;
+ BirthDate3 = BirthDate;
}
}
}
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/Views/LocalizationTest/PersonForm.cshtml b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/Views/LocalizationTest/PersonForm.cshtml
index 7f0a0d470f..31dee8bf83 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/Views/LocalizationTest/PersonForm.cshtml
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/Views/LocalizationTest/PersonForm.cshtml
@@ -5,4 +5,13 @@
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs
index 0fe6fb7cd9..3c186e3fea 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs
@@ -88,6 +88,7 @@ namespace Volo.Abp.AspNetCore.Mvc
options.Languages.Add(new LanguageInfo("en", "en", "English"));
options.Languages.Add(new LanguageInfo("hu", "hu", "Magyar"));
+ options.Languages.Add(new LanguageInfo("ro-RO", "ro-RO", "Română"));
options.Languages.Add(new LanguageInfo("sk", "sk", "Slovak"));
options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe"));
});
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs
index 7743e575ed..c9183d41d7 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs
@@ -16,11 +16,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ContentFormatters
{
var memoryStream = new MemoryStream();
await memoryStream.WriteAsync(Encoding.UTF8.GetBytes("DownloadAsync"));
-
- return new RemoteStreamContent(memoryStream, "download.rtf")
- {
- ContentType = "application/rtf"
- };
+ memoryStream.Position = 0;
+ return new RemoteStreamContent(memoryStream, "download.rtf", "application/rtf");
}
[HttpPost]
@@ -32,5 +29,15 @@ namespace Volo.Abp.AspNetCore.Mvc.ContentFormatters
return await reader.ReadToEndAsync() + ":" + file.ContentType + ":" + file.FileName;
}
}
+
+ [HttpPost]
+ [Route("Upload-Raw")]
+ public async Task UploadRawAsync(IRemoteStreamContent file)
+ {
+ using (var reader = new StreamReader(file.GetStream()))
+ {
+ return await reader.ReadToEndAsync() + ":" + file.ContentType;
+ }
+ }
}
}
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs
index 8f42a5cb37..14d755e1b2 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs
@@ -30,13 +30,32 @@ namespace Volo.Abp.AspNetCore.Mvc.ContentFormatters
var streamContent = new StreamContent(memoryStream);
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/rtf");
-
- requestMessage.Content = new MultipartFormDataContent {{streamContent, "file", "upload.rtf"}};
+ requestMessage.Content = new MultipartFormDataContent {{ streamContent, "file", "upload.rtf" }};
var response = await Client.SendAsync(requestMessage);
(await response.Content.ReadAsStringAsync()).ShouldBe("UploadAsync:application/rtf:upload.rtf");
}
}
+
+ [Fact]
+ public async Task UploadRawAsync()
+ {
+ using (var requestMessage = new HttpRequestMessage(HttpMethod.Post, "/api/remote-stream-content-test/upload-raw"))
+ {
+ var memoryStream = new MemoryStream();
+ var text = @"{ ""hello"": ""world"" }";
+ await memoryStream.WriteAsync(Encoding.UTF8.GetBytes(text));
+ memoryStream.Position = 0;
+
+ var streamContent = new StreamContent(memoryStream);
+ streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
+
+ requestMessage.Content = streamContent;
+
+ var response = await Client.SendAsync(requestMessage);
+ (await response.Content.ReadAsStringAsync()).ShouldBe($"{text}:application/json");
+ }
+ }
}
}
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/MvcLocalization_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/MvcLocalization_Tests.cs
index 4d9a4f4624..fe7912951c 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/MvcLocalization_Tests.cs
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/MvcLocalization_Tests.cs
@@ -30,7 +30,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Localization
var result = await GetResponseAsStringAsync("/LocalizationTest/HelloJohn");
result.ShouldBe("Hello John.");
}
-
+
[Fact]
public async Task Should_Localize_Display_Attribute()
{
@@ -38,12 +38,18 @@ namespace Volo.Abp.AspNetCore.Mvc.Localization
{
var result = await GetResponseAsStringAsync("/LocalizationTest/PersonForm");
result.ShouldContain("");
+ result.ShouldContain("");
+ result.ShouldContain("");
+ result.ShouldContain("");
}
using (CultureHelper.Use("tr"))
{
var result = await GetResponseAsStringAsync("/LocalizationTest/PersonForm");
result.ShouldContain("");
+ result.ShouldContain("");
+ result.ShouldContain("");
+ result.ShouldContain("");
}
}
}
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/en.json b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/en.json
index 2451c1b294..f11c5458db 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/en.json
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/en.json
@@ -1,7 +1,10 @@
{
"culture": "en",
"texts": {
+ "DisplayName:PersonModel:BirthDate1": "Birth date1",
+ "DisplayName:BirthDate2": "Birth date2",
+ "PersonModel:BirthDate3": "Birth date3",
"BirthDate": "Birth date",
- "Value1": "Value One"
+ "Value1": "Value One"
}
-}
\ No newline at end of file
+}
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/tr.json b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/tr.json
index 546e672ede..b99e81bec0 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/tr.json
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/tr.json
@@ -1,7 +1,10 @@
{
"culture": "tr",
"texts": {
+ "DisplayName:PersonModel:BirthDate1": "Dogum gunu1",
+ "DisplayName:BirthDate2": "Dogum gunu2",
+ "PersonModel:BirthDate3": "Dogum gunu3",
"BirthDate": "Dogum gunu",
- "Value1": "Değer Bir"
+ "Value1": "Değer Bir"
}
-}
\ No newline at end of file
+}
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/TestUnitOfWork.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/TestUnitOfWork.cs
index 3b9ec55e75..bf0d0c8781 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/TestUnitOfWork.cs
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/TestUnitOfWork.cs
@@ -13,8 +13,14 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow
{
private readonly TestUnitOfWorkConfig _config;
- public TestUnitOfWork(IServiceProvider serviceProvider, IOptions options, TestUnitOfWorkConfig config)
- : base(serviceProvider, options)
+ public TestUnitOfWork(
+ IServiceProvider serviceProvider,
+ IUnitOfWorkEventPublisher unitOfWorkEventPublisher,
+ IOptions options, TestUnitOfWorkConfig config)
+ : base(
+ serviceProvider,
+ unitOfWorkEventPublisher,
+ options)
{
_config = config;
}
diff --git a/framework/test/Volo.Abp.BlobStoring.FileSystem.Tests/Volo/Abp/BlobStoring/FileSystem/AbpBlobStoringTestBase.cs b/framework/test/Volo.Abp.BlobStoring.FileSystem.Tests/Volo/Abp/BlobStoring/FileSystem/AbpBlobStoringFileSystemTestBase.cs
similarity index 100%
rename from framework/test/Volo.Abp.BlobStoring.FileSystem.Tests/Volo/Abp/BlobStoring/FileSystem/AbpBlobStoringTestBase.cs
rename to framework/test/Volo.Abp.BlobStoring.FileSystem.Tests/Volo/Abp/BlobStoring/FileSystem/AbpBlobStoringFileSystemTestBase.cs
diff --git a/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs b/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs
index a93eabda1d..6263d03ddd 100644
--- a/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs
+++ b/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs
@@ -39,7 +39,8 @@ namespace Volo.Abp.FluentValidation
},
MyMethodInput3 = new MyMethodInput3
{
- MyStringValue3 = "ccc"
+ MyStringValue3 = "ccc",
+ MyBoolValue3 = true
}
});
@@ -62,12 +63,13 @@ namespace Volo.Abp.FluentValidation
},
MyMethodInput3 = new MyMethodInput3
{
- MyStringValue3 = "c"
+ MyStringValue3 = "c",
+ MyBoolValue3 = false
}
}
)
);
-
+
exception.ValidationErrors.ShouldContain(x => x.MemberNames.Contains("MyStringValue"));
exception.ValidationErrors.ShouldContain(x => x.MemberNames.Contains("MyMethodInput2.MyStringValue2"));
exception.ValidationErrors.ShouldContain(x => x.MemberNames.Contains("MyMethodInput3.MyStringValue3"));
@@ -100,7 +102,7 @@ namespace Volo.Abp.FluentValidation
output.ShouldBe("444");
}
-
+
[DependsOn(typeof(AbpAutofacModule))]
[DependsOn(typeof(AbpFluentValidationModule))]
public class TestModule : AbpModule
@@ -162,6 +164,8 @@ namespace Volo.Abp.FluentValidation
{
public string MyStringValue3 { get; set; }
+
+ public bool MyBoolValue3 { get; set; }
}
public class MyMethodInput4
@@ -175,7 +179,8 @@ namespace Volo.Abp.FluentValidation
{
RuleFor(x => x.MyStringValue).Equal("aaa");
RuleFor(x => x.MyMethodInput2.MyStringValue2).Equal("bbb");
- RuleFor(customer => customer.MyMethodInput3).SetValidator(new MyMethodInput3Validator());
+ RuleFor(x => x.MyMethodInput3).SetValidator(new MyMethodInput3Validator());
+ RuleFor(x => x.MyMethodInput3).SetValidator(new MyMethodInput3AsyncValidator());
}
}
@@ -194,5 +199,15 @@ namespace Volo.Abp.FluentValidation
RuleFor(x => x.MyStringValue3).Equal("ccc");
}
}
+
+ public class MyMethodInput3AsyncValidator : MethodInputBaseValidator
+ {
+ public MyMethodInput3AsyncValidator()
+ {
+ RuleFor(x => x.MyStringValue3).Equal("ccc");
+
+ RuleFor(x => x.MyBoolValue3).MustAsync((myBookValue3, cancellation) => Task.FromResult(myBookValue3));
+ }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs
index 23694e4e72..d1c1275db7 100644
--- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs
+++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading;
using System.Threading.Tasks;
namespace Volo.Abp.Http.DynamicProxying
@@ -36,5 +37,7 @@ namespace Volo.Abp.Http.DynamicProxying
Task PatchValueWithHeaderAndQueryStringAsync(string headerValue, string qsValue);
Task DeleteByIdAsync(int id);
+
+ Task AbortRequestAsync(CancellationToken cancellationToken = default);
}
}
diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs
index d92e1ad5d1..b040c3e3d4 100644
--- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs
+++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs
@@ -49,7 +49,7 @@ namespace Volo.Abp.Http.DynamicProxying
{
var people = await _peopleAppService.GetListAsync(new PagedAndSortedResultRequestDto());
people.TotalCount.ShouldBeGreaterThan(0);
- people.Items.Count.ShouldBe((int) people.TotalCount);
+ people.Items.Count.ShouldBe((int)people.TotalCount);
}
[Fact]
@@ -90,8 +90,7 @@ namespace Volo.Abp.Http.DynamicProxying
{
Name = uniquePersonName,
Age = 42
- }
- );
+ });
person.ShouldNotBeNull();
person.Id.ShouldNotBe(Guid.Empty);
@@ -110,8 +109,7 @@ namespace Volo.Abp.Http.DynamicProxying
var person = await _peopleAppService.CreateAsync(new PersonDto
{
Age = 42
- }
- );
+ });
});
}
@@ -195,10 +193,22 @@ namespace Volo.Abp.Http.DynamicProxying
var memoryStream = new MemoryStream();
await memoryStream.WriteAsync(Encoding.UTF8.GetBytes("UploadAsync"));
memoryStream.Position = 0;
- var result = await _peopleAppService.UploadAsync(new RemoteStreamContent(memoryStream, "upload.rtf")
- {
- ContentType = "application/rtf"
- });
+
+ var result = await _peopleAppService.UploadAsync(new RemoteStreamContent(memoryStream, "upload.rtf", "application/rtf"));
+ result.ShouldBe("UploadAsync:application/rtf:upload.rtf");
+ }
+
+ [Fact]
+ public async Task UploadPartialAsync()
+ {
+ var memoryStream = new MemoryStream();
+ var rawData = new byte[16];
+ var text = Encoding.UTF8.GetBytes("UploadAsync");
+ await memoryStream.WriteAsync(rawData);
+ await memoryStream.WriteAsync(text);
+ memoryStream.Position = rawData.Length;
+
+ var result = await _peopleAppService.UploadAsync(new RemoteStreamContent(memoryStream, "upload.rtf", "application/rtf"));
result.ShouldBe("UploadAsync:application/rtf:upload.rtf");
}
@@ -215,15 +225,8 @@ namespace Volo.Abp.Http.DynamicProxying
var result = await _peopleAppService.UploadMultipleAsync(new List()
{
- new RemoteStreamContent(memoryStream, "File1.rtf")
- {
- ContentType = "application/rtf"
- },
-
- new RemoteStreamContent(memoryStream2, "File2.rtf")
- {
- ContentType = "application/rtf2"
- }
+ new RemoteStreamContent(memoryStream, "File1.rtf", "application/rtf"),
+ new RemoteStreamContent(memoryStream2, "File2.rtf", "application/rtf2")
});
result.ShouldBe("File1:application/rtf:File1.rtfFile2:application/rtf2:File2.rtf");
}
@@ -237,10 +240,7 @@ namespace Volo.Abp.Http.DynamicProxying
var result = await _peopleAppService.CreateFileAsync(new CreateFileInput()
{
Name = "123.rtf",
- Content = new RemoteStreamContent(memoryStream, "create.rtf")
- {
- ContentType = "application/rtf"
- }
+ Content = new RemoteStreamContent(memoryStream, "create.rtf", "application/rtf")
});
result.ShouldBe("123.rtf:CreateFileAsync:application/rtf:create.rtf");
}
@@ -265,23 +265,13 @@ namespace Volo.Abp.Http.DynamicProxying
Name = "123.rtf",
Contents = new List()
{
- new RemoteStreamContent(memoryStream, "1-1.rtf")
- {
- ContentType = "application/rtf"
- },
-
- new RemoteStreamContent(memoryStream2, "1-2.rtf")
- {
- ContentType = "application/rtf2"
- }
+ new RemoteStreamContent(memoryStream, "1-1.rtf", "application/rtf"),
+ new RemoteStreamContent(memoryStream2, "1-2.rtf", "application/rtf2")
},
Inner = new CreateFileInput()
{
Name = "789.rtf",
- Content = new RemoteStreamContent(memoryStream3, "i-789.rtf")
- {
- ContentType = "application/rtf3"
- }
+ Content = new RemoteStreamContent(memoryStream3, "i-789.rtf", "application/rtf3")
}
});
result.ShouldBe("123.rtf:File1:application/rtf:1-1.rtf123.rtf:File2:application/rtf2:1-2.rtf789.rtf:File3:application/rtf3:i-789.rtf");
diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs
index e18c2f8f4a..782b839626 100644
--- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs
+++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
-using Volo.Abp.Application.Services;
using Volo.Abp.AspNetCore.Mvc;
-using Volo.Abp.UI;
namespace Volo.Abp.Http.DynamicProxying
{
@@ -129,6 +128,14 @@ namespace Volo.Abp.Http.DynamicProxying
{
return Task.FromResult(id + 1);
}
+
+ [HttpGet]
+ [Route("abort-request")]
+ public async Task AbortRequestAsync(CancellationToken cancellationToken = default)
+ {
+ await Task.Delay(100, cancellationToken);
+ return "AbortRequestAsync";
+ }
}
public class Car
diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs
index bd35016989..8df3e94b3c 100644
--- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs
+++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs
@@ -1,10 +1,10 @@
using System;
+using System.Net.Http;
+using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Localization;
using Shouldly;
using Volo.Abp.Http.Client;
-using Volo.Abp.Http.Localization;
using Volo.Abp.Localization;
using Xunit;
@@ -159,5 +159,17 @@ namespace Volo.Abp.Http.DynamicProxying
(await _controller.DeleteByIdAsync(42)).ShouldBe(43);
}
+ [Fact]
+ public async Task AbortRequestAsync()
+ {
+ var cts = new CancellationTokenSource();
+ cts.CancelAfter(10);
+
+ var result = await _controller.AbortRequestAsync(default);
+ result.ShouldBe("AbortRequestAsync");
+
+ var exception = await Assert.ThrowsAsync(async () => await _controller.AbortRequestAsync(cts.Token));
+ exception.InnerException.InnerException.Message.ShouldBe("The client aborted the request.");
+ }
}
}
diff --git a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/DomainEvents/DomainEvents_Tests.cs b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/DomainEvents/DomainEvents_Tests.cs
index 52af309369..eae88cab0a 100644
--- a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/DomainEvents/DomainEvents_Tests.cs
+++ b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/DomainEvents/DomainEvents_Tests.cs
@@ -1,9 +1,15 @@
-using Volo.Abp.TestApp.Testing;
+using System.Threading.Tasks;
+using Volo.Abp.TestApp.Testing;
+using Xunit;
namespace Volo.Abp.MemoryDb.DomainEvents
{
public class DomainEvents_Tests : DomainEvents_Tests
{
-
+ [Fact(Skip = "MemoryDB doesn't support transactions.")]
+ public override Task Should_Rollback_Uow_If_Event_Handler_Throws_Exception()
+ {
+ return base.Should_Rollback_Uow_If_Event_Handler_Throws_Exception();
+ }
}
}
\ No newline at end of file
diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs
index f3dfef2891..a3d8764423 100644
--- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs
+++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs
@@ -72,11 +72,9 @@ namespace Volo.Abp.TestApp.Application
{
var memoryStream = new MemoryStream();
await memoryStream.WriteAsync(Encoding.UTF8.GetBytes("DownloadAsync"));
+ memoryStream.Position = 0;
- return new RemoteStreamContent(memoryStream, "download.rtf")
- {
- ContentType = "application/rtf"
- };
+ return new RemoteStreamContent(memoryStream, "download.rtf", "application/rtf");
}
public async Task UploadAsync(IRemoteStreamContent streamContent)
diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs
index 3ca7eaf8e4..04d0dda3c4 100644
--- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs
+++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs
@@ -2,11 +2,13 @@
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
+using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Modularity;
using Volo.Abp.TestApp.Domain;
+using Volo.Abp.Uow;
using Xunit;
namespace Volo.Abp.TestApp.Testing
@@ -25,6 +27,113 @@ namespace Volo.Abp.TestApp.Testing
DistributedEventBus = GetRequiredService();
}
+ [Fact]
+ public virtual async Task Should_Publish_Events_In_Order()
+ {
+ bool testPersonCreateHandled = false;
+ bool douglesUpdateHandled = false;
+ bool douglesNameChangeHandled = false;
+ bool customEventHandled = false;
+ bool customEvent2Handled = false;
+
+ LocalEventBus.Subscribe>(data =>
+ {
+ data.Entity.Name.ShouldBe("TestPerson1");
+ testPersonCreateHandled = true;
+ douglesUpdateHandled.ShouldBeFalse();
+ douglesNameChangeHandled.ShouldBeFalse();
+ customEventHandled.ShouldBeFalse();
+ customEvent2Handled.ShouldBeFalse();
+ return Task.CompletedTask;
+ });
+
+ LocalEventBus.Subscribe(data =>
+ {
+ data.Value.ShouldBe("42");
+ customEventHandled = true;
+ testPersonCreateHandled.ShouldBeTrue();
+ douglesUpdateHandled.ShouldBeFalse();
+ douglesNameChangeHandled.ShouldBeFalse();
+ customEvent2Handled.ShouldBeFalse();
+ return Task.CompletedTask;
+ });
+
+ LocalEventBus.Subscribe(data =>
+ {
+ data.OldName.ShouldBe("Douglas");
+ data.Person.Name.ShouldBe("Douglas-Updated");
+ douglesNameChangeHandled = true;
+ testPersonCreateHandled.ShouldBeTrue();
+ customEventHandled.ShouldBeTrue();
+ douglesUpdateHandled.ShouldBeFalse();
+ customEvent2Handled.ShouldBeFalse();
+ return Task.CompletedTask;
+ });
+
+ LocalEventBus.Subscribe>(data =>
+ {
+ data.Entity.Name.ShouldBe("Douglas-Updated");
+ douglesUpdateHandled = true;
+ testPersonCreateHandled.ShouldBeTrue();
+ customEventHandled.ShouldBeTrue();
+ douglesNameChangeHandled.ShouldBeTrue();
+ customEvent2Handled.ShouldBeFalse();
+ return Task.CompletedTask;
+ });
+
+ LocalEventBus.Subscribe(data =>
+ {
+ data.Value.ShouldBe("44");
+ customEvent2Handled = true;
+ testPersonCreateHandled.ShouldBeTrue();
+ customEventHandled.ShouldBeTrue();
+ douglesUpdateHandled.ShouldBeTrue();
+ douglesNameChangeHandled.ShouldBeTrue();
+ return Task.CompletedTask;
+ });
+
+ await WithUnitOfWorkAsync(new AbpUnitOfWorkOptions{IsTransactional = true}, async () =>
+ {
+ await PersonRepository.InsertAsync(
+ new Person(Guid.NewGuid(), "TestPerson1", 42)
+ );
+
+ await LocalEventBus.PublishAsync(new MyCustomEventData { Value = "42" });
+
+ var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId);
+ douglas.ChangeName("Douglas-Updated");
+ await PersonRepository.UpdateAsync(douglas);
+
+ await LocalEventBus.PublishAsync(new MyCustomEventData2 { Value = "44" });
+ });
+ }
+
+ [Fact]
+ public virtual async Task Should_Rollback_Uow_If_Event_Handler_Throws_Exception()
+ {
+ (await PersonRepository.FindAsync(x => x.Name == "TestPerson1")).ShouldBeNull();
+
+ LocalEventBus.Subscribe>(data =>
+ {
+ data.Entity.Name.ShouldBe("TestPerson1");
+ throw new ApplicationException("Just to rollback the UOW");
+ });
+
+ var exception = await Assert.ThrowsAsync(async () =>
+ {
+ await WithUnitOfWorkAsync(new AbpUnitOfWorkOptions{IsTransactional = true}, async () =>
+ {
+ await PersonRepository.InsertAsync(
+ new Person(Guid.NewGuid(), "TestPerson1", 42)
+ );
+ });
+ });
+
+ exception.Message.ShouldBe("Just to rollback the UOW");
+
+ (await PersonRepository.FindAsync(x => x.Name == "TestPerson1")).ShouldBeNull();
+ }
+
[Fact]
public async Task Should_Trigger_Domain_Events_For_Aggregate_Root()
{
@@ -63,5 +172,15 @@ namespace Volo.Abp.TestApp.Testing
isLocalEventTriggered.ShouldBeTrue();
isDistributedEventTriggered.ShouldBeTrue();
}
+
+ private class MyCustomEventData
+ {
+ public string Value { get; set; }
+ }
+
+ private class MyCustomEventData2
+ {
+ public string Value { get; set; }
+ }
}
}
\ No newline at end of file
diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs
index cb16a46439..b87f23774a 100644
--- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs
+++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs
@@ -38,7 +38,9 @@ namespace Volo.Abp.TestApp.Testing
using (var uow = GetRequiredService().Begin())
{
+#pragma warning disable 618
LocalEventBus.Subscribe>(data =>
+#pragma warning restore 618
{
creatingEventTriggered.ShouldBeFalse();
createdEventTriggered.ShouldBeFalse();
@@ -88,12 +90,16 @@ namespace Volo.Abp.TestApp.Testing
[Fact]
public async Task Multiple_Update_Should_Result_With_Single_Updated_Event_In_The_Same_Uow()
{
- var personId = Guid.NewGuid();
- await PersonRepository.InsertAsync(new Person(personId, Guid.NewGuid().ToString("D"), 42));
-
+ var createEventCount = 0;
var updateEventCount = 0;
var updatedAge = 0;
+ DistributedEventBus.Subscribe>(eto =>
+ {
+ createEventCount++;
+ return Task.CompletedTask;
+ });
+
DistributedEventBus.Subscribe>(eto =>
{
updateEventCount++;
@@ -101,6 +107,9 @@ namespace Volo.Abp.TestApp.Testing
return Task.CompletedTask;
});
+ var personId = Guid.NewGuid();
+ await PersonRepository.InsertAsync(new Person(personId, Guid.NewGuid().ToString("D"), 42));
+
using (var uow = GetRequiredService().Begin())
{
var person = await PersonRepository.GetAsync(personId);
@@ -120,6 +129,7 @@ namespace Volo.Abp.TestApp.Testing
await uow.CompleteAsync();
}
+ createEventCount.ShouldBe(1);
updateEventCount.ShouldBe(1);
updatedAge.ShouldBe(45);
}
diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/TestAppTestBase.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/TestAppTestBase.cs
index f21cc7371b..0fdcd5a2ba 100644
--- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/TestAppTestBase.cs
+++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/TestAppTestBase.cs
@@ -31,7 +31,6 @@ namespace Volo.Abp.TestApp.Testing
using (var uow = uowManager.Begin(options))
{
await action();
-
await uow.CompleteAsync();
}
}
diff --git a/framework/test/Volo.Abp.Threading.Tests/Volo.Abp.Threading.Tests.csproj b/framework/test/Volo.Abp.Threading.Tests/Volo.Abp.Threading.Tests.csproj
new file mode 100644
index 0000000000..cbca0b1329
--- /dev/null
+++ b/framework/test/Volo.Abp.Threading.Tests/Volo.Abp.Threading.Tests.csproj
@@ -0,0 +1,16 @@
+
+
+
+
+
+ net5.0
+
+
+
+
+
+
+
+
+
+
diff --git a/framework/test/Volo.Abp.Threading.Tests/Volo/Abp/Threading/AbpThreadingTestModule.cs b/framework/test/Volo.Abp.Threading.Tests/Volo/Abp/Threading/AbpThreadingTestModule.cs
new file mode 100644
index 0000000000..de530512d3
--- /dev/null
+++ b/framework/test/Volo.Abp.Threading.Tests/Volo/Abp/Threading/AbpThreadingTestModule.cs
@@ -0,0 +1,15 @@
+using Volo.Abp.Modularity;
+
+namespace Volo.Abp.Threading
+{
+ [DependsOn(
+ typeof(AbpThreadingModule),
+ typeof(AbpTestBaseModule)
+ )]
+ public class AbpThreadingTestModule : AbpModule
+ {
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ }
+ }
+}
diff --git a/framework/test/Volo.Abp.Threading.Tests/Volo/Abp/Threading/NullCancellationTokenProvider_Tests.cs b/framework/test/Volo.Abp.Threading.Tests/Volo/Abp/Threading/NullCancellationTokenProvider_Tests.cs
new file mode 100644
index 0000000000..34c5988eb1
--- /dev/null
+++ b/framework/test/Volo.Abp.Threading.Tests/Volo/Abp/Threading/NullCancellationTokenProvider_Tests.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Shouldly;
+using Volo.Abp.Testing;
+using Xunit;
+
+namespace Volo.Abp.Threading
+{
+ public class NullCancellationTokenProvider_Tests : AbpIntegratedTest
+ {
+ private readonly ICancellationTokenProvider _cancellationTokenProvider;
+
+ public NullCancellationTokenProvider_Tests()
+ {
+ _cancellationTokenProvider = NullCancellationTokenProvider.Instance;
+ }
+
+ [Fact]
+ public void Should_Return_None_Token()
+ {
+ _cancellationTokenProvider.Token.ShouldBe(CancellationToken.None);
+ }
+
+ [Fact]
+ public void Should_Return_Specific_Token()
+ {
+ var cts = new CancellationTokenSource();
+
+ using (_cancellationTokenProvider.Use(cts.Token))
+ {
+ var newCancellationTokenProvider = NullCancellationTokenProvider.Instance;
+
+ newCancellationTokenProvider.Token.ShouldBe(cts.Token);
+ }
+
+ _cancellationTokenProvider.Token.ShouldBe(CancellationToken.None);
+ }
+
+ [Fact]
+ public void Should_Cancel_After_100_Milliseconds()
+ {
+ var cts = new CancellationTokenSource();
+ cts.CancelAfter(TimeSpan.FromMilliseconds(100));
+
+ using (_cancellationTokenProvider.Use(cts.Token))
+ {
+ var newCancellationTokenProvider = NullCancellationTokenProvider.Instance;
+ Should.Throw(() => LongTask(1000, newCancellationTokenProvider.Token));
+ }
+ }
+
+ private void LongTask(int loopCounter, CancellationToken cancellationToken = default)
+ {
+ for (var i = 0; i < loopCounter; i++)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ Thread.Sleep(10);
+ }
+ }
+ }
+}
diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ro-RO.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ro-RO.json
new file mode 100644
index 0000000000..909d09f211
--- /dev/null
+++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ro-RO.json
@@ -0,0 +1,67 @@
+{
+ "culture": "ro-RO",
+ "texts": {
+ "UserName": "Nume de utilizator",
+ "EmailAddress": "Adresa de email",
+ "UserNameOrEmailAddress": "Nume de utilizator sau adresa de email",
+ "Password": "Parola",
+ "RememberMe": "Ţine-mă minte",
+ "UseAnotherServiceToLogin": "Folisiţi alt serviciu pentru a vă autentifica",
+ "UserLockedOutMessage": "Contul a fost blocat din cauza incercărilor eşuate de autentificare. Vă rugăm să aşteptaţi şi să încercaţi din nou.",
+ "InvalidUserNameOrPassword": "Nume de utilizator sau parolă invalide!",
+ "LoginIsNotAllowed": "Nu vă este permis să vă autentificaţi! Trebuie să vă confirmaţi email-ul/numărul de telefon.",
+ "SelfRegistrationDisabledMessage": "Înregistrarea personală este dezactivată pentru această aplicaţie. Vă rugăm să contactaţi administratorul aplicaţiei pentru a înregistra un nou utilizator.",
+ "LocalLoginDisabledMessage": "Autentificarea locală este dezactivată pentru această aplicaţie.",
+ "Login": "Autentificare",
+ "Cancel": "Anulează",
+ "Register": "Înregistrare",
+ "AreYouANewUser": "Sunteţi un utilizator nou?",
+ "AlreadyRegistered": "Deja înregistrat?",
+ "InvalidLoginRequest": "Cerere de autentificare invalidă",
+ "ThereAreNoLoginSchemesConfiguredForThisClient": "Nu există scheme de autentificare configurate pentru acest client.",
+ "LogInUsingYourProviderAccount": "Autentificaţi-vă folosindu-vă contul {0}",
+ "DisplayName:CurrentPassword": "Parola curentă",
+ "DisplayName:NewPassword": "Parola nouă",
+ "DisplayName:NewPasswordConfirm": "Confirmă noua parolă",
+ "PasswordChangedMessage": "Parola dumneavoastră a fost schimbată cu succes.",
+ "DisplayName:UserName": "Nume de utilizator",
+ "DisplayName:Email": "Email",
+ "DisplayName:Name": "Nume",
+ "DisplayName:Surname": "Surname",
+ "DisplayName:Password": "Parolă",
+ "DisplayName:EmailAddress": "Adresa de email",
+ "DisplayName:PhoneNumber": "Număr de telefon",
+ "PersonalSettings": "Setări personale",
+ "PersonalSettingsSaved": "Setări personale salvate",
+ "PasswordChanged": "Parola schimbată",
+ "NewPasswordConfirmFailed": "Vă rugăm să confirmaţi noua parolă.",
+ "Manage": "Administrează",
+ "MyAccount": "Contul meu",
+ "DisplayName:Abp.Account.IsSelfRegistrationEnabled": "Este înregistrarea personală activată",
+ "Description:Abp.Account.IsSelfRegistrationEnabled": "Dacă un utilizator îşi poate înregistra contul singur(ă).",
+ "DisplayName:Abp.Account.EnableLocalLogin": "Autentificaţi-vă cu un cont local",
+ "Description:Abp.Account.EnableLocalLogin": "Indică dacă serverul va permite utilizatorilor să se autentifice cu un cont local.",
+ "LoggedOutTitle": "Deconectat",
+ "LoggedOutText": "V-aţi deconectat şi veţi fi redirectat(ă) curând.",
+ "ReturnToText": "Click aici pentru a vă întoarce la aplicaţie",
+ "OrLoginWith": "Sau autentificaţi-vă cu:",
+ "ForgotPassword": "Aţi uitat parola?",
+ "SendPasswordResetLink_Information": "Un link pentru resetarea parolei va fi trimis pe emailul dumneavoastră. Dacă nu primiţi un email în decurs de câteva minute, vă rugăm să reîncercaţi.",
+ "PasswordResetMailSentMessage": "Emailul de recuperare al contului a fost trimis la adresa dumneavoastră de email. Dacă nu vedeţi acest email în decurs de 15 minute, cautaţi-l în dosarul de junk/spam. Dacă îl găsiţi acolo, vă rugăm să îl marcaţi ca -Not Junk-/-Not Spam-. ",
+ "ResetPassword": "Resetaţi parola",
+ "ConfirmPassword": "Confirmaţi (repetaţi) parola",
+ "ResetPassword_Information": "Vă rugăm să vă introduceţi noua parola.",
+ "YourPasswordIsSuccessfullyReset": "Parola a fost resetată cu succes.",
+ "GoToTheApplication": "Navigaţi la aplicaţie",
+ "BackToLogin": "Înapoi la autentificare",
+ "ProfileTab:Password": "Schimbă parola",
+ "ProfileTab:PersonalInfo": "Date personale",
+ "ReturnToApplication": "Întoarceţi-vă la aplicaţie",
+ "Volo.Account:InvalidEmailAddress": "Nu a putut fi găsită adresa de email: {0}",
+ "PasswordReset": "Resetarea parolei",
+ "PasswordResetInfoInEmail": "Am primit o cerere de recuperare a contului! Dacă dumneavoastră aţi iniţiat această cerere, daţi click pe următorul link pentru a vă reseta parola.",
+ "ResetMyPassword": "Resetează-mi parola",
+ "AccessDenied": "Acces interzis!",
+ "AccessDeniedMessage": "Nu aveţi acces la această resursă."
+ }
+}
diff --git a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AccountAppService.cs b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AccountAppService.cs
index 05ff98b35b..5c6612d1cc 100644
--- a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AccountAppService.cs
+++ b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AccountAppService.cs
@@ -55,7 +55,7 @@ namespace Volo.Abp.Account
public virtual async Task SendPasswordResetCodeAsync(SendPasswordResetCodeDto input)
{
- var user = await GetUserByEmail(input.Email);
+ var user = await GetUserByEmailAsync(input.Email);
var resetToken = await UserManager.GeneratePasswordResetTokenAsync(user);
await AccountEmailer.SendPasswordResetLinkAsync(user, resetToken, input.AppName, input.ReturnUrl, input.ReturnUrlHash);
}
@@ -74,7 +74,7 @@ namespace Volo.Abp.Account
});
}
- protected virtual async Task GetUserByEmail(string email)
+ protected virtual async Task GetUserByEmailAsync(string email)
{
var user = await UserManager.FindByEmailAsync(email);
if (user == null)
diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/AccountProfilePersonalInfoManagementGroupViewComponent.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/AccountProfilePersonalInfoManagementGroupViewComponent.cs
index 512d646ff2..7b86f8f3fd 100644
--- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/AccountProfilePersonalInfoManagementGroupViewComponent.cs
+++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/AccountProfilePersonalInfoManagementGroupViewComponent.cs
@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.Domain.Entities;
using Volo.Abp.Identity;
using Volo.Abp.Validation;
@@ -28,7 +29,7 @@ namespace Volo.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.P
return View("~/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.cshtml", model);
}
- public class PersonalInfoModel
+ public class PersonalInfoModel : IHasConcurrencyStamp
{
[Required]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxUserNameLength))]
@@ -51,6 +52,9 @@ namespace Volo.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.P
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPhoneNumberLength))]
[Display(Name = "DisplayName:PhoneNumber")]
public string PhoneNumber { get; set; }
+
+ [HiddenInput]
+ public string ConcurrencyStamp { get; set; }
}
}
}
diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.cshtml b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.cshtml
index 33ca670b0c..ec65f49834 100644
--- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.cshtml
+++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.cshtml
@@ -19,6 +19,8 @@