diff --git a/Directory.Packages.props b/Directory.Packages.props index b9c94c0106..f5cf8871de 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -107,7 +107,6 @@ - diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json index aa16e3931c..ee660f72e4 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json @@ -592,6 +592,8 @@ "OrganizationId": "Organization Id", "RemoveAllWinnersConfirmationMessage": "Are you sure you want to remove all winners?", "AutoRenewals": "Auto Renewals", - "OrganizationHasCreditCard": "Organization has credit card. Please remove credit card first!" + "OrganizationHasCreditCard": "Organization has credit card. Please remove credit card first!", + "DisplayName:DontSendEmailForLicenseExpire": "Don't Send Email For License Expire", + "DontSendEmailForLicenseExpire": "Don't Send Email For License Expire" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json index f2f4bf8d41..29a4cf27d3 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json @@ -1131,6 +1131,7 @@ "NameOnCard": "Name on Card", "BillingDetails": "Billing Details", "ThereIsNoDeveloper": "There is no developer.", - "CardDetails": "Card Details" + "CardDetails": "Debit/Credit Card Details", + "NoActiveLicence": "You are not eligible for this action! You have no active license." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json index 963546d9a3..7151345ea9 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json @@ -255,6 +255,8 @@ "LatestArticles": "أحدث المقالات", "RaffleHeader": "مرحبًا عضو مجتمع برنامج الجسر الأكاديمي!", "RafflesInfo": "
هذه هي صفحة السحب المخصصة لإظهار تقديرنا لك لكونك عضوًا نشطًا في المجتمع. نحن نقوم بإجراء محادثات مجتمعية لبرنامج ABP ، ومؤتمر ABP .NET ، ونحضر أو نرعى الأحداث المتعلقة بـ .NET والتي نقدم فيها بعض الهدايا.

يمكنك متابعة هذه الصفحة لرؤية السحوبات القادمة أو حضورها أو الاطلاع على السحوبات السابقة التي قمنا بسحبها بما في ذلك الفائزين.

شكرا لكونك عضوا نشطا! نراكم في السحوبات القادمة.", - "RafflesInfoTitle": "سحوبات مجتمع ABP" + "RafflesInfoTitle": "سحوبات مجتمع ABP", + "MarkdownSupported": "Markdown أيد.", + "Preview": "معاينة" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/cs.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/cs.json index 418cf5aef1..252b0dcb2b 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/cs.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/cs.json @@ -255,6 +255,8 @@ "LatestArticles": "poslední články", "RaffleHeader": "Dobrý den, člen komunity ABP!", "RafflesInfo": "
Toto je stránka s losováním věnovaná tomu, abychom vám ukázali naše uznání za to, že jste aktivním členem komunity. Pořádáme ABP Community Talks , ABP .NET Conference , účastníme se nebo sponzorujeme akce související s .NET, ve kterých rozdáváme nějaké dárky.

Na této stránce můžete sledovat nadcházející tomboly, zúčastnit se jich nebo si prohlédnout předchozí tomboly, které losujeme, včetně výherců.

Děkujeme, že jste aktivním členem! Uvidíme se v nadcházejícím slosování.", - "RafflesInfoTitle": "Komunitní tomboly ABP" + "RafflesInfoTitle": "Komunitní tomboly ABP", + "MarkdownSupported": "Markdown podporováno.", + "Preview": "Náhled" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/de.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/de.json index 021c19b3ff..4326ff88ef 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/de.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/de.json @@ -255,6 +255,8 @@ "LatestArticles": "Neueste Artikel", "RaffleHeader": "Hallo ABP-Community-Mitglied!", "RafflesInfo": "
Auf dieser Verlosungsseite möchten wir Ihnen unsere Wertschätzung dafür zeigen, dass Sie ein aktives Community-Mitglied sind. Wir veranstalten ABP Community Talks und ABP .NET Conferences , nehmen an .NET-bezogenen Veranstaltungen teil oder sponsern diese, bei denen wir einige Geschenke verschenken.

Sie können dieser Seite folgen, um die bevorstehenden Verlosungen zu sehen, daran teilzunehmen oder frühere Verlosungen, die wir verlosen, einschließlich der Gewinner, anzusehen.

Vielen Dank, dass Sie ein aktives Mitglied sind! Wir sehen uns bei den kommenden Gewinnspielen.", - "RafflesInfoTitle": "ABP-Community- Verlosungen" + "RafflesInfoTitle": "ABP-Community- Verlosungen", + "MarkdownSupported": "Markdown unterstützt.", + "Preview": "Vorschau" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json index 0283b963bc..347b18ce4b 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json @@ -103,6 +103,8 @@ "Language": "Language", "CreatePostLanguageInfo": "Language of the post", "SeeMore": "See More", - "MemberNotPublishedPostYet": "This member hasn't published any posts yet." + "MemberNotPublishedPostYet": "This member hasn't published any posts yet.", + "MarkdownSupported": "Markdown supported.", + "Preview": "Preview" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json index fa10d9c408..b22fc19de8 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json @@ -256,6 +256,8 @@ "RaffleHeader": "Hello ABP Community Member!", "RafflesInfo": "
This is the raffle page dedicated to show our appreciation towards you for being an active Community Member. We do ABP Community Talks ,ABP .NET Conference, attend or sponsor to the .NET-related events in which we give away some gifts.

You can follow this page to see the upcoming raffles, attend them, or see previous raffles we draw including the winners.

Thank you for being an active member! See you in the upcoming raffles.", "RafflesInfoTitle": "ABP Community Raffles", - "ToLuckyWinner": "to 1 lucky winner" + "ToLuckyWinner": "to 1 lucky winner", + "MarkdownSupported": "Markdown supported.", + "Preview": "Preview" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/es.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/es.json index c4e178bbd9..c53b45ab81 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/es.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/es.json @@ -255,6 +255,8 @@ "LatestArticles": "últimos artículos", "RaffleHeader": "¡Hola miembro de la comunidad ABP!", "RafflesInfo": "
Esta es la página del sorteo dedicada a mostrarle nuestro agradecimiento por ser un miembro activo de la comunidad. Realizamos charlas comunitarias de ABP , conferencias ABP .NET , asistimos o patrocinamos eventos relacionados con .NET en los que regalamos algunos obsequios.

Puedes seguir esta página para ver los próximos sorteos, asistir a ellos o ver sorteos anteriores que sorteamos incluyendo a los ganadores.

¡Gracias por ser un miembro activo! Nos vemos en los próximos sorteos.", - "RafflesInfoTitle": "Rifas de la Comunidad ABP" + "RafflesInfoTitle": "Rifas de la Comunidad ABP", + "MarkdownSupported": "Markdown soportado.", + "Preview": "Avance" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json index ac509875d6..abd8cdd21f 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json @@ -255,6 +255,8 @@ "LatestArticles": "Viimeisimmät artikkelit", "RaffleHeader": "Hei ABP-yhteisön jäsen!", "RafflesInfo": "
Tämä on arvontasivu, joka on omistettu osoittamaan kiitollisuuttamme sinua kohtaan, että olet aktiivinen yhteisön jäsen. Teemme ABP Community Talksia , ABP .NET -konferenssia , osallistumme tai sponsoroimme .NET-tapahtumia, joissa annamme lahjoja.

Voit seurata tätä sivua nähdäksesi tulevat arvonnat, osallistua niihin tai nähdäksesi aiemmat arvonnamme, mukaan lukien voittajat.

Kiitos aktiivisesta jäsenyydestäsi! Nähdään tulevissa arvonnassa.", - "RafflesInfoTitle": "ABP-yhteisön arpajaiset" + "RafflesInfoTitle": "ABP-yhteisön arpajaiset", + "MarkdownSupported": "Markdown tuettu.", + "Preview": "Esikatselu" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fr.json index c98a48d93e..1f259aac6d 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fr.json @@ -255,6 +255,8 @@ "LatestArticles": "Derniers articles", "RaffleHeader": "Bonjour membre de la communauté ABP !", "RafflesInfo": "
Ceci est la page de tirage au sort dédiée à vous montrer notre gratitude pour votre participation active à la communauté. Nous organisons des discussions communautaires ABP , des conférences ABP .NET , assistons ou sponsorisons des événements liés à .NET au cours desquels nous offrons des cadeaux.

Vous pouvez suivre cette page pour voir les tirages au sort à venir, y assister ou voir les tirages au sort précédents que nous tirons, y compris les gagnants.

Merci d'être un membre actif ! Rendez-vous lors des prochains tirages au sort.", - "RafflesInfoTitle": "Tirages au sort communautaires ABP" + "RafflesInfoTitle": "Tirages au sort communautaires ABP", + "MarkdownSupported": "Markdown prise en charge.", + "Preview": "Aperçu" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hi.json index f3d300e8a2..b868260ae6 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hi.json @@ -255,6 +255,8 @@ "LatestArticles": "नवीनतम लेख", "RaffleHeader": "नमस्ते एबीपी समुदाय सदस्य!", "RafflesInfo": "
यह रैफ़ल पेज है जो एक सक्रिय समुदाय सदस्य होने के लिए आपके प्रति हमारी सराहना दिखाने के लिए समर्पित है। हम एबीपी सामुदायिक वार्ता , एबीपी .NET सम्मेलन करते हैं, .NET से संबंधित कार्यक्रमों में भाग लेते हैं या प्रायोजित करते हैं जिसमें हम कुछ उपहार देते हैं।

आप आगामी रैफ़ल देखने, उनमें भाग लेने, या विजेताओं सहित हमारे द्वारा निकाले गए पिछले रैफ़ल देखने के लिए इस पृष्ठ का अनुसरण कर सकते हैं।

सक्रिय सदस्य बनने के लिए धन्यवाद! आगामी रैफ़ल में मिलते हैं।", - "RafflesInfoTitle": "एबीपी कम्युनिटी रैफल्स" + "RafflesInfoTitle": "एबीपी कम्युनिटी रैफल्स", + "MarkdownSupported": "Markdown का समर्थन किया।", + "Preview": "पूर्व दर्शन" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hr.json index 5b3546a78b..eb3b66d9c8 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hr.json @@ -255,6 +255,8 @@ "LatestArticles": "Najnoviji članci", "RaffleHeader": "Pozdrav članu ABP zajednice!", "RafflesInfo": "
Ovo je stranica za nagradnu igru namijenjena da vam pokažemo našu zahvalnost što ste aktivni član zajednice. Vodimo razgovore o ABP zajednici , ABP .NET konferenciji , prisustvujemo ili sponzoriramo događaje vezane uz .NET na kojima dijelimo neke darove.

Možete pratiti ovu stranicu kako biste vidjeli nadolazeće nagradne igre, prisustvovali im ili vidjeli prethodne nagradne igre koje izvlačimo uključujući dobitnike.

Hvala vam što ste aktivan član! Vidimo se u nadolazećim nagradnim igrama.", - "RafflesInfoTitle": "Izvlačenje nagradne igre zajednice ABP" + "RafflesInfoTitle": "Izvlačenje nagradne igre zajednice ABP", + "MarkdownSupported": "Markdown podržan.", + "Preview": "Pregled" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hu.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hu.json index 1f74f9e7a9..08917573ff 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hu.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hu.json @@ -255,6 +255,8 @@ "LatestArticles": "Legfrissebb cikkek", "RaffleHeader": "Kedves ABP közösségi tag!", "RafflesInfo": "
Ez az a sorsolási oldal, amelynek célja, hogy kifejezzük hálánkat feléd, amiért aktív közösségi tag vagy. Az ABP Community Talks-okat , az ABP .NET konferenciákat szervezzük, részt veszünk vagy szponzorálunk olyan .NET-hez kapcsolódó eseményeket, amelyeken ajándékokat adunk.

Ezt az oldalt követheti, hogy megtekinthesse a közelgő sorsolásokat, részt vegyen azokon, vagy megtekinthesse korábbi sorsolásainkat, beleértve a nyerteseket is.

Köszönjük, hogy aktív tag vagy! Találkozunk a sorsoláson.", - "RafflesInfoTitle": "ABP közösségi tombola" + "RafflesInfoTitle": "ABP közösségi tombola", + "MarkdownSupported": "Markdown támogatott.", + "Preview": "Előnézet" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/is.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/is.json index a991c387d4..0d8eb6cb48 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/is.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/is.json @@ -255,6 +255,8 @@ "LatestArticles": "Nýjustu greinar", "RaffleHeader": "Halló ABP samfélagsmeðlimur!", "RafflesInfo": "
Þetta er happdrættisíðan sem er tileinkuð þér að þakka þér fyrir að vera virkur samfélagsmeðlimur. Við gerum ABP Community Talks , ABP .NET ráðstefnu , sækjum eða styrkjum .NET tengda viðburði þar sem við gefum nokkrar gjafir.

Þú getur fylgst með þessari síðu til að sjá komandi happdrætti, mæta á þær eða sjá fyrri happdrætti sem við drögum út, þar á meðal vinningshafa.

Þakka þér fyrir að vera virkur meðlimur! Sjáumst í komandi happdrætti.", - "RafflesInfoTitle": "ABP samfélagshappdrætti" + "RafflesInfoTitle": "ABP samfélagshappdrætti", + "MarkdownSupported": "Markdown stutt.", + "Preview": "Forskoðun" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/it.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/it.json index 901c356c9a..a301a7f482 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/it.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/it.json @@ -255,6 +255,8 @@ "LatestArticles": "Articoli Recenti", "RaffleHeader": "Ciao membro della comunità ABP!", "RafflesInfo": "
Questa è la pagina della lotteria dedicata a mostrare il nostro apprezzamento nei tuoi confronti per essere un membro attivo della comunità. Organizziamo ABP Community Talks , ABP .NET Conference , partecipiamo o sponsorizziamo eventi relativi a .NET in cui regaliamo alcuni regali.

Puoi seguire questa pagina per vedere le prossime lotterie, parteciparvi o vedere le lotterie precedenti che estraiamo, compresi i vincitori.

Grazie per essere un membro attivo! Ci vediamo alle prossime lotterie.", - "RafflesInfoTitle": "Lotterie comunitarie ABP" + "RafflesInfoTitle": "Lotterie comunitarie ABP", + "MarkdownSupported": "Markdown supportato.", + "Preview": "Anteprima" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/nl.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/nl.json index 4ee8e44a09..45b3024c96 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/nl.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/nl.json @@ -255,6 +255,8 @@ "LatestArticles": "Laatste artikels", "RaffleHeader": "Hallo ABP Community-lid!", "RafflesInfo": "
Dit is de loterijpagina die bedoeld is om onze waardering voor u te tonen omdat u een actief lid van de community bent. We houden ABP Community Talks , ABP .NET Conference , wonen of sponsoren de .NET-gerelateerde evenementen bij waarin we een aantal geschenken weggeven.

U kunt deze pagina volgen om de komende loterijen te zien, deze bij te wonen of eerdere loterijen te zien die we trekken, inclusief de winnaars.

Bedankt dat u een actief lid bent! Tot ziens bij de komende loterijen.", - "RafflesInfoTitle": "ABP- gemeenschaploterijen" + "RafflesInfoTitle": "ABP- gemeenschaploterijen", + "MarkdownSupported": "Markdown ondersteund.", + "Preview": "Voorbeeld" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pl-PL.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pl-PL.json index 2df6780f03..124f910ac0 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pl-PL.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pl-PL.json @@ -255,6 +255,8 @@ "LatestArticles": "ostatnie artykuły", "RaffleHeader": "Witaj, członku społeczności ABP!", "RafflesInfo": "
To jest strona loterii, której celem jest wyrażenie naszego uznania dla Ciebie za bycie aktywnym członkiem społeczności. Prowadzimy rozmowy społecznościowe ABP , konferencje ABP .NET , uczestniczymy lub sponsorujemy wydarzenia związane z .NET, podczas których rozdajemy prezenty.

Możesz śledzić tę stronę, aby zobaczyć nadchodzące loterie, wziąć w nich udział lub zobaczyć poprzednie loterie, które losowaliśmy, w tym zwycięzców.

Dziękujemy za bycie aktywnym członkiem! Do zobaczenia w nadchodzących loteriach.", - "RafflesInfoTitle": "Loterie społecznościowe ABP" + "RafflesInfoTitle": "Loterie społecznościowe ABP", + "MarkdownSupported": "Markdown utrzymany.", + "Preview": "Zapowiedź" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pt-BR.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pt-BR.json index 9f2ce433d9..419ef77140 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pt-BR.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pt-BR.json @@ -255,6 +255,8 @@ "LatestArticles": "Artigos Mais Recentes", "RaffleHeader": "Olá, membro da comunidade ABP!", "RafflesInfo": "
Esta é a página do sorteio dedicada a mostrar nosso agradecimento por você ser um membro ativo da comunidade. Fazemos ABP Community Talks , ABP .NET Conference , participamos ou patrocinamos eventos relacionados ao .NET nos quais distribuímos alguns presentes.

Você pode seguir esta página para ver os próximos sorteios, participar deles ou ver os sorteios anteriores que sorteamos, incluindo os vencedores.

Obrigado por ser um membro ativo! Nos vemos nos próximos sorteios.", - "RafflesInfoTitle": "Sorteios da Comunidade ABP" + "RafflesInfoTitle": "Sorteios da Comunidade ABP", + "MarkdownSupported": "Markdown suportado.", + "Preview": "Visualização" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json index c2862d1fd7..47e513f125 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json @@ -255,6 +255,8 @@ "LatestArticles": "ultimele articole", "RaffleHeader": "Bună ziua, membru al comunității ABP!", "RafflesInfo": "
Aceasta este pagina de tombolă dedicată pentru a arăta aprecierea noastră față de dvs. pentru că sunteți un membru activ al comunității. Facem ABP Community Talks , ABP .NET Conference , participăm sau sponsorizăm evenimentele legate de .NET în care oferim câteva cadouri.

Puteți urmări această pagină pentru a vedea tombolele viitoare, a participa la ele sau pentru a vedea tombolele anterioare pe care le extragem, inclusiv câștigătorii.

Vă mulțumim că sunteți un membru activ! Ne vedem la tombolele viitoare.", - "RafflesInfoTitle": "Tombole comunitare ABP" + "RafflesInfoTitle": "Tombole comunitare ABP", + "MarkdownSupported": "Markdown sprijinit.", + "Preview": "previzualizare" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ru.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ru.json index 27f2b1203a..b91893ce94 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ru.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ru.json @@ -258,6 +258,8 @@ "LatestArticles": "Последние статьи", "RaffleHeader": "Привет, участник сообщества ABP!", "RafflesInfo": "
Эта страница розыгрыша посвящена тому, чтобы выразить нашу признательность вам за то, что вы являетесь активным членом сообщества. Обсуждения сообщества ABP ,Конференция ABP .NET, посещать или спонсировать мероприятия, связанные с .NET, на которых мы раздаем подарки.

Вы можете подписаться на эту страницу, чтобы увидеть предстоящие розыгрыши, посетить их или просмотреть предыдущие розыгрыши, которые мы проводим, включая победителей.

Спасибо за активное участие! ", - "RafflesInfoTitle": "Сообщество АБП Розыгрыши" + "RafflesInfoTitle": "Сообщество АБП Розыгрыши", + "MarkdownSupported": "Markdown поддерживается.", + "Preview": "Предварительный просмотр" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sk.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sk.json index 6ab3c9d074..25a73a6bd7 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sk.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sk.json @@ -255,6 +255,8 @@ "LatestArticles": "Najnovšie články", "RaffleHeader": "Dobrý deň, člen komunity ABP!", "RafflesInfo": "
Toto je stránka žrebovania venovaná na vyjadrenie nášho uznania vám za to, že ste aktívnym členom komunity. Robíme ABP Community Talks , ABP .NET konferenciu , zúčastňujeme sa alebo sponzorujeme podujatia súvisiace s .NET, na ktorých rozdávame nejaké darčeky.

Na tejto stránke si môžete pozrieť pripravované tomboly, zúčastniť sa ich alebo si pozrieť predchádzajúce žrebovanie, ktoré vyžrebujeme vrátane výhercov.

Ďakujeme, že ste aktívnym členom! Vidíme sa v najbližšom žrebovaní.", - "RafflesInfoTitle": "Komunitné tomboly ABP" + "RafflesInfoTitle": "Komunitné tomboly ABP", + "MarkdownSupported": "Markdown podporované.", + "Preview": "Náhľad" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sl.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sl.json index 23763c6f78..b6192142c6 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sl.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sl.json @@ -255,6 +255,8 @@ "LatestArticles": "Najnovejši članki", "RaffleHeader": "Pozdravljeni član skupnosti ABP!", "RafflesInfo": "
To je stran za nagradno igro, namenjena izkazovanju naše hvaležnosti do vas, ker ste aktivni član skupnosti. Izvajamo ABP Community Talks , ABP .NET Conference , se udeležujemo ali sponzoriramo dogodke, povezane z .NET, na katerih podarimo nekaj daril.

To stran lahko spremljate in si ogledate prihajajoče nagradne igre, se jih udeležite ali si ogledate prejšnje nagradne igre, ki smo jih izžrebali, vključno z zmagovalci.

Hvala, ker ste aktivni član! Se vidimo na prihajajočih nagradnih igrah.", - "RafflesInfoTitle": "Žrebanje skupnosti ABP" + "RafflesInfoTitle": "Žrebanje skupnosti ABP", + "MarkdownSupported": "Markdown podprt.", + "Preview": "Predogled" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json index 2d52d01ed2..88c88208e8 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json @@ -189,6 +189,8 @@ "Layout_MetaDescription": "ABP Topluluğu, insanların ABP çerçevesi hakkında paylaşımlarda bulunabileceği ve projeleri takip edebileceği bir ortamdır.", "Index_Page_CommunityIntroduction": "Burası ABP Çerçevesi, .NET ve yazılım geliştirme için bir merkezdir. Makaleleri okuyabilir, eğitim videolarını izleyebilir, ABP'nin gelişim süreci ve ABP ile ilgili etkinlikler hakkında bilgi alabilir, diğer geliştiricilere yardımcı olabilir ve uzmanlığınızı ABP topluluğu ile paylaşabilirsiniz.", "IConsentToMedium": "Bu yazının https://medium.com/volosoft adresinde yayınlanmasına izin veriyorum.", - "DiscordPageTitle": "ABP Discord Topluluğu" + "DiscordPageTitle": "ABP Discord Topluluğu", + "MarkdownSupported": "Markdown destekleniyor.", + "Preview": "Ön izleme" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/vi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/vi.json index a36ec9b0e8..e195a80fa5 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/vi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/vi.json @@ -255,6 +255,8 @@ "LatestArticles": "Bài viết mới nhất", "RaffleHeader": "Xin chào Thành viên Cộng đồng ABP!", "RafflesInfo": "
Đây là trang xổ số dành riêng để thể hiện sự đánh giá cao của chúng tôi đối với bạn vì đã trở thành Thành viên cộng đồng tích cực. Chúng tôi tổ chức các buổi nói chuyện cộng đồng ABP , Hội nghị ABP .NET , tham dự hoặc tài trợ cho các sự kiện liên quan đến .NET mà trong đó chúng tôi tặng một số quà tặng.

Bạn có thể theo dõi trang này để xem các cuộc xổ số sắp tới, tham dự hoặc xem các cuộc xổ số trước đây mà chúng tôi rút ra bao gồm cả những người chiến thắng.

Cảm ơn bạn đã là thành viên tích cực! Hẹn gặp lại các bạn trong đợt xổ số sắp tới.", - "RafflesInfoTitle": "Xổ số cộng đồng ABP" + "RafflesInfoTitle": "Xổ số cộng đồng ABP", + "MarkdownSupported": "Markdown được hỗ trợ.", + "Preview": "Xem trước" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json index e899a94872..fd1130b894 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json @@ -255,6 +255,8 @@ "LatestArticles": "最新文章", "RaffleHeader": "你好,ABP 社区成员!", "RafflesInfo": "
这是一个抽奖页面,旨在感谢您成为活跃的社区成员。我们举办 ABP 社区讲座 、ABP .NET 会议,参加或赞助与 .NET 相关的活动,并在活动中赠送一些礼品。

您可以关注此页面,查看即将举行的抽奖活动、参加这些活动或查看我们以前举行的抽奖活动(包括获奖者)。

感谢您成为我们的活跃成员!在即将举行的抽奖活动中再见。", - "RafflesInfoTitle": "ABP 社区来抽奖来抽奖Markdown 支持的。", + "Preview": "预览" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hant.json index ebec42dd8a..e5725ce996 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hant.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hant.json @@ -255,6 +255,8 @@ "LatestArticles": "最新的文章", "RaffleHeader": "ABP 社群成員您好!", "RafflesInfo": "
這是抽獎頁面,旨在表達我們對您作為活躍社區成員的感謝。我們舉辦ABP 社群講座、ABP .NET 會議、參加或贊助 .NET 相關活動,並在活動中贈送一些禮物。

您可以關注此頁面查看即將舉行的抽獎活動、參加抽獎活動或查看我們之前抽獎的抽獎活動(包括獲獎者)。

感謝您成為活躍會員!在即將到來的抽獎活動中再見。", - "RafflesInfoTitle": "ABP 社區萊佛士" + "RafflesInfoTitle": "ABP 社區萊佛士", + "MarkdownSupported": "Markdown 支持的。", + "Preview": "预览" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json index d1bc23b308..ec2d301a29 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json @@ -353,6 +353,8 @@ "BuildSolutionsWithAbp": "Build maintainable .NET solutions by following software development best practices using ABP.", "BuyOnAmazon": "Buy on Amazon", "BuyOnPackt": "Buy on Packt", + "BuyOnDangDang": "Buy on DangDang", + "BuyOnJD": "Buy on JD", "Discounted": "Discounted", "MasteringAbpFramework_Book_KeyFeatures": "Key Features", "MasteringAbpFramework_Book_Key_Features_Description_1": "Build robust, maintainable, modular, and scalable software solutions using ABP Framework.", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json index 9fb6a08b32..88d56a6303 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json @@ -353,6 +353,8 @@ "BuildSolutionsWithAbp": "使用 ABP,遵循软件开发最佳实践,构建可维护的 .NET 解决方案。", "BuyOnAmazon": "在亚马逊上购买", "BuyOnPackt": "在 Packt 购买", + "BuyOnDangDang": "在当当网购买", + "BuyOnJD": "在京东上购买", "Discounted": "折扣", "MasteringAbpFramework_Book_KeyFeatures": "主要功能", "MasteringAbpFramework_Book_Key_Features_Description_1": "使用 ABP 框架构建稳健、可维护、模块化和可扩展的软件解决方案。", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json index 81664b5f8d..dc396ce8b9 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json @@ -353,6 +353,8 @@ "BuildSolutionsWithAbp": "使用 ABP 遵循軟體開發最佳實務來建立可維護的 .NET 解決方案。", "BuyOnAmazon": "在亞馬遜上購買", "BuyOnPackt": "在 Packt 上購買", + "BuyOnDangDang": "在當當上購買", + "BuyOnJD": "在京東上購買", "Discounted": "折扣", "MasteringAbpFramework_Book_KeyFeatures": "主要特徵", "MasteringAbpFramework_Book_Key_Features_Description_1": "使用 ABP 框架建構健壯、可維護、模組化和可擴展的軟體解決方案。", diff --git a/docs/en/Community-Articles/2024-01-04-CLI-Online-Translate/Post.md b/docs/en/Community-Articles/2024-01-04-CLI-Online-Translate/Post.md new file mode 100644 index 0000000000..285d7d5dc9 --- /dev/null +++ b/docs/en/Community-Articles/2024-01-04-CLI-Online-Translate/Post.md @@ -0,0 +1,72 @@ +# Use Deepl to translate localization files + +Translating localized text during the development of ABP modules is a boring job. For this reason, we have added the `translate` command to the CLI tool to translate the localization files, but it still requires manual translation of texts by the developer. + +Now, we introduce a new way to translate the target language, which is to use the [Deepl](https://www.deepl.com/translator) translation service to translate the target language. + +You can use the `translate --online` command in your module directory to translate the target language. + +For example, if you have added all `en` localization texts to your module, and you want to translate them to `zh-Hans`, you can run the following command: + +``` +abp translate -r en -c zh-Hans --online --deepl-auth-key your_auth_key +``` + +* `-r` parameter is used to specify the source language. It is usually a localized file that you have created. +* `-c` parameter is used to specify the target language. It is usually a language that you want to translate. +* `--online` parameter is used to indicate that the translation is performed from the Deepl service. +* `--deepl-auth-key` parameter is the API key of your Deepl account. You can get it from [here](https://support.deepl.com/hc/en-us/articles/360020695820-Authentication-Key). + + +The output of the above command is as follows: + +``` +ABP CLI 8.0.0 +Abp translate online... +Target culture: zh-Hans +Reference culture: en +Create translation: Settings => 设置 +Create translation: SuccessfullySaved => 成功保存 +Create translation: Permission:SettingManagement => 设置管理 +Create translation: Permission:Emailing => 发送电子邮件 +Create translation: Permission:EmailingTest => 电子邮件测试 +Create translation: Permission:TimeZone => 时区 +Create translation: SendTestEmail => 发送测试电子邮件 +Create translation: SenderEmailAddress => 发件人电子邮件地址 +Create translation: TargetEmailAddress => 目标电子邮件地址 +Create translation: Subject => 主题 +Create translation: Body => 正文 +Create translation: TestEmailSubject => 测试电子邮件 {0} +Create translation: TestEmailBody => 在此测试电子邮件正文信息 +Create translation: SuccessfullySent => 成功发送 +Create translation: Send => 发送 +Create translation: Menu:Emailing => 发送电子邮件 +Create translation: Menu:TimeZone => 时区 +Create translation: DisplayName:Timezone => 时区 +Create translation: TimezoneHelpText => 此设置用于应用程序范围或基于租户的设置。 +Create translation: SmtpHost => 主机 +Create translation: SmtpPort => 端口 +Create translation: SmtpUserName => 用户名 +Create translation: SmtpPassword => 密码 +Create translation: SmtpDomain => 域名 +Create translation: SmtpEnableSsl => 启用 ssl +Create translation: SmtpUseDefaultCredentials => 使用默认凭据 +Create translation: DefaultFromAddress => 默认地址 +Create translation: DefaultFromDisplayName => 显示名称的默认值 +Create translation: Feature:SettingManagementGroup => 设置管理 +Create translation: Feature:SettingManagementEnable => 启用设置管理 +Create translation: Feature:SettingManagementEnableDescription => 在应用程序中启用设置管理系统。 +Create translation: Feature:AllowChangingEmailSettings => 允许更改电子邮件设置。 +Create translation: Feature:AllowChangingEmailSettingsDescription => 允许更改电子邮件设置。 +Write translation json to setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/zh-Hans.json. +``` + +The generated `zh-Hans.json` as follow: + +![zh-Hans.json](deepl.jpg) + +In this example, It only translates one `en.json` to `zh-Hans.json`, but if there are multiple `en.json` files in the module, it will translate all `en.json` files to `zh-Hans.json`. + +Of course, the translation is not always correct, you can update the translation in the generated `zh-Hans.json` files. + +Enjoy it! diff --git a/docs/en/Community-Articles/2024-01-04-CLI-Online-Translate/deepl.jpg b/docs/en/Community-Articles/2024-01-04-CLI-Online-Translate/deepl.jpg new file mode 100644 index 0000000000..c54b9840f0 Binary files /dev/null and b/docs/en/Community-Articles/2024-01-04-CLI-Online-Translate/deepl.jpg differ diff --git a/docs/en/Migration-Guides/Abp-8_1.md b/docs/en/Migration-Guides/Abp-8_1.md new file mode 100644 index 0000000000..6f4c316d3f --- /dev/null +++ b/docs/en/Migration-Guides/Abp-8_1.md @@ -0,0 +1,85 @@ +# ABP Version 8.1 Migration Guide + +This document is a guide for upgrading ABP v8.0 solutions to ABP v8.1. There are some changes in this version that may affect your applications, please read it carefully and apply the necessary changes to your application. + +## Added `NormalizedName` property to `Tenant` + +The `Tenant` entity has a new property called `NormalizedName`. It is used to find/cache a tenant by its name in a case-insensitive way. +This property is automatically set when a tenant is created or updated. It gets the normalized name of the tenant name by `UpperInvariantTenantNormalizer(ITenantNormalizer)` service. You can implement this service to change the normalization logic. + +### `ITenantStore` + +The `ITenantStore` will use the `NormalizedName` parameter to get tenants, Please use the `ITenantNormalizer` to normalize the tenant name before calling the `ITenantStore` methods. + +### Update `NormalizedName` in `appsettings.json` + +If your tenants defined in the `appsettings.json` file, you should add the `NormalizedName` property to your tenants. + +````json +"Tenants": [ + { + "Id": "446a5211-3d72-4339-9adc-845151f8ada0", + "Name": "tenant1", + "NormalizedName": "TENANT1" // <-- Add this property + }, + { + "Id": "25388015-ef1c-4355-9c18-f6b6ddbaf89d", + "Name": "tenant2", + "NormalizedName": "TENANT2", // <-- Add this property + "ConnectionStrings": { + "Default": "...tenant2's db connection string here..." + } + } + ] +```` + +### Update `NormalizedName` in the database + +Please add a sql script to your migration to set the `NormalizedName` property of the existing tenants. You can use the following script: + +> This script is for the SQL Server database. You can change it for your database. + +> The table name `SaasTenants` is used for ABP commercial Saas module. `AbpTenants` is for the ABP open-source Tenant Management module. + +```sql +UPDATE SaasTenants SET NormalizedName = UPPER(Name) WHERE NormalizedName IS NULL OR NormalizedName = '' +``` + +```csharp +/// +public partial class Add_NormalizedName : Migration +{ + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "NormalizedName", + table: "SaasTenants", + type: "nvarchar(64)", + nullable: false, + defaultValue: ""); + + migrationBuilder.Sql("UPDATE SaasTenants SET NormalizedName = UPPER(Name) WHERE NormalizedName IS NULL OR NormalizedName = ''"); + + migrationBuilder.CreateIndex( + name: "IX_SaasTenants_NormalizedName", + table: "SaasTenants", + column: "NormalizedName"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_SaasTenants_NormalizedName", + table: "SaasTenants"); + + migrationBuilder.DropColumn( + name: "NormalizedName", + table: "SaasTenants"); + } +} +``` + +See https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/managing?tabs=dotnet-core-cli#adding-raw-sql to learn how to add raw SQL to migrations. + diff --git a/docs/en/Multi-Tenancy.md b/docs/en/Multi-Tenancy.md index 661d99da16..922976767d 100644 --- a/docs/en/Multi-Tenancy.md +++ b/docs/en/Multi-Tenancy.md @@ -394,6 +394,8 @@ app.UseMultiTenancy(); `ITenantStore` is used to get the tenant configuration from a data source. +> Tenant names are not case-sensitive. `ITenantStore` will use the `NormalizedName` parameter to get tenants, You need to use `ITenantNormalizer` to normalize tenant names. + #### Tenant Management Module The [tenant management module](Modules/Tenant-Management) is **included in the startup templates** and implements the `ITenantStore` interface to get the tenants and their configuration from a database. It also provides the necessary functionality and UI to manage the tenants and their connection strings. @@ -408,11 +410,13 @@ The [tenant management module](Modules/Tenant-Management) is **included in the s "Tenants": [ { "Id": "446a5211-3d72-4339-9adc-845151f8ada0", - "Name": "tenant1" + "Name": "tenant1", + "NormalizedName": "TENANT1" }, { "Id": "25388015-ef1c-4355-9c18-f6b6ddbaf89d", "Name": "tenant2", + "NormalizedName": "TENANT2", "ConnectionStrings": { "Default": "...tenant2's db connection string here..." } diff --git a/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiBlazorRemoteTenantStore.cs b/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiBlazorRemoteTenantStore.cs index d17a2b6f87..3873b48db3 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiBlazorRemoteTenantStore.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiBlazorRemoteTenantStore.cs @@ -23,13 +23,13 @@ public class MauiBlazorRemoteTenantStore : ITenantStore, ITransientDependency Cache = cache; } - public async Task FindAsync(string name) + public async Task FindAsync(string normalizedName) { - var cacheKey = CreateCacheKey(name); + var cacheKey = CreateCacheKey(normalizedName); var tenantConfiguration = await Cache.GetOrAddAsync( cacheKey, - async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(name))!, + async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(normalizedName))!, () => new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = @@ -57,13 +57,13 @@ public class MauiBlazorRemoteTenantStore : ITenantStore, ITransientDependency return tenantConfiguration; } - public TenantConfiguration? Find(string name) + public TenantConfiguration? Find(string normalizedName) { - var cacheKey = CreateCacheKey(name); + var cacheKey = CreateCacheKey(normalizedName); var tenantConfiguration = Cache.GetOrAdd( cacheKey, - () => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(name)))!, + () => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(normalizedName)))!, () => new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = @@ -98,16 +98,16 @@ public class MauiBlazorRemoteTenantStore : ITenantStore, ITransientDependency return null; } - return new TenantConfiguration(tenantResultDto.TenantId.Value, tenantResultDto.Name!); + return new TenantConfiguration(tenantResultDto.TenantId.Value, tenantResultDto.Name!, tenantResultDto.NormalizedName!); } - protected virtual string CreateCacheKey(string tenantName) + protected virtual string CreateCacheKey(string normalizedName) { - return $"RemoteTenantStore_Name_{tenantName}"; + return $"RemoteTenantStore_Name_{normalizedName}"; } protected virtual string CreateCacheKey(Guid tenantId) { return $"RemoteTenantStore_Id_{tenantId:N}"; } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs index 310add4bfc..520e2944f6 100644 --- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Middleware; using Volo.Abp.DependencyInjection; using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; @@ -15,7 +16,7 @@ using Volo.Abp.Settings; namespace Volo.Abp.AspNetCore.MultiTenancy; -public class MultiTenancyMiddleware : IMiddleware, ITransientDependency +public class MultiTenancyMiddleware : AbpMiddlewareBase, ITransientDependency { public ILogger Logger { get; set; } @@ -38,7 +39,7 @@ public class MultiTenancyMiddleware : IMiddleware, ITransientDependency _options = options.Value; } - public async Task InvokeAsync(HttpContext context, RequestDelegate next) + public async override Task InvokeAsync(HttpContext context, RequestDelegate next) { TenantConfiguration? tenant = null; try diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcRemoteTenantStore.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcRemoteTenantStore.cs index e0c450b8b4..1bc7856ca6 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcRemoteTenantStore.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcRemoteTenantStore.cs @@ -29,9 +29,9 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency Options = options.Value; } - public async Task FindAsync(string name) + public async Task FindAsync(string normalizedName) { - var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(name); + var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(normalizedName); var httpContext = HttpContextAccessor?.HttpContext; if (httpContext != null && httpContext.Items[cacheKey] is TenantConfigurationCacheItem tenantConfigurationInHttpContext) @@ -42,7 +42,7 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency var tenantConfiguration = await Cache.GetAsync(cacheKey); if (tenantConfiguration == null) { - await TenantAppService.FindTenantByNameAsync(name); + await TenantAppService.FindTenantByNameAsync(normalizedName); tenantConfiguration = await Cache.GetAsync(cacheKey); } @@ -79,9 +79,9 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency return tenantConfiguration?.Value; } - public TenantConfiguration? Find(string name) + public TenantConfiguration? Find(string normalizedName) { - var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(name); + var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(normalizedName); var httpContext = HttpContextAccessor?.HttpContext; if (httpContext != null && httpContext.Items[cacheKey] is TenantConfigurationCacheItem tenantConfigurationInHttpContext) @@ -92,7 +92,7 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency var tenantConfiguration = Cache.Get(cacheKey); if (tenantConfiguration == null) { - AsyncHelper.RunSync(async () => await TenantAppService.FindTenantByNameAsync(name)); + AsyncHelper.RunSync(async () => await TenantAppService.FindTenantByNameAsync(normalizedName)); tenantConfiguration = Cache.Get(cacheKey); } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/MultiTenancy/FindTenantResultDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/MultiTenancy/FindTenantResultDto.cs index 599b0b8a67..1de5f942dc 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/MultiTenancy/FindTenantResultDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/MultiTenancy/FindTenantResultDto.cs @@ -11,5 +11,7 @@ public class FindTenantResultDto public string? Name { get; set; } + public string? NormalizedName { get; set; } + public bool IsActive { get; set; } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalFooterTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalFooterTagHelperService.cs index 671b00e094..8b46f6e78c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalFooterTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalFooterTagHelperService.cs @@ -90,13 +90,13 @@ public class AbpModalFooterTagHelperService : AbpTagHelperService FindTenantByNameAsync(string name) { - var tenant = await TenantStore.FindAsync(name); + var tenant = await TenantStore.FindAsync(TenantNormalizer.NormalizeName(name)!); if (tenant == null) { @@ -29,6 +31,7 @@ public class AbpTenantAppService : ApplicationService, IAbpTenantAppService Success = true, TenantId = tenant.Id, Name = tenant.Name, + NormalizedName = tenant.NormalizedName, IsActive = tenant.IsActive }; } @@ -47,6 +50,7 @@ public class AbpTenantAppService : ApplicationService, IAbpTenantAppService Success = true, TenantId = tenant.Id, Name = tenant.Name, + NormalizedName = tenant.NormalizedName, IsActive = tenant.IsActive }; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml.cs index f6711be826..94a6760df3 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml.cs @@ -18,13 +18,16 @@ public class TenantSwitchModalModel : AbpPageModel public TenantInfoModel Input { get; set; } = default!; protected ITenantStore TenantStore { get; } + protected ITenantNormalizer TenantNormalizer { get; } protected AbpAspNetCoreMultiTenancyOptions Options { get; } public TenantSwitchModalModel( ITenantStore tenantStore, + ITenantNormalizer tenantNormalizer, IOptions options) { TenantStore = tenantStore; + TenantNormalizer = tenantNormalizer; Options = options.Value; LocalizationResourceType = typeof(AbpUiMultiTenancyResource); } @@ -45,7 +48,7 @@ public class TenantSwitchModalModel : AbpPageModel Guid? tenantId = null; if (!Input.Name.IsNullOrEmpty()) { - var tenant = await TenantStore.FindAsync(Input.Name!); + var tenant = await TenantStore.FindAsync(TenantNormalizer.NormalizeName(Input.Name!)!); if (tenant == null) { throw new UserFriendlyException(L["GivenTenantIsNotExist", Input.Name!]); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert2/abp-sweetalert2.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert2/abp-sweetalert2.js index 51c7db5cd9..4a11feeda2 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert2/abp-sweetalert2.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert2/abp-sweetalert2.js @@ -103,6 +103,13 @@ var abp = abp || {}; abp.libs.sweetAlert.config.default.confirmButtonText = l('Ok'); abp.libs.sweetAlert.config.default.denyButtonText = l('No'); abp.libs.sweetAlert.config.default.cancelButtonText = l('Cancel'); + abp.libs.sweetAlert.config.default.buttonsStyling = false; + abp.libs.sweetAlert.config.default.customClass = { + confirmButton: "btn btn-primary", + cancelButton: "btn btn-outline-primary mx-2", + denyButton: "btn btn-outline-primary mx-2" + }; + abp.libs.sweetAlert.config.confirm.title = l('AreYouSure'); abp.libs.sweetAlert.config.confirm.confirmButtonText = l('Yes'); abp.libs.sweetAlert.config.confirm.showCancelButton = true; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs index c9b5984843..a2f2c1c989 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs @@ -14,6 +14,7 @@ using System.Linq; using System.Net; using System.Reflection; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.DataAnnotations; using Microsoft.AspNetCore.Mvc.RazorPages; @@ -25,6 +26,7 @@ using Volo.Abp.ApiVersioning; using Volo.Abp.Application; using Volo.Abp.AspNetCore.Mvc.AntiForgery; using Volo.Abp.AspNetCore.Mvc.ApiExploring; +using Volo.Abp.AspNetCore.Mvc.ApplicationModels; using Volo.Abp.AspNetCore.Mvc.Conventions; using Volo.Abp.AspNetCore.Mvc.DataAnnotations; using Volo.Abp.AspNetCore.Mvc.DependencyInjection; @@ -176,6 +178,7 @@ public class AbpAspNetCoreMvcModule : AbpModule context.Services.Replace(ServiceDescriptor.Singleton()); context.Services.AddSingleton(); + context.Services.TryAddEnumerable(ServiceDescriptor.Transient()); context.Services.AddOptions() .Configure((mvcOptions, serviceProvider) => { @@ -247,7 +250,7 @@ public class AbpAspNetCoreMvcModule : AbpModule .Distinct(); AddToApplicationParts(partManager, controllerAssemblies); - + var additionalAssemblies = moduleContainer .Modules .SelectMany(m => m.GetAdditionalAssemblies()) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcActionDescriptorProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcActionDescriptorProvider.cs new file mode 100644 index 0000000000..1ae2180e47 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcActionDescriptorProvider.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.Controllers; +using Volo.Abp.AspNetCore.Filters; + +namespace Volo.Abp.AspNetCore.Mvc.ApplicationModels; + +public class AbpMvcActionDescriptorProvider : IActionDescriptorProvider +{ + public virtual int Order => -1000 + 10; + + public virtual void OnProvidersExecuting(ActionDescriptorProviderContext context) + { + } + + public virtual void OnProvidersExecuted(ActionDescriptorProviderContext context) + { + foreach (var action in context.Results.Where(x => x is ControllerActionDescriptor).Cast()) + { + var disableAbpFeaturesAttribute = action.ControllerTypeInfo.GetCustomAttribute(true); + if (disableAbpFeaturesAttribute != null && disableAbpFeaturesAttribute.DisableMvcFilters) + { + action.FilterDescriptors.RemoveAll(x => x.Filter is ServiceFilterAttribute serviceFilterAttribute && + typeof(IAbpFilter).IsAssignableFrom(serviceFilterAttribute.ServiceType)); + } + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs index 07101da0cb..d982adb12a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs @@ -5,12 +5,13 @@ using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Options; using Volo.Abp.Aspects; +using Volo.Abp.AspNetCore.Filters; using Volo.Abp.Auditing; using Volo.Abp.DependencyInjection; namespace Volo.Abp.AspNetCore.Mvc.Auditing; -public class AbpAuditActionFilter : IAsyncActionFilter, ITransientDependency +public class AbpAuditActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDependency { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs index 8445be60ae..6b97ac980a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs @@ -5,12 +5,13 @@ using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Options; using Volo.Abp.Aspects; +using Volo.Abp.AspNetCore.Filters; using Volo.Abp.Auditing; using Volo.Abp.DependencyInjection; namespace Volo.Abp.AspNetCore.Mvc.Auditing; -public class AbpAuditPageFilter : IAsyncPageFilter, ITransientDependency +public class AbpAuditPageFilter : IAsyncPageFilter, IAbpFilter, ITransientDependency { public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs index 61e37104ee..a63e557198 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.ExceptionHandling; +using Volo.Abp.AspNetCore.Filters; using Volo.Abp.Authorization; using Volo.Abp.DependencyInjection; using Volo.Abp.ExceptionHandling; @@ -18,7 +19,7 @@ using Volo.Abp.Json; namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling; -public class AbpExceptionFilter : IAsyncExceptionFilter, ITransientDependency +public class AbpExceptionFilter : IAsyncExceptionFilter, IAbpFilter, ITransientDependency { public virtual async Task OnExceptionAsync(ExceptionContext context) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs index 31784cb6ea..97c21268fe 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.ExceptionHandling; +using Volo.Abp.AspNetCore.Filters; using Volo.Abp.Authorization; using Volo.Abp.DependencyInjection; using Volo.Abp.ExceptionHandling; @@ -18,7 +19,7 @@ using Volo.Abp.Json; namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling; -public class AbpExceptionPageFilter : IAsyncPageFilter, ITransientDependency +public class AbpExceptionPageFilter : IAsyncPageFilter, IAbpFilter, ITransientDependency { public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeatureActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeatureActionFilter.cs index b4b70a5e1a..35bb9ba572 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeatureActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeatureActionFilter.cs @@ -2,12 +2,13 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Abstractions; using Volo.Abp.Aspects; +using Volo.Abp.AspNetCore.Filters; using Volo.Abp.DependencyInjection; using Volo.Abp.Features; namespace Volo.Abp.AspNetCore.Mvc.Features; -public class AbpFeatureActionFilter : IAsyncActionFilter, ITransientDependency +public class AbpFeatureActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDependency { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeaturePageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeaturePageFilter.cs index 3c586f762b..a35764c43c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeaturePageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeaturePageFilter.cs @@ -2,12 +2,13 @@ using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; using Volo.Abp.Aspects; +using Volo.Abp.AspNetCore.Filters; using Volo.Abp.DependencyInjection; using Volo.Abp.Features; namespace Volo.Abp.AspNetCore.Mvc.Features; -public class AbpFeaturePageFilter : IAsyncPageFilter, ITransientDependency +public class AbpFeaturePageFilter : IAsyncPageFilter, IAbpFilter, ITransientDependency { public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeatureActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeatureActionFilter.cs index aae85e4d25..34f125f228 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeatureActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeatureActionFilter.cs @@ -6,12 +6,13 @@ using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Aspects; +using Volo.Abp.AspNetCore.Filters; using Volo.Abp.DependencyInjection; using Volo.Abp.GlobalFeatures; namespace Volo.Abp.AspNetCore.Mvc.GlobalFeatures; -public class GlobalFeatureActionFilter : IAsyncActionFilter, ITransientDependency +public class GlobalFeatureActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDependency { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeaturePageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeaturePageFilter.cs index 46455730a4..3c43301221 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeaturePageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeaturePageFilter.cs @@ -6,12 +6,13 @@ using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Aspects; +using Volo.Abp.AspNetCore.Filters; using Volo.Abp.DependencyInjection; using Volo.Abp.GlobalFeatures; namespace Volo.Abp.AspNetCore.Mvc.GlobalFeatures; -public class GlobalFeaturePageFilter : IAsyncPageFilter, ITransientDependency +public class GlobalFeaturePageFilter : IAsyncPageFilter, IAbpFilter, ITransientDependency { public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Response/AbpNoContentActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Response/AbpNoContentActionFilter.cs index b0565cbc4d..455dd52f24 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Response/AbpNoContentActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Response/AbpNoContentActionFilter.cs @@ -2,11 +2,12 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; +using Volo.Abp.AspNetCore.Filters; using Volo.Abp.DependencyInjection; namespace Volo.Abp.AspNetCore.Mvc.Response; -public class AbpNoContentActionFilter : IAsyncActionFilter, ITransientDependency +public class AbpNoContentActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDependency { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs index 14032b52d5..4a6a04a554 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs @@ -4,12 +4,13 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Filters; using Volo.Abp.DependencyInjection; using Volo.Abp.Uow; namespace Volo.Abp.AspNetCore.Mvc.Uow; -public class AbpUowActionFilter : IAsyncActionFilter, ITransientDependency +public class AbpUowActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDependency { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs index 7cfc1f0492..f4a7be3333 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs @@ -4,13 +4,14 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Filters; using Volo.Abp.AspNetCore.Uow; using Volo.Abp.DependencyInjection; using Volo.Abp.Uow; namespace Volo.Abp.AspNetCore.Mvc.Uow; -public class AbpUowPageFilter : IAsyncPageFilter, ITransientDependency +public class AbpUowPageFilter : IAsyncPageFilter, IAbpFilter, ITransientDependency { public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/AbpValidationActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/AbpValidationActionFilter.cs index e88cee4eb6..f866c85585 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/AbpValidationActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/AbpValidationActionFilter.cs @@ -3,13 +3,14 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Filters; using Volo.Abp.DependencyInjection; using Volo.Abp.Reflection; using Volo.Abp.Validation; namespace Volo.Abp.AspNetCore.Mvc.Validation; -public class AbpValidationActionFilter : IAsyncActionFilter, ITransientDependency +public class AbpValidationActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDependency { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { diff --git a/framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpSerilogMiddleware.cs b/framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpSerilogMiddleware.cs index 1df327b742..52ee2e6b76 100644 --- a/framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpSerilogMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpSerilogMiddleware.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Options; using Serilog.Context; using Serilog.Core; using Serilog.Core.Enrichers; +using Volo.Abp.AspNetCore.Middleware; using Volo.Abp.Clients; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; @@ -13,7 +14,7 @@ using Volo.Abp.Users; namespace Volo.Abp.AspNetCore.Serilog; -public class AbpSerilogMiddleware : IMiddleware, ITransientDependency +public class AbpSerilogMiddleware : AbpMiddlewareBase, ITransientDependency { private readonly ICurrentClient _currentClient; private readonly ICurrentTenant _currentTenant; @@ -35,7 +36,7 @@ public class AbpSerilogMiddleware : IMiddleware, ITransientDependency _options = options.Value; } - public async Task InvokeAsync(HttpContext context, RequestDelegate next) + public async override Task InvokeAsync(HttpContext context, RequestDelegate next) { var enrichers = new List(); diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs index 6fd02a0470..cb531762ba 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs @@ -4,11 +4,12 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Localization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Middleware; using Volo.Abp.DependencyInjection; namespace Microsoft.AspNetCore.RequestLocalization; -public class AbpRequestLocalizationMiddleware : IMiddleware, ITransientDependency +public class AbpRequestLocalizationMiddleware : AbpMiddlewareBase, ITransientDependency { public const string HttpContextItemName = "__AbpSetCultureCookie"; @@ -23,7 +24,7 @@ public class AbpRequestLocalizationMiddleware : IMiddleware, ITransientDependenc _loggerFactory = loggerFactory; } - public async Task InvokeAsync(HttpContext context, RequestDelegate next) + public async override Task InvokeAsync(HttpContext context, RequestDelegate next) { var middleware = new RequestLocalizationMiddleware( next, diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAuditingMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAuditingMiddleware.cs index 0987a8fd8f..86cc997ae7 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAuditingMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAuditingMiddleware.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Middleware; using Volo.Abp.Auditing; using Volo.Abp.DependencyInjection; using Volo.Abp.Uow; @@ -11,7 +12,7 @@ using Volo.Abp.Users; namespace Volo.Abp.AspNetCore.Auditing; -public class AbpAuditingMiddleware : IMiddleware, ITransientDependency +public class AbpAuditingMiddleware : AbpMiddlewareBase, ITransientDependency { private readonly IAuditingManager _auditingManager; protected AbpAuditingOptions AuditingOptions { get; } @@ -34,9 +35,9 @@ public class AbpAuditingMiddleware : IMiddleware, ITransientDependency AspNetCoreAuditingOptions = aspNetCoreAuditingOptions.Value; } - public async Task InvokeAsync(HttpContext context, RequestDelegate next) + public async override Task InvokeAsync(HttpContext context, RequestDelegate next) { - if (!AuditingOptions.IsEnabled || IsIgnoredUrl(context)) + if (await ShouldSkipAsync(context, next) || !AuditingOptions.IsEnabled || IsIgnoredUrl(context)) { await next(context); return; diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs index b9d3b83068..7d5ef610e5 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Net.Http.Headers; +using Volo.Abp.AspNetCore.Middleware; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.Authorization; using Volo.Abp.DependencyInjection; @@ -14,7 +15,7 @@ using Volo.Abp.Json; namespace Volo.Abp.AspNetCore.ExceptionHandling; -public class AbpExceptionHandlingMiddleware : IMiddleware, ITransientDependency +public class AbpExceptionHandlingMiddleware : AbpMiddlewareBase, ITransientDependency { private readonly ILogger _logger; @@ -27,7 +28,7 @@ public class AbpExceptionHandlingMiddleware : IMiddleware, ITransientDependency _clearCacheHeadersDelegate = ClearCacheHeaders; } - public async Task InvokeAsync(HttpContext context, RequestDelegate next) + public async override Task InvokeAsync(HttpContext context, RequestDelegate next) { try { diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Filters/IAbpFilter.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Filters/IAbpFilter.cs new file mode 100644 index 0000000000..dbd55a8ed4 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Filters/IAbpFilter.cs @@ -0,0 +1,6 @@ +namespace Volo.Abp.AspNetCore.Filters; + +public interface IAbpFilter +{ + +} diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Middleware/AbpMiddlewareBase.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Middleware/AbpMiddlewareBase.cs new file mode 100644 index 0000000000..52c9990a4f --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Middleware/AbpMiddlewareBase.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Controllers; + +namespace Volo.Abp.AspNetCore.Middleware; + +public abstract class AbpMiddlewareBase : IMiddleware +{ + protected Task ShouldSkipAsync(HttpContext context, RequestDelegate next) + { + var endpoint = context.GetEndpoint(); + var controllerActionDescriptor = endpoint?.Metadata.GetMetadata(); + var disableAbpFeaturesAttribute = controllerActionDescriptor?.ControllerTypeInfo.GetCustomAttribute(); + return Task.FromResult(disableAbpFeaturesAttribute != null && disableAbpFeaturesAttribute.DisableMiddleware); + } + + public abstract Task InvokeAsync(HttpContext context, RequestDelegate next); +} diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersMiddleware.cs index ae2e3b173b..4542dd32e1 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersMiddleware.cs @@ -5,11 +5,12 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; +using Volo.Abp.AspNetCore.Middleware; using Volo.Abp.DependencyInjection; namespace Volo.Abp.AspNetCore.Security; -public class AbpSecurityHeadersMiddleware : IMiddleware, ITransientDependency +public class AbpSecurityHeadersMiddleware : AbpMiddlewareBase, ITransientDependency { public IOptions Options { get; set; } protected const string ScriptSrcKey = "script-src"; @@ -20,7 +21,7 @@ public class AbpSecurityHeadersMiddleware : IMiddleware, ITransientDependency Options = options; } - public async Task InvokeAsync(HttpContext context, RequestDelegate next) + public async override Task InvokeAsync(HttpContext context, RequestDelegate next) { /*X-Content-Type-Options header tells the browser to not try and “guess” what a mimetype of a resource might be, and to just take what mimetype the server has returned as fact.*/ AddHeader(context, "X-Content-Type-Options", "nosniff"); diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs index ab23bdb944..bb2bedf901 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs @@ -4,14 +4,15 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Middleware; using Volo.Abp.DependencyInjection; using Volo.Abp.Security.Claims; namespace Volo.Abp.AspNetCore.Security.Claims; -public class AbpClaimsMapMiddleware : IMiddleware, ITransientDependency +public class AbpClaimsMapMiddleware : AbpMiddlewareBase, ITransientDependency { - public async Task InvokeAsync(HttpContext context, RequestDelegate next) + public async override Task InvokeAsync(HttpContext context, RequestDelegate next) { var currentPrincipalAccessor = context.RequestServices .GetRequiredService(); diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpDynamicClaimsMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpDynamicClaimsMiddleware.cs index 777ca7744a..9c62fa8b25 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpDynamicClaimsMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpDynamicClaimsMiddleware.cs @@ -2,14 +2,15 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Middleware; using Volo.Abp.DependencyInjection; using Volo.Abp.Security.Claims; namespace Volo.Abp.AspNetCore.Security.Claims; -public class AbpDynamicClaimsMiddleware : IMiddleware, ITransientDependency +public class AbpDynamicClaimsMiddleware : AbpMiddlewareBase, ITransientDependency { - public async Task InvokeAsync(HttpContext context, RequestDelegate next) + public async override Task InvokeAsync(HttpContext context, RequestDelegate next) { if (context.User.Identity?.IsAuthenticated == true) { diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AbpCorrelationIdMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AbpCorrelationIdMiddleware.cs index a5f954c260..38356f8151 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AbpCorrelationIdMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AbpCorrelationIdMiddleware.cs @@ -3,12 +3,13 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Middleware; using Volo.Abp.DependencyInjection; using Volo.Abp.Tracing; namespace Volo.Abp.AspNetCore.Tracing; -public class AbpCorrelationIdMiddleware : IMiddleware, ITransientDependency +public class AbpCorrelationIdMiddleware : AbpMiddlewareBase, ITransientDependency { private readonly AbpCorrelationIdOptions _options; private readonly ICorrelationIdProvider _correlationIdProvider; @@ -20,7 +21,7 @@ public class AbpCorrelationIdMiddleware : IMiddleware, ITransientDependency _correlationIdProvider = correlationIdProvider; } - public async Task InvokeAsync(HttpContext context, RequestDelegate next) + public async override Task InvokeAsync(HttpContext context, RequestDelegate next) { var correlationId = GetCorrelationIdFromRequest(context); using (_correlationIdProvider.Change(correlationId)) diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs index 186501b4ac..013b3dad98 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs @@ -3,12 +3,13 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Middleware; using Volo.Abp.DependencyInjection; using Volo.Abp.Uow; namespace Volo.Abp.AspNetCore.Uow; -public class AbpUnitOfWorkMiddleware : IMiddleware, ITransientDependency +public class AbpUnitOfWorkMiddleware : AbpMiddlewareBase, ITransientDependency { private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly AbpAspNetCoreUnitOfWorkOptions _options; @@ -21,9 +22,9 @@ public class AbpUnitOfWorkMiddleware : IMiddleware, ITransientDependency _options = options.Value; } - public async Task InvokeAsync(HttpContext context, RequestDelegate next) + public async override Task InvokeAsync(HttpContext context, RequestDelegate next) { - if (IsIgnoredUrl(context)) + if (await ShouldSkipAsync(context, next) || IsIgnoredUrl(context)) { await next(context); return; diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/WebContentFileProvider.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/WebContentFileProvider.cs index ba9240d48b..fffc35792a 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/WebContentFileProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/WebContentFileProvider.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using JetBrains.Annotations; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Options; @@ -34,7 +33,10 @@ public class WebContentFileProvider : IWebContentFileProvider, ISingletonDepende public virtual IFileInfo GetFileInfo(string subpath) { - Check.NotNullOrEmpty(subpath, nameof(subpath)); + if (string.IsNullOrEmpty(subpath)) + { + return new NotFoundFileInfo(subpath); + } if (PathUtils.PathNavigatesAboveRoot(subpath)) { @@ -53,11 +55,9 @@ public class WebContentFileProvider : IWebContentFileProvider, ISingletonDepende return _fileProvider.GetFileInfo(_rootPath + subpath); } - public virtual IDirectoryContents GetDirectoryContents([NotNull] string subpath) + public virtual IDirectoryContents GetDirectoryContents(string subpath) { - Check.NotNullOrEmpty(subpath, nameof(subpath)); - - if (PathUtils.PathNavigatesAboveRoot(subpath)) + if (subpath == null || PathUtils.PathNavigatesAboveRoot(subpath)) { return NotFoundDirectoryContents.Singleton; } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProviderManager.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProviderManager.cs index 84d0ad0b2c..aebd14f36e 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProviderManager.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProviderManager.cs @@ -13,19 +13,31 @@ public class PermissionValueProviderManager : IPermissionValueProviderManager, I private readonly Lazy> _lazyProviders; protected AbpPermissionOptions Options { get; } + protected IServiceProvider ServiceProvider { get; } public PermissionValueProviderManager( IServiceProvider serviceProvider, IOptions options) { Options = options.Value; + ServiceProvider = serviceProvider; - _lazyProviders = new Lazy>( - () => Options - .ValueProviders - .Select(c => serviceProvider.GetRequiredService(c) as IPermissionValueProvider) - .ToList()!, - true - ); + _lazyProviders = new Lazy>(GetProviders, true); + } + + protected virtual List GetProviders() + { + var providers = Options + .ValueProviders + .Select(type => (ServiceProvider.GetRequiredService(type) as IPermissionValueProvider)!) + .ToList(); + + var multipleProviders = providers.GroupBy(p => p.Name).FirstOrDefault(x => x.Count() > 1); + if(multipleProviders != null) + { + throw new AbpException($"Duplicate permission value provider name detected: {multipleProviders.Key}. Providers:{Environment.NewLine}{multipleProviders.Select(p => p.GetType().FullName!).JoinAsString(Environment.NewLine)}"); + } + + return providers; } } diff --git a/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs b/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs index 043f824b1a..53216b03b9 100644 --- a/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs @@ -1,12 +1,15 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using Autofac.Core; using Autofac.Extras.DynamicProxy; using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; using Volo.Abp.Autofac; using Volo.Abp.Castle.DynamicProxy; using Volo.Abp.DependencyInjection; +using Volo.Abp.DynamicProxy; using Volo.Abp.Modularity; namespace Autofac.Builder; @@ -75,11 +78,15 @@ public static class AbpRegistrationBuilderExtensions if (serviceRegistredArgs.Interceptors.Any()) { - registrationBuilder = registrationBuilder.AddInterceptors( - registrationActionList, - serviceType, - serviceRegistredArgs.Interceptors - ); + var disableAbpFeaturesAttribute = serviceRegistredArgs.ImplementationType.GetCustomAttribute(true); + if (disableAbpFeaturesAttribute == null || !disableAbpFeaturesAttribute.DisableInterceptors) + { + registrationBuilder = registrationBuilder.AddInterceptors( + registrationActionList, + serviceType, + serviceRegistredArgs.Interceptors + ); + } } return registrationBuilder; diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/UiMessageAlert.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/UiMessageAlert.razor index 82fc576b7e..9951e616e2 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/UiMessageAlert.razor +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/UiMessageAlert.razor @@ -22,7 +22,7 @@ @if ( IsConfirmation ) { - - + + } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs index 1a5356a1be..9805f03752 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs @@ -144,7 +144,7 @@ public class FeatureManager : IFeatureManager, ISingletonDependency if (!providers.Any()) { - return; + throw new AbpException($"Unknown feature value provider: {providerName}"); } if (providers.Count > 1 && !forceToSet && value != null) diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml index ca38284046..a3a00a89c1 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml @@ -123,8 +123,8 @@ - @L["ResetToDefault"] - @L["Cancel"] + @L["Cancel"] + @L["ResetToDefault"] @L["Save"] } diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs index 831d021e38..fd4ea324ea 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs @@ -209,4 +209,15 @@ public class FeatureManager_Tests : FeatureManagementDomainTestBase (await _featureManager.GetOrNullAsync(TestFeatureDefinitionProvider.BackupCount, TenantFeatureValueProvider.ProviderName, TestEditionIds.TenantId.ToString())).ShouldBe("0"); } + + [Fact] + public async Task Set_Should_Throw_Exception_If_Provider_Not_Found() + { + var exception = await Assert.ThrowsAsync(async () => + { + await _featureManager.SetAsync(TestFeatureDefinitionProvider.EmailSupport, "true", "UndefinedProvider", "Test"); + }); + + exception.Message.ShouldBe("Unknown feature value provider: UndefinedProvider"); + } } diff --git a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleManagement.razor b/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleManagement.razor index b5b8b15d47..d65325abae 100644 --- a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleManagement.razor +++ b/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/RoleManagement.razor @@ -63,7 +63,7 @@ - + @@ -101,7 +101,7 @@ - + diff --git a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor b/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor index 57ab80dc5e..349da3d9da 100644 --- a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor +++ b/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor @@ -154,7 +154,7 @@ - + @@ -275,7 +275,7 @@ - + diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor index 8c1f5871db..88d023a906 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor @@ -81,7 +81,7 @@ } - + diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs index 1f771bdb3b..3f2e9c7565 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs @@ -134,6 +134,21 @@ public class PermissionManager_Tests : PermissionTestBase "Test", true); } + + [Fact] + public async Task Set_Should_Throw_Exception_If_Provider_Not_Found() + { + var exception = await Assert.ThrowsAsync(async () => + { + await _permissionManager.SetAsync( + "MyPermission1", + "UndefinedProvider", + "Test", + true); + }); + + exception.Message.ShouldBe("Unknown permission management provider: UndefinedProvider"); + } [Fact] public async Task UpdateProviderKey() diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor index e80115cfde..19f95ca52a 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor @@ -92,11 +92,11 @@ - @if (HasSendTestEmailPermission) { - + } + diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs index 5439c1213a..ddf451154d 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs @@ -125,7 +125,7 @@ public class SettingManager : ISettingManager, ISingletonDependency if (!providers.Any()) { - return; + throw new AbpException($"Unknown setting value provider: {providerName}"); } if (setting.IsEncrypted) diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Components/EmailSettingGroup/Default.cshtml b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Components/EmailSettingGroup/Default.cshtml index f653ec54a0..ee8db3e38f 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Components/EmailSettingGroup/Default.cshtml +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Components/EmailSettingGroup/Default.cshtml @@ -26,15 +26,15 @@
- - @L["Save"] - @if (await PermissionChecker.IsGrantedAsync(SettingManagementPermissions.EmailingTest)) { - + @L["SendTestEmail"] } + + @L["Save"] +
diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManager_Basic_Tests.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManager_Basic_Tests.cs index 44655c8cb0..ca9db64c70 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManager_Basic_Tests.cs +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManager_Basic_Tests.cs @@ -1,3 +1,4 @@ +using System; using System.Threading.Tasks; using Shouldly; using Volo.Abp.Settings; @@ -63,4 +64,15 @@ public class SettingManager_Basic_Tests : SettingsTestBase (await _settingManager.GetOrNullGlobalAsync("MySetting1")).ShouldBe("43"); (await _settingProvider.GetOrNullAsync("MySetting1")).ShouldBe("43"); } + + [Fact] + public async Task Set_Should_Throw_Exception_If_Provider_Not_Found() + { + var exception = await Assert.ThrowsAsync(async () => + { + await _settingManager.SetAsync("MySetting1", "43", "UndefinedProvider", "Test"); + }); + + exception.Message.ShouldBe("Unknown setting value provider: UndefinedProvider"); + } } \ No newline at end of file diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor index 04251a5003..478adfb0eb 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor @@ -85,7 +85,7 @@ - + @@ -119,7 +119,7 @@ - + diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantRepository.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantRepository.cs index 6412993d14..41ea978524 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantRepository.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantRepository.cs @@ -9,13 +9,13 @@ namespace Volo.Abp.TenantManagement; public interface ITenantRepository : IBasicRepository { Task FindByNameAsync( - string name, + string normalizedName, bool includeDetails = true, CancellationToken cancellationToken = default); [Obsolete("Use FindByNameAsync method.")] Tenant FindByName( - string name, + string normalizedName, bool includeDetails = true ); diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/Tenant.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/Tenant.cs index 5275e39ab3..c6c5c3edee 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/Tenant.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/Tenant.cs @@ -10,7 +10,9 @@ namespace Volo.Abp.TenantManagement; public class Tenant : FullAuditedAggregateRoot, IHasEntityVersion { public virtual string Name { get; protected set; } - + + public virtual string NormalizedName { get; protected set; } + public virtual int EntityVersion { get; protected set; } public virtual List ConnectionStrings { get; protected set; } @@ -20,10 +22,11 @@ public class Tenant : FullAuditedAggregateRoot, IHasEntityVersion } - protected internal Tenant(Guid id, [NotNull] string name) + protected internal Tenant(Guid id, [NotNull] string name, [CanBeNull] string normalizedName) : base(id) { SetName(name); + SetNormalizedName(normalizedName); ConnectionStrings = new List(); } @@ -78,4 +81,9 @@ public class Tenant : FullAuditedAggregateRoot, IHasEntityVersion { Name = Check.NotNullOrWhiteSpace(name, nameof(name), TenantConsts.MaxNameLength); } + + protected internal virtual void SetNormalizedName([CanBeNull] string normalizedName) + { + NormalizedName = normalizedName; + } } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantConfigurationCacheItemInvalidator.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantConfigurationCacheItemInvalidator.cs index e629186e20..09c1a9368f 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantConfigurationCacheItemInvalidator.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantConfigurationCacheItemInvalidator.cs @@ -22,21 +22,21 @@ public class TenantConfigurationCacheItemInvalidator : public virtual async Task HandleEventAsync(EntityChangedEventData eventData) { - await ClearCacheAsync(eventData.Entity.Id, eventData.Entity.Name); + await ClearCacheAsync(eventData.Entity.Id, eventData.Entity.NormalizedName); } public virtual async Task HandleEventAsync(EntityDeletedEventData eventData) { - await ClearCacheAsync(eventData.Entity.Id, eventData.Entity.Name); + await ClearCacheAsync(eventData.Entity.Id, eventData.Entity.NormalizedName); } - protected virtual async Task ClearCacheAsync(Guid? id, string name) + protected virtual async Task ClearCacheAsync(Guid? id, string normalizedName) { await Cache.RemoveManyAsync( new[] { TenantConfigurationCacheItem.CalculateCacheKey(id, null), - TenantConfigurationCacheItem.CalculateCacheKey(null, name), + TenantConfigurationCacheItem.CalculateCacheKey(null, normalizedName), }); } } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs index 1ad7324c35..648e02d381 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs @@ -10,20 +10,22 @@ public class TenantManager : DomainService, ITenantManager { protected ITenantRepository TenantRepository { get; } protected IDistributedCache Cache { get; } + protected ITenantNormalizer TenantNormalizer { get; } - public TenantManager(ITenantRepository tenantRepository, - IDistributedCache cache) + public TenantManager(ITenantRepository tenantRepository, IDistributedCache cache, ITenantNormalizer tenantNormalizer) { TenantRepository = tenantRepository; Cache = cache; + TenantNormalizer = tenantNormalizer; } public virtual async Task CreateAsync(string name) { Check.NotNull(name, nameof(name)); - await ValidateNameAsync(name); - return new Tenant(GuidGenerator.Create(), name); + var normalizedName = TenantNormalizer.NormalizeName(name); + await ValidateNameAsync(normalizedName); + return new Tenant(GuidGenerator.Create(), name, normalizedName); } public virtual async Task ChangeNameAsync(Tenant tenant, string name) @@ -31,17 +33,20 @@ public class TenantManager : DomainService, ITenantManager Check.NotNull(tenant, nameof(tenant)); Check.NotNull(name, nameof(name)); - await ValidateNameAsync(name, tenant.Id); - await Cache.RemoveAsync(TenantConfigurationCacheItem.CalculateCacheKey(tenant.Name)); + var normalizedName = TenantNormalizer.NormalizeName(name); + + await ValidateNameAsync(normalizedName, tenant.Id); + await Cache.RemoveAsync(TenantConfigurationCacheItem.CalculateCacheKey(tenant.NormalizedName)); tenant.SetName(name); + tenant.SetNormalizedName(normalizedName); } - protected virtual async Task ValidateNameAsync(string name, Guid? expectedId = null) + protected virtual async Task ValidateNameAsync(string normalizeName, Guid? expectedId = null) { - var tenant = await TenantRepository.FindByNameAsync(name); + var tenant = await TenantRepository.FindByNameAsync(normalizeName); if (tenant != null && tenant.Id != expectedId) { - throw new BusinessException("Volo.Abp.TenantManagement:DuplicateTenantName").WithData("Name", name); + throw new BusinessException("Volo.Abp.TenantManagement:DuplicateTenantName").WithData("Name", normalizeName); } } } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantStore.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantStore.cs index 5fd23add6b..d334c124a6 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantStore.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantStore.cs @@ -27,9 +27,9 @@ public class TenantStore : ITenantStore, ITransientDependency Cache = cache; } - public virtual async Task FindAsync(string name) + public virtual async Task FindAsync(string normalizedName) { - return (await GetCacheItemAsync(null, name)).Value; + return (await GetCacheItemAsync(null, normalizedName)).Value; } public virtual async Task FindAsync(Guid id) @@ -38,9 +38,9 @@ public class TenantStore : ITenantStore, ITransientDependency } [Obsolete("Use FindAsync method.")] - public virtual TenantConfiguration Find(string name) + public virtual TenantConfiguration Find(string normalizedName) { - return (GetCacheItem(null, name)).Value; + return (GetCacheItem(null, normalizedName)).Value; } [Obsolete("Use FindAsync method.")] @@ -49,9 +49,9 @@ public class TenantStore : ITenantStore, ITransientDependency return (GetCacheItem(id, null)).Value; } - protected virtual async Task GetCacheItemAsync(Guid? id, string name) + protected virtual async Task GetCacheItemAsync(Guid? id, string normalizedName) { - var cacheKey = CalculateCacheKey(id, name); + var cacheKey = CalculateCacheKey(id, normalizedName); var cacheItem = await Cache.GetAsync(cacheKey, considerUow: true); if (cacheItem != null) @@ -68,16 +68,16 @@ public class TenantStore : ITenantStore, ITransientDependency } } - if (!name.IsNullOrWhiteSpace()) + if (!normalizedName.IsNullOrWhiteSpace()) { using (CurrentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities! { - var tenant = await TenantRepository.FindByNameAsync(name); + var tenant = await TenantRepository.FindByNameAsync(normalizedName); return await SetCacheAsync(cacheKey, tenant); } } - throw new AbpException("Both id and name can't be invalid."); + throw new AbpException("Both id and normalizedName can't be invalid."); } protected virtual async Task SetCacheAsync(string cacheKey, [CanBeNull] Tenant tenant) @@ -89,9 +89,9 @@ public class TenantStore : ITenantStore, ITransientDependency } [Obsolete("Use GetCacheItemAsync method.")] - protected virtual TenantConfigurationCacheItem GetCacheItem(Guid? id, string name) + protected virtual TenantConfigurationCacheItem GetCacheItem(Guid? id, string normalizedName) { - var cacheKey = CalculateCacheKey(id, name); + var cacheKey = CalculateCacheKey(id, normalizedName); var cacheItem = Cache.Get(cacheKey, considerUow: true); if (cacheItem != null) @@ -108,16 +108,16 @@ public class TenantStore : ITenantStore, ITransientDependency } } - if (!name.IsNullOrWhiteSpace()) + if (!normalizedName.IsNullOrWhiteSpace()) { using (CurrentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities! { - var tenant = TenantRepository.FindByName(name); + var tenant = TenantRepository.FindByName(normalizedName); return SetCache(cacheKey, tenant); } } - throw new AbpException("Both id and name can't be invalid."); + throw new AbpException("Both id and normalizedName can't be invalid."); } [Obsolete("Use SetCacheAsync method.")] @@ -129,8 +129,8 @@ public class TenantStore : ITenantStore, ITransientDependency return cacheItem; } - protected virtual string CalculateCacheKey(Guid? id, string name) + protected virtual string CalculateCacheKey(Guid? id, string normalizedName) { - return TenantConfigurationCacheItem.CalculateCacheKey(id, name); + return TenantConfigurationCacheItem.CalculateCacheKey(id, normalizedName); } } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/AbpTenantManagementDbContextModelCreatingExtensions.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/AbpTenantManagementDbContextModelCreatingExtensions.cs index 6b1d7f7e8e..a91cf066e5 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/AbpTenantManagementDbContextModelCreatingExtensions.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/AbpTenantManagementDbContextModelCreatingExtensions.cs @@ -23,10 +23,12 @@ public static class AbpTenantManagementDbContextModelCreatingExtensions b.ConfigureByConvention(); b.Property(t => t.Name).IsRequired().HasMaxLength(TenantConsts.MaxNameLength); + b.Property(t => t.NormalizedName).IsRequired().HasMaxLength(TenantConsts.MaxNameLength); b.HasMany(u => u.ConnectionStrings).WithOne().HasForeignKey(uc => uc.TenantId).IsRequired(); b.HasIndex(u => u.Name); + b.HasIndex(u => u.NormalizedName); b.ApplyObjectExtensionMappings(); }); diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs index 34d350d242..e58512dc13 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs @@ -19,23 +19,23 @@ public class EfCoreTenantRepository : EfCoreRepository FindByNameAsync( - string name, + string normalizedName, bool includeDetails = true, CancellationToken cancellationToken = default) { return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .OrderBy(t => t.Id) - .FirstOrDefaultAsync(t => t.Name == name, GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(t => t.NormalizedName == normalizedName, GetCancellationToken(cancellationToken)); } [Obsolete("Use FindByNameAsync method.")] - public virtual Tenant FindByName(string name, bool includeDetails = true) + public virtual Tenant FindByName(string normalizedName, bool includeDetails = true) { return DbSet .IncludeDetails(includeDetails) .OrderBy(t => t.Id) - .FirstOrDefault(t => t.Name == name); + .FirstOrDefault(t => t.NormalizedName == normalizedName); } [Obsolete("Use FindAsync method.")] diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs index 321dcf365f..049dc5e57c 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs @@ -20,19 +20,19 @@ public class MongoTenantRepository : MongoDbRepository FindByNameAsync( - string name, + string normalizedName, bool includeDetails = true, CancellationToken cancellationToken = default) { return await (await GetMongoQueryableAsync(cancellationToken)) - .FirstOrDefaultAsync(t => t.Name == name, GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(t => t.NormalizedName == normalizedName, GetCancellationToken(cancellationToken)); } [Obsolete("Use FindByNameAsync method.")] - public virtual Tenant FindByName(string name, bool includeDetails = true) + public virtual Tenant FindByName(string normalizedName, bool includeDetails = true) { return GetMongoQueryable() - .FirstOrDefault(t => t.Name == name); + .FirstOrDefault(t => t.NormalizedName == normalizedName); } [Obsolete("Use FindAsync method.")] diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantCacheItemInvalidator_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantCacheItemInvalidator_Tests.cs index 9671402560..2dc844d71e 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantCacheItemInvalidator_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantCacheItemInvalidator_Tests.cs @@ -12,6 +12,7 @@ public class TenantConfigurationCacheItemInvalidator_Tests : AbpTenantManagement private readonly ITenantStore _tenantStore; private readonly ITenantRepository _tenantRepository; private readonly ITenantManager _tenantManager; + private readonly ITenantNormalizer _tenantNormalizer; public TenantConfigurationCacheItemInvalidator_Tests() { @@ -19,86 +20,87 @@ public class TenantConfigurationCacheItemInvalidator_Tests : AbpTenantManagement _tenantStore = GetRequiredService(); _tenantRepository = GetRequiredService(); _tenantManager = GetRequiredService(); + _tenantNormalizer = GetRequiredService(); } [Fact] public async Task Get_Tenant_Should_Cached() { - var acme = await _tenantRepository.FindByNameAsync("acme"); + var acme = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("acme")); acme.ShouldNotBeNull(); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldBeNull(); - (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.Name))).ShouldBeNull(); + (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.NormalizedName))).ShouldBeNull(); await _tenantStore.FindAsync(acme.Id); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldNotBeNull(); - await _tenantStore.FindAsync(acme.Name); - (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.Name))).ShouldNotBeNull(); + await _tenantStore.FindAsync(acme.NormalizedName); + (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.NormalizedName))).ShouldNotBeNull(); - var volosoft = _tenantRepository.FindByName("volosoft"); + var volosoft = _tenantRepository.FindByName(_tenantNormalizer.NormalizeName("volosoft")); volosoft.ShouldNotBeNull(); (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(volosoft.Id, null))).ShouldBeNull(); - (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.Name))).ShouldBeNull(); + (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.NormalizedName))).ShouldBeNull(); _tenantStore.Find(volosoft.Id); (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(volosoft.Id, null))).ShouldNotBeNull(); - _tenantStore.Find(volosoft.Name); - (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.Name))).ShouldNotBeNull(); + _tenantStore.Find(volosoft.NormalizedName); + (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.NormalizedName))).ShouldNotBeNull(); } [Fact] public async Task Cache_Should_Invalidator_When_Tenant_Changed() { - var acme = await _tenantRepository.FindByNameAsync("acme"); + var acme = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("acme")); acme.ShouldNotBeNull(); // FindAsync will cache tenant. await _tenantStore.FindAsync(acme.Id); - await _tenantStore.FindAsync(acme.Name); + await _tenantStore.FindAsync(acme.NormalizedName); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldNotBeNull(); - (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.Name))).ShouldNotBeNull(); + (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.NormalizedName))).ShouldNotBeNull(); await _tenantRepository.DeleteAsync(acme); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldBeNull(); - (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.Name))).ShouldBeNull(); + (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.NormalizedName))).ShouldBeNull(); - var volosoft = await _tenantRepository.FindByNameAsync("volosoft"); + var volosoft = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("volosoft")); volosoft.ShouldNotBeNull(); // Find will cache tenant. _tenantStore.Find(volosoft.Id); - _tenantStore.Find(volosoft.Name); + _tenantStore.Find(volosoft.NormalizedName); (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(volosoft.Id, null))).ShouldNotBeNull(); - (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.Name))).ShouldNotBeNull(); + (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.NormalizedName))).ShouldNotBeNull(); await _tenantRepository.DeleteAsync(volosoft); (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(volosoft.Id, null))).ShouldBeNull(); - (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.Name))).ShouldBeNull(); + (_cache.Get(TenantConfigurationCacheItem.CalculateCacheKey(null, volosoft.NormalizedName))).ShouldBeNull(); - var abp = await _tenantRepository.FindByNameAsync("abp"); + var abp = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("abp")); abp.ShouldNotBeNull(); // Find will cache tenant. await _tenantStore.FindAsync(abp.Id); - await _tenantStore.FindAsync(abp.Name); + await _tenantStore.FindAsync(abp.NormalizedName); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(abp.Id, null))).ShouldNotBeNull(); - (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, abp.Name))).ShouldNotBeNull(); + (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, abp.NormalizedName))).ShouldNotBeNull(); await _tenantManager.ChangeNameAsync(abp, "abp2"); await _tenantRepository.UpdateAsync(abp); (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(abp.Id, null))).ShouldBeNull(); - (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, "abp"))).ShouldBeNull(); - (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, "abp2"))).ShouldBeNull(); + (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, _tenantNormalizer.NormalizeName("abp")))).ShouldBeNull(); + (await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, _tenantNormalizer.NormalizeName("abp2")))).ShouldBeNull(); } } diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs index 161882e412..f46bcf8573 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Shouldly; +using Volo.Abp.MultiTenancy; using Xunit; namespace Volo.Abp.TenantManagement; @@ -8,19 +9,21 @@ public class TenantManager_Tests : AbpTenantManagementDomainTestBase { private readonly ITenantManager _tenantManager; private readonly ITenantRepository _tenantRepository; + private readonly ITenantNormalizer _tenantNormalizer; public TenantManager_Tests() { _tenantManager = GetRequiredService(); _tenantRepository = GetRequiredService(); + _tenantNormalizer = GetRequiredService(); } - [Fact] public async Task CreateAsync() { var tenant = await _tenantManager.CreateAsync("Test"); tenant.Name.ShouldBe("Test"); + tenant.NormalizedName.ShouldBe(_tenantNormalizer.NormalizeName("Test")); } [Fact] @@ -32,18 +35,20 @@ public class TenantManager_Tests : AbpTenantManagementDomainTestBase [Fact] public async Task ChangeNameAsync() { - var tenant = await _tenantRepository.FindByNameAsync("volosoft"); + var tenant = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("volosoft")); tenant.ShouldNotBeNull(); + tenant.NormalizedName.ShouldBe(_tenantNormalizer.NormalizeName("volosoft")); await _tenantManager.ChangeNameAsync(tenant, "newVolosoft"); tenant.Name.ShouldBe("newVolosoft"); + tenant.NormalizedName.ShouldBe(_tenantNormalizer.NormalizeName("newVolosoft")); } [Fact] public async Task ChangeName_Tenant_Name_Can_Not_Duplicate() { - var tenant = await _tenantRepository.FindByNameAsync("acme"); + var tenant = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("acme")); tenant.ShouldNotBeNull(); await Assert.ThrowsAsync(async () => await _tenantManager.ChangeNameAsync(tenant, "volosoft")); diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantStore_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantStore_Tests.cs index 1af4ebd1ea..10f203eb43 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantStore_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantStore_Tests.cs @@ -9,25 +9,28 @@ public class TenantStore_Tests : AbpTenantManagementDomainTestBase { private readonly ITenantStore _tenantStore; private readonly ITenantRepository _tenantRepository; + private readonly ITenantNormalizer _tenantNormalizer; public TenantStore_Tests() { _tenantStore = GetRequiredService(); _tenantRepository = GetRequiredService(); + _tenantNormalizer = GetRequiredService(); } [Fact] public async Task FindAsyncByName() { - var acme = await _tenantStore.FindAsync("acme"); + var acme = await _tenantStore.FindAsync(_tenantNormalizer.NormalizeName("acme")!); acme.ShouldNotBeNull(); acme.Name.ShouldBe("acme"); + acme.NormalizedName.ShouldBe(_tenantNormalizer.NormalizeName("acme")!); } [Fact] public async Task FindAsyncById() { - var acme = await _tenantRepository.FindByNameAsync("acme"); + var acme = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("acme")); acme.ShouldNotBeNull(); (await _tenantStore.FindAsync(acme.Id)).ShouldNotBeNull(); diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/Tenant_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/Tenant_Tests.cs index dbe631d431..bcefc527e6 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/Tenant_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/Tenant_Tests.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Shouldly; +using Volo.Abp.MultiTenancy; using Xunit; namespace Volo.Abp.TenantManagement; @@ -7,16 +8,18 @@ namespace Volo.Abp.TenantManagement; public class Tenant_Tests : AbpTenantManagementDomainTestBase { private readonly ITenantRepository _tenantRepository; + private readonly ITenantNormalizer _tenantNormalizer; public Tenant_Tests() { _tenantRepository = GetRequiredService(); + _tenantNormalizer = GetRequiredService(); } [Fact] public async Task FindDefaultConnectionString() { - var acme = await _tenantRepository.FindByNameAsync("acme"); + var acme = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("acme")); acme.ShouldNotBeNull(); acme.FindDefaultConnectionString().ShouldBe("DefaultConnString-Value"); @@ -25,7 +28,7 @@ public class Tenant_Tests : AbpTenantManagementDomainTestBase [Fact] public async Task FindConnectionString() { - var acme = await _tenantRepository.FindByNameAsync("acme"); + var acme = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("acme")); acme.ShouldNotBeNull(); acme.FindConnectionString(Data.ConnectionStrings.DefaultConnectionStringName).ShouldBe("DefaultConnString-Value"); diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/LazyLoad_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/LazyLoad_Tests.cs index 049d93cf65..9fe123d73b 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/LazyLoad_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/LazyLoad_Tests.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Shouldly; using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; using Xunit; @@ -11,10 +12,12 @@ public abstract class LazyLoad_Tests : TenantManagementTestBase< where TStartupModule : IAbpModule { public ITenantRepository TenantRepository { get; } + public ITenantNormalizer TenantNormalizer { get; } protected LazyLoad_Tests() { TenantRepository = GetRequiredService(); + TenantNormalizer = GetRequiredService(); } [Fact] @@ -22,7 +25,7 @@ public abstract class LazyLoad_Tests : TenantManagementTestBase< { using (var uow = GetRequiredService().Begin()) { - var role = await TenantRepository.FindByNameAsync("acme", includeDetails: false); + var role = await TenantRepository.FindByNameAsync(TenantNormalizer.NormalizeName("acme"), includeDetails: false); role.ConnectionStrings.ShouldNotBeNull(); role.ConnectionStrings.Any().ShouldBeTrue(); diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/TenantRepository_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/TenantRepository_Tests.cs index c8ff94d069..6e4c3c8db5 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/TenantRepository_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/TenantRepository_Tests.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using Shouldly; using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; using Xunit; namespace Volo.Abp.TenantManagement; @@ -11,22 +12,24 @@ public abstract class TenantRepository_Tests : TenantManagementT where TStartupModule : IAbpModule { public ITenantRepository TenantRepository { get; } + public ITenantNormalizer TenantNormalizer { get; } protected TenantRepository_Tests() { TenantRepository = GetRequiredService(); + TenantNormalizer = GetRequiredService(); } [Fact] public async Task FindByNameAsync() { - var tenant = await TenantRepository.FindByNameAsync("acme"); + var tenant = await TenantRepository.FindByNameAsync(TenantNormalizer.NormalizeName("acme")); tenant.ShouldNotBeNull(); - tenant = await TenantRepository.FindByNameAsync("undefined-tenant"); + tenant = await TenantRepository.FindByNameAsync(TenantNormalizer.NormalizeName("undefined-tenant")); tenant.ShouldBeNull(); - tenant = await TenantRepository.FindByNameAsync("acme", includeDetails: true); + tenant = await TenantRepository.FindByNameAsync(TenantNormalizer.NormalizeName("acme"), includeDetails: true); tenant.ShouldNotBeNull(); tenant.ConnectionStrings.Count.ShouldBeGreaterThanOrEqualTo(2); } @@ -34,7 +37,7 @@ public abstract class TenantRepository_Tests : TenantManagementT [Fact] public async Task FindAsync() { - var tenantId = (await TenantRepository.FindByNameAsync("acme")).Id; + var tenantId = (await TenantRepository.FindByNameAsync(TenantNormalizer.NormalizeName("acme"))).Id; var tenant = await TenantRepository.FindAsync(tenantId); tenant.ShouldNotBeNull(); @@ -51,14 +54,14 @@ public abstract class TenantRepository_Tests : TenantManagementT public async Task GetListAsync() { var tenants = await TenantRepository.GetListAsync(); - tenants.ShouldContain(t => t.Name == "acme"); - tenants.ShouldContain(t => t.Name == "volosoft"); + tenants.ShouldContain(t => t.Name == "acme" && t.NormalizedName == TenantNormalizer.NormalizeName("acme")); + tenants.ShouldContain(t => t.Name == "volosoft" && t.NormalizedName == TenantNormalizer.NormalizeName("volosoft")); } [Fact] public async Task Should_Eager_Load_Tenant_Collections() { - var role = await TenantRepository.FindByNameAsync("acme"); + var role = await TenantRepository.FindByNameAsync(TenantNormalizer.NormalizeName("acme")); role.ConnectionStrings.ShouldNotBeNull(); role.ConnectionStrings.Any().ShouldBeTrue(); } diff --git a/npm/ng-packs/packages/core/src/lib/services/list.service.ts b/npm/ng-packs/packages/core/src/lib/services/list.service.ts index 76dac87b5a..48996bade1 100644 --- a/npm/ng-packs/packages/core/src/lib/services/list.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/list.service.ts @@ -52,7 +52,7 @@ export class ListService implements return this._page; } - private _totalCount = 0 + private _totalCount = 0; set totalCount(value: number) { if (value === this._totalCount) return; @@ -150,7 +150,7 @@ export class ListService implements this._query$.next({ filter: this._filter || undefined, maxResultCount: this._maxResultCount, - skipCount: this._page * this._maxResultCount, + skipCount: this._filter ? 0 : this._page * this._maxResultCount, sorting: this._sortOrder ? `${this._sortKey} ${this._sortOrder}` : undefined, } as any as QueryParamsType); } diff --git a/npm/ng-packs/packages/oauth/src/lib/services/remember-me.service.ts b/npm/ng-packs/packages/oauth/src/lib/services/remember-me.service.ts new file mode 100644 index 0000000000..84d40d982a --- /dev/null +++ b/npm/ng-packs/packages/oauth/src/lib/services/remember-me.service.ts @@ -0,0 +1,27 @@ +import { AbpLocalStorageService } from '@abp/ng.core'; +import { Injectable, inject } from '@angular/core'; + +@Injectable({ + providedIn: 'root', +}) +export class RememberMeService { + readonly #rememberMe = 'remember_me'; + protected readonly localStorageService = inject(AbpLocalStorageService); + + set(remember: boolean) { + this.localStorageService.setItem(this.#rememberMe, JSON.stringify(remember)); + } + + remove() { + this.localStorageService.removeItem(this.#rememberMe); + } + + get() { + return Boolean(JSON.parse(this.localStorageService.getItem(this.#rememberMe))); + } + + getFromToken(accessToken: string) { + const parsedToken = JSON.parse(atob(accessToken.split('.')[1])); + return Boolean(parsedToken[this.#rememberMe]); + } +} diff --git a/npm/ng-packs/packages/oauth/src/lib/strategies/auth-code-flow-strategy.ts b/npm/ng-packs/packages/oauth/src/lib/strategies/auth-code-flow-strategy.ts index c9708d699e..7b1e0c108a 100644 --- a/npm/ng-packs/packages/oauth/src/lib/strategies/auth-code-flow-strategy.ts +++ b/npm/ng-packs/packages/oauth/src/lib/strategies/auth-code-flow-strategy.ts @@ -2,15 +2,36 @@ import { noop } from '@abp/ng.core'; import { Params } from '@angular/router'; import { from, of } from 'rxjs'; import { AuthFlowStrategy } from './auth-flow-strategy'; +import { isTokenExpired } from '../utils'; export class AuthCodeFlowStrategy extends AuthFlowStrategy { readonly isInternalAuth = false; async init() { + this.checkRememberMeOption(); + return super .init() .then(() => this.oAuthService.tryLogin().catch(noop)) - .then(() => this.oAuthService.setupAutomaticSilentRefresh({}, 'access_token')); + .then(() => this.oAuthService.setupAutomaticSilentRefresh()); + } + + private checkRememberMeOption() { + const accessToken = this.oAuthService.getAccessToken(); + const isTokenExpire = isTokenExpired(this.oAuthService.getAccessTokenExpiration()); + let rememberMe = this.rememberMeService.get(); + + if (accessToken && !rememberMe) { + const rememberMeValue = this.rememberMeService.getFromToken(accessToken); + + this.rememberMeService.set(!!rememberMeValue); + } + + rememberMe = this.rememberMeService.get(); + if (accessToken && isTokenExpire && !rememberMe) { + this.rememberMeService.remove(); + this.oAuthService.logOut(); + } } navigateToLogin(queryParams?: Params) { @@ -29,6 +50,7 @@ export class AuthCodeFlowStrategy extends AuthFlowStrategy { } logout(queryParams?: Params) { + this.rememberMeService.remove(); return from(this.oAuthService.revokeTokenAndLogout(this.getCultureParams(queryParams))); } diff --git a/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts b/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts index 256b4b38fa..1417fb7825 100644 --- a/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts +++ b/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts @@ -24,6 +24,8 @@ import { import { clearOAuthStorage } from '../utils/clear-o-auth-storage'; import { oAuthStorage } from '../utils/oauth-storage'; import { OAuthErrorFilterService } from '../services'; +import { isTokenExpired } from '../utils'; +import { RememberMeService } from '../services/remember-me.service'; export abstract class AuthFlowStrategy { abstract readonly isInternalAuth: boolean; @@ -35,6 +37,7 @@ export abstract class AuthFlowStrategy { protected oAuthConfig!: AuthConfig; protected sessionState: SessionStateService; protected localStorageService: AbpLocalStorageService; + protected rememberMeService: RememberMeService; protected tenantKey: string; protected router: Router; @@ -61,6 +64,7 @@ export abstract class AuthFlowStrategy { this.tenantKey = injector.get(TENANT_KEY); this.router = injector.get(Router); this.oAuthErrorFilterService = injector.get(OAuthErrorFilterService); + this.rememberMeService = injector.get(RememberMeService); this.listenToOauthErrors(); } @@ -70,23 +74,20 @@ export abstract class AuthFlowStrategy { const shouldClear = shouldStorageClear(this.oAuthConfig.clientId, oAuthStorage); if (shouldClear) clearOAuthStorage(oAuthStorage); } - this.oAuthService.configure(this.oAuthConfig); - this.oAuthService.events .pipe(filter(event => event.type === 'token_refresh_error')) .subscribe(() => this.navigateToLogin()); - this.navigateToPreviousUrl(); - return this.oAuthService .loadDiscoveryDocument() .then(() => { - if (this.oAuthService.hasValidAccessToken() || !this.oAuthService.getRefreshToken()) { - return Promise.resolve(); + const isTokenExpire = isTokenExpired(this.oAuthService.getAccessTokenExpiration()); + if (!isTokenExpire || this.oAuthService.getRefreshToken()) { + return this.refreshToken(); } - return this.refreshToken(); + return Promise.resolve(); }) .catch(this.catchError); } diff --git a/npm/ng-packs/packages/oauth/src/lib/strategies/auth-password-flow-strategy.ts b/npm/ng-packs/packages/oauth/src/lib/strategies/auth-password-flow-strategy.ts index 1958865e23..9c38c64e27 100644 --- a/npm/ng-packs/packages/oauth/src/lib/strategies/auth-password-flow-strategy.ts +++ b/npm/ng-packs/packages/oauth/src/lib/strategies/auth-password-flow-strategy.ts @@ -1,31 +1,23 @@ import { filter, switchMap, tap } from 'rxjs/operators'; import { OAuthInfoEvent } from 'angular-oauth2-oidc'; import { Params, Router } from '@angular/router'; -import { from, Observable, pipe } from 'rxjs'; +import { from, Observable } from 'rxjs'; import { HttpHeaders } from '@angular/common/http'; import { AuthFlowStrategy } from './auth-flow-strategy'; -import { pipeToLogin, removeRememberMe } from '../utils/auth-utils'; +import { isTokenExpired, pipeToLogin } from '../utils/auth-utils'; import { LoginParams } from '@abp/ng.core'; import { clearOAuthStorage } from '../utils/clear-o-auth-storage'; -function getCookieValueByName(name: string) { - const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)')); - return match ? match[2] : ''; -} - export class AuthPasswordFlowStrategy extends AuthFlowStrategy { readonly isInternalAuth = true; - private cookieKey = 'rememberMe'; - private storageKey = 'passwordFlow'; private listenToTokenExpiration() { this.oAuthService.events .pipe( filter( - event => - event instanceof OAuthInfoEvent && + event => event instanceof OAuthInfoEvent && event.type === 'token_expires' && - event.info === 'access_token', + event.info === 'access_token' ), ) .subscribe(() => { @@ -33,20 +25,28 @@ export class AuthPasswordFlowStrategy extends AuthFlowStrategy { this.refreshToken(); } else { this.oAuthService.logOut(); - removeRememberMe(this.localStorageService); + this.rememberMeService.remove(); this.configState.refreshAppState().subscribe(); } }); } async init() { - if (!getCookieValueByName(this.cookieKey) && localStorage.getItem(this.storageKey)) { - this.oAuthService.logOut(); - } + this.checkRememberMeOption(); return super.init().then(() => this.listenToTokenExpiration()); } + private checkRememberMeOption() { + const accessToken = this.oAuthService.getAccessToken(); + const isTokenExpire = isTokenExpired(this.oAuthService.getAccessTokenExpiration()); + const rememberMe = this.rememberMeService.get(); + if (accessToken && isTokenExpire && !rememberMe) { + this.rememberMeService.remove(); + this.oAuthService.logOut(); + } + } + navigateToLogin(queryParams?: Params) { const router = this.injector.get(Router); return router.navigate(['/account/login'], { queryParams }); @@ -67,14 +67,15 @@ export class AuthPasswordFlowStrategy extends AuthFlowStrategy { ), ).pipe(pipeToLogin(params, this.injector)); } + logout() { const router = this.injector.get(Router); const noRedirectToLogoutUrl = true; return from(this.oAuthService.revokeTokenAndLogout(noRedirectToLogoutUrl)).pipe( switchMap(() => this.configState.refreshAppState()), tap(() => { + this.rememberMeService.remove(); router.navigateByUrl('/'); - removeRememberMe(this.localStorageService); }), ); } @@ -82,7 +83,7 @@ export class AuthPasswordFlowStrategy extends AuthFlowStrategy { protected refreshToken() { return this.oAuthService.refreshToken().catch(() => { clearOAuthStorage(); - removeRememberMe(this.localStorageService); + this.rememberMeService.remove(); }); } } diff --git a/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts b/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts index bd50e97ee7..bc76609f5a 100644 --- a/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts +++ b/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts @@ -6,11 +6,8 @@ import { ConfigStateService, LoginParams, PipeToLoginFn, - AbpLocalStorageService, } from '@abp/ng.core'; - -const cookieKey = 'rememberMe'; -const storageKey = 'passwordFlow'; +import { RememberMeService } from '../services/remember-me.service'; export const pipeToLogin: PipeToLoginFn = function ( params: Pick, @@ -18,28 +15,18 @@ export const pipeToLogin: PipeToLoginFn = function ( ) { const configState = injector.get(ConfigStateService); const router = injector.get(Router); - const localStorage = injector.get(AbpLocalStorageService); + const rememberMeService = injector.get(RememberMeService); return pipe( switchMap(() => configState.refreshAppState()), tap(() => { - setRememberMe(params.rememberMe, localStorage); + rememberMeService.set(params.rememberMe); if (params.redirectUrl) router.navigate([params.redirectUrl]); }), ); }; -export function setRememberMe( - remember: boolean | undefined, - localStorageService: AbpLocalStorageService, -) { - removeRememberMe(localStorageService); - localStorageService.setItem(storageKey, 'true'); - document.cookie = `${cookieKey}=true; path=/${ - remember ? ' ;expires=Fri, 31 Dec 9999 23:59:59 GMT' : '' - }`; -} - -export function removeRememberMe(localStorageService: AbpLocalStorageService) { - localStorageService.removeItem(storageKey); - document.cookie = cookieKey + '= ; path=/; expires = Thu, 01 Jan 1970 00:00:00 GMT'; +//Ref: https://github.com/manfredsteyer/angular-oauth2-oidc/issues/1214 +export function isTokenExpired(expireDate: number): boolean { + const currentDate = new Date().getTime(); + return expireDate < currentDate; } diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20240108044306_Initial.Designer.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20240125061235_Initial.Designer.cs similarity index 99% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20240108044306_Initial.Designer.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20240125061235_Initial.Designer.cs index 302fe32cd9..2f3a437364 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20240108044306_Initial.Designer.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20240125061235_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20240108044306_Initial")] + [Migration("20240125061235_Initial")] partial class Initial { /// @@ -1687,10 +1687,17 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20240108044306_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20240125061235_Initial.cs similarity index 99% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20240108044306_Initial.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20240125061235_Initial.cs index 49dedb5ed0..dd96c605e7 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20240108044306_Initial.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20240125061235_Initial.cs @@ -296,6 +296,7 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations { Id = table.Column(type: "uniqueidentifier", nullable: false), Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + NormalizedName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), EntityVersion = table.Column(type: "int", nullable: false), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: false), @@ -913,6 +914,11 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations table: "AbpTenants", column: "Name"); + migrationBuilder.CreateIndex( + name: "IX_AbpTenants_NormalizedName", + table: "AbpTenants", + column: "NormalizedName"); + migrationBuilder.CreateIndex( name: "IX_AbpUserClaims_UserId", table: "AbpUserClaims", diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs index 8d7aa677c6..652e7b674d 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -1684,10 +1684,17 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20240108044315_Initial.Designer.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20240125061501_Initial.Designer.cs similarity index 99% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20240108044315_Initial.Designer.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20240125061501_Initial.Designer.cs index 41a98ace68..f25d60e99b 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20240108044315_Initial.Designer.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20240125061501_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20240108044315_Initial")] + [Migration("20240125061501_Initial")] partial class Initial { /// @@ -1687,10 +1687,17 @@ namespace MyCompanyName.MyProjectName.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20240108044243_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20240125061501_Initial.cs similarity index 99% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20240108044243_Initial.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20240125061501_Initial.cs index 074d9e6943..b0cb9b0e6f 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20240108044243_Initial.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20240125061501_Initial.cs @@ -296,6 +296,7 @@ namespace MyCompanyName.MyProjectName.Migrations { Id = table.Column(type: "uniqueidentifier", nullable: false), Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + NormalizedName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), EntityVersion = table.Column(type: "int", nullable: false), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: false), @@ -913,6 +914,11 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpTenants", column: "Name"); + migrationBuilder.CreateIndex( + name: "IX_AbpTenants_NormalizedName", + table: "AbpTenants", + column: "NormalizedName"); + migrationBuilder.CreateIndex( name: "IX_AbpUserClaims_UserId", table: "AbpUserClaims", diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/MyProjectNameDbContextModelSnapshot.cs index a125e23672..72f44ed239 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -1684,10 +1684,17 @@ namespace MyCompanyName.MyProjectName.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20240108044236_Initial.Designer.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20240125061101_Initial.Designer.cs similarity index 99% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20240108044236_Initial.Designer.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20240125061101_Initial.Designer.cs index 993398bdb4..364eaa6b57 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20240108044236_Initial.Designer.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20240125061101_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Host.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20240108044236_Initial")] + [Migration("20240125061101_Initial")] partial class Initial { /// @@ -1687,10 +1687,17 @@ namespace MyCompanyName.MyProjectName.Host.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20240108044236_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20240125061101_Initial.cs similarity index 99% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20240108044236_Initial.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20240125061101_Initial.cs index 01cf74227d..bfb34fcaad 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20240108044236_Initial.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20240125061101_Initial.cs @@ -296,6 +296,7 @@ namespace MyCompanyName.MyProjectName.Host.Migrations { Id = table.Column(type: "uniqueidentifier", nullable: false), Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + NormalizedName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), EntityVersion = table.Column(type: "int", nullable: false), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: false), @@ -913,6 +914,11 @@ namespace MyCompanyName.MyProjectName.Host.Migrations table: "AbpTenants", column: "Name"); + migrationBuilder.CreateIndex( + name: "IX_AbpTenants_NormalizedName", + table: "AbpTenants", + column: "NormalizedName"); + migrationBuilder.CreateIndex( name: "IX_AbpUserClaims_UserId", table: "AbpUserClaims", diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs index 40d1f4ea66..f2b46a651f 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -1684,10 +1684,17 @@ namespace MyCompanyName.MyProjectName.Host.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20240108044233_Initial.Designer.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20240125061143_Initial.Designer.cs similarity index 99% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20240108044233_Initial.Designer.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20240125061143_Initial.Designer.cs index d720b8d921..54929eb8e9 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20240108044233_Initial.Designer.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20240125061143_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Mvc.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20240108044233_Initial")] + [Migration("20240125061143_Initial")] partial class Initial { /// @@ -1687,10 +1687,17 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20240108044233_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20240125061143_Initial.cs similarity index 99% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20240108044233_Initial.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20240125061143_Initial.cs index ccf4b1064e..44eddb6abb 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20240108044233_Initial.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20240125061143_Initial.cs @@ -296,6 +296,7 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations { Id = table.Column(type: "uniqueidentifier", nullable: false), Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + NormalizedName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), EntityVersion = table.Column(type: "int", nullable: false), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: false), @@ -913,6 +914,11 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations table: "AbpTenants", column: "Name"); + migrationBuilder.CreateIndex( + name: "IX_AbpTenants_NormalizedName", + table: "AbpTenants", + column: "NormalizedName"); + migrationBuilder.CreateIndex( name: "IX_AbpUserClaims_UserId", table: "AbpUserClaims", diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs index 8189c80c22..8041069541 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -1684,10 +1684,17 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20240108044016_Initial.Designer.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20240125061248_Initial.Designer.cs similarity index 99% rename from templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20240108044016_Initial.Designer.cs rename to templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20240125061248_Initial.Designer.cs index 771c4cd06e..e211d7e755 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20240108044016_Initial.Designer.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20240125061248_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20240108044016_Initial")] + [Migration("20240125061248_Initial")] partial class Initial { /// @@ -1739,10 +1739,17 @@ namespace MyCompanyName.MyProjectName.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20240108044016_Initial.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20240125061248_Initial.cs similarity index 99% rename from templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20240108044016_Initial.cs rename to templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20240125061248_Initial.cs index 671c999d0c..9fc3a5a0b9 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20240108044016_Initial.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20240125061248_Initial.cs @@ -317,6 +317,7 @@ namespace MyCompanyName.MyProjectName.Migrations { Id = table.Column(type: "uniqueidentifier", nullable: false), Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + NormalizedName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), EntityVersion = table.Column(type: "int", nullable: false), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: false), @@ -939,6 +940,11 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpTenants", column: "Name"); + migrationBuilder.CreateIndex( + name: "IX_AbpTenants_NormalizedName", + table: "AbpTenants", + column: "NormalizedName"); + migrationBuilder.CreateIndex( name: "IX_AbpUserClaims_UserId", table: "AbpUserClaims", diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs index 9634d0695a..877bff36e8 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -1736,10 +1736,17 @@ namespace MyCompanyName.MyProjectName.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20240108044243_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20240125061344_Initial.Designer.cs similarity index 99% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20240108044243_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20240125061344_Initial.Designer.cs index 4c54d46943..b6dd932e2f 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20240108044243_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20240125061344_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(AuthServerDbContext))] - [Migration("20240108044243_Initial")] + [Migration("20240125061344_Initial")] partial class Initial { /// @@ -1687,10 +1687,17 @@ namespace MyCompanyName.MyProjectName.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20240108044315_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20240125061344_Initial.cs similarity index 99% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20240108044315_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20240125061344_Initial.cs index 074d9e6943..b0cb9b0e6f 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20240108044315_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20240125061344_Initial.cs @@ -296,6 +296,7 @@ namespace MyCompanyName.MyProjectName.Migrations { Id = table.Column(type: "uniqueidentifier", nullable: false), Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + NormalizedName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), EntityVersion = table.Column(type: "int", nullable: false), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: false), @@ -913,6 +914,11 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpTenants", column: "Name"); + migrationBuilder.CreateIndex( + name: "IX_AbpTenants_NormalizedName", + table: "AbpTenants", + column: "NormalizedName"); + migrationBuilder.CreateIndex( name: "IX_AbpUserClaims_UserId", table: "AbpUserClaims", diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs index 64621bc9f5..c3fb7f9ff0 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs @@ -1684,10 +1684,17 @@ namespace MyCompanyName.MyProjectName.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20240108044309_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20240125061321_Initial.Designer.cs similarity index 99% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20240108044309_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20240125061321_Initial.Designer.cs index ba9b832925..3c17670e22 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20240108044309_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20240125061321_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations { [DbContext(typeof(UnifiedDbContext))] - [Migration("20240108044309_Initial")] + [Migration("20240125061321_Initial")] partial class Initial { /// @@ -1328,10 +1328,17 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20240108044309_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20240125061321_Initial.cs similarity index 99% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20240108044309_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20240125061321_Initial.cs index 5e5fa539d2..1a8774f577 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20240108044309_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20240125061321_Initial.cs @@ -296,6 +296,7 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations { Id = table.Column(type: "uniqueidentifier", nullable: false), Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + NormalizedName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), EntityVersion = table.Column(type: "int", nullable: false), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: false), @@ -777,6 +778,11 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations table: "AbpTenants", column: "Name"); + migrationBuilder.CreateIndex( + name: "IX_AbpTenants_NormalizedName", + table: "AbpTenants", + column: "NormalizedName"); + migrationBuilder.CreateIndex( name: "IX_AbpUserClaims_UserId", table: "AbpUserClaims", diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs index d2a1a0f6d6..4acfb0c562 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs @@ -1325,10 +1325,17 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/20240125061400_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/20240125061400_Initial.Designer.cs new file mode 100644 index 0000000000..c58552ea60 --- /dev/null +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/20240125061400_Initial.Designer.cs @@ -0,0 +1,31 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MyCompanyName.MyProjectName.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace MyCompanyName.MyProjectName.Migrations +{ + [DbContext(typeof(MyProjectNameHttpApiHostMigrationsDbContext))] + [Migration("20240125061400_Initial")] + partial class Initial + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); +#pragma warning restore 612, 618 + } + } +} diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/20240125061400_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/20240125061400_Initial.cs new file mode 100644 index 0000000000..64af8f3c4a --- /dev/null +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/20240125061400_Initial.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MyCompanyName.MyProjectName.Migrations +{ + /// + public partial class Initial : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/MyProjectNameHttpApiHostMigrationsDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/MyProjectNameHttpApiHostMigrationsDbContextModelSnapshot.cs new file mode 100644 index 0000000000..30b1ab980c --- /dev/null +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/MyProjectNameHttpApiHostMigrationsDbContextModelSnapshot.cs @@ -0,0 +1,28 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MyCompanyName.MyProjectName.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace MyCompanyName.MyProjectName.Migrations +{ + [DbContext(typeof(MyProjectNameHttpApiHostMigrationsDbContext))] + partial class MyProjectNameHttpApiHostMigrationsDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); +#pragma warning restore 612, 618 + } + } +} diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20240108044305_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20240125061424_Initial.Designer.cs similarity index 99% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20240108044305_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20240125061424_Initial.Designer.cs index 3f214a4e82..04cad1c308 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20240108044305_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20240125061424_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(UnifiedDbContext))] - [Migration("20240108044305_Initial")] + [Migration("20240125061424_Initial")] partial class Initial { /// @@ -1328,10 +1328,17 @@ namespace MyCompanyName.MyProjectName.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); }); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20240108044305_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20240125061424_Initial.cs similarity index 99% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20240108044305_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20240125061424_Initial.cs index 3ee2a58667..469e6eac08 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20240108044305_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20240125061424_Initial.cs @@ -296,6 +296,7 @@ namespace MyCompanyName.MyProjectName.Migrations { Id = table.Column(type: "uniqueidentifier", nullable: false), Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + NormalizedName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), EntityVersion = table.Column(type: "int", nullable: false), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: false), @@ -777,6 +778,11 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpTenants", column: "Name"); + migrationBuilder.CreateIndex( + name: "IX_AbpTenants_NormalizedName", + table: "AbpTenants", + column: "NormalizedName"); + migrationBuilder.CreateIndex( name: "IX_AbpUserClaims_UserId", table: "AbpUserClaims", diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs index 29ac3dcc2f..b6fd7b9e97 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs @@ -1325,10 +1325,17 @@ namespace MyCompanyName.MyProjectName.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.HasKey("Id"); b.HasIndex("Name"); + b.HasIndex("NormalizedName"); + b.ToTable("AbpTenants", (string)null); });