"DoYouAgreePrivacyPolicy":"بالضغط <i>يشترك</i> الزر الذي توافق عليه <a href=\"https://account.abp.io/Account/TermsConditions\">شروط</a> و <a href=\"https://account.abp.io/Account/Privacy\">سياسة الخصوصية</a>.",
"DisplayName:CommunityIndexPagePoll":"Anketa na stránce s indexem komunity"
"DisplayName:CommunityIndexPagePoll":"Anketa na stránce s indexem komunity",
"OrganizationOverview":"Přehled organizace",
"EmailPreferences":"Předvolby e-mailu",
"DoYouAgreePrivacyPolicy":"Kliknutím <i>předplatit</i> souhlasíte s <a href=\"https://account.abp.io/Account/TermsConditions\">Podmínky</a> a <a href=\"https://account.abp.io/Account/Privacy\">Zásady ochrany osobních údajů</a>.",
"DoYouAgreePrivacyPolicy":"Beim Klicken <i>Abonnieren</i> Mit der Schaltfläche stimmen Sie dem zu <a href=\"https://account.abp.io/Account/TermsConditions\">Bedingungen</a> Und <a href=\"https://account.abp.io/Account/Privacy\">Datenschutzrichtlinie</a>.",
"Volo.AbpIo.Domain:020005":"License extend year can not be lower than {MinExtendLicenseYear} year and greater than {MaxExtendLicenseYear} years ",
"Volo.AbpIo.Domain:020005":"License extend year can not be lower than {MinExtendLicenseYear} year and greater than {MaxExtendLicenseYear} years ",
"DisplayName:CommunityIndexPagePoll":"Community Index Page Poll"
"DisplayName:CommunityIndexPagePoll":"Community Index Page Poll",
"OrganizationOverview":"Organization Overview",
"EmailPreferences":"Email Preferences",
"DoYouAgreePrivacyPolicy":"By clicking <i>Subscribe</i> button you agree to the <a href=\"https://account.abp.io/Account/TermsConditions\">Terms & Conditions</a> and <a href=\"https://account.abp.io/Account/Privacy\">Privacy Policy</a>."
"ReleaseNotesDefinition":"ABP.IO Platform releases, new products, etc.",
"Newsletter":"Newsletter",
"NewsletterDefinition":"Blog posts, community news, etc.",
"OrganizationOverview":"Organization Overview",
"EmailPreferences":"Email Preferences",
"DoYouAgreePrivacyPolicy":"By clicking <i>Subscribe</i> button you agree to the <a href=\"https://account.abp.io/Account/TermsConditions\">Terms & Conditions</a> and <a href=\"https://account.abp.io/Account/Privacy\">Privacy Policy</a>.",
"MeetTheABPCommunity":"Conozca la ABP<span class=\"gradient-community\">Comunidad</span>",
"MeetTheABPCommunity":"Conozca la ABP<span class=\"gradient-community\">Comunidad</span>",
"DisplayName:CommunityIndexPagePoll":"Encuesta de la página de índice de la comunidad"
"DisplayName:CommunityIndexPagePoll":"Encuesta de la página de índice de la comunidad",
"OrganizationOverview":"Descripción de la organización",
"EmailPreferences":"Preferencias de correo electrónico",
"DoYouAgreePrivacyPolicy":"Haciendo click <i>Suscribir</i> botón estás de acuerdo con el <a href=\"https://account.abp.io/Account/TermsConditions\">Términos</a> y <a href=\"https://account.abp.io/Account/Privacy\">política de privacidad</a>.",
"MeetTheABPCommunity":"Découvrez ABP avec la <span class=\"gradient-community\">Communauté</span>",
"MeetTheABPCommunity":"Découvrez ABP avec la <span class=\"gradient-community\">Communauté</span>",
"DisplayName:CommunityIndexPagePoll":"Sondage de la page d'accueil de la communauté"
"DisplayName:CommunityIndexPagePoll":"Sondage de la page d'accueil de la communauté",
"OrganizationOverview":"Aperçu de l'organisation",
"EmailPreferences":"Préférences de messagerie",
"DoYouAgreePrivacyPolicy":"En cliquant <i>S'abonner</i> bouton, vous acceptez le <a href=\"https://account.abp.io/Account/TermsConditions\">Termes</a> et <a href=\"https://account.abp.io/Account/Privacy\">politique de confidentialité</a>.",
"DoYouAgreePrivacyPolicy":"क्लिक करके <i>सदस्यता लें</i> जिस बटन से आप सहमत हैं <a href=\"https://account.abp.io/Account/TermsConditions\">शर्तें</a> और <a href=\"https://account.abp.io/Account/Privacy\">गोपनीयता नीति</a>.",
"DisplayName:CommunityIndexPagePoll":"Anketa na stranici indeksa zajednice"
"DisplayName:CommunityIndexPagePoll":"Anketa na stranici indeksa zajednice",
"OrganizationOverview":"Pregled organizacije",
"EmailPreferences":"Postavke e-pošte",
"DoYouAgreePrivacyPolicy":"Klikom <i>Pretplatite se</i> gumb slažete se s <a href=\"https://account.abp.io/Account/TermsConditions\">Pojmovi</a> i <a href=\"https://account.abp.io/Account/Privacy\">Politika privatnosti</a>.",
"DoYouAgreePrivacyPolicy":"Með því að smella <i>Gerast áskrifandi</i> hnappinn sem þú samþykkir <a href=\"https://account.abp.io/Account/TermsConditions\">Skilmálar</a> og <a href=\"https://account.abp.io/Account/Privacy\">Friðhelgisstefna</a>.",
"DoYouAgreePrivacyPolicy":"Cliccando <i>sottoscrivi</i> pulsante accetti il <a href=\"https://account.abp.io/Account/TermsConditions\">Termini</a> E <a href=\"https://account.abp.io/Account/Privacy\">politica sulla riservatezza</a>.",
"DoYouAgreePrivacyPolicy":"Door te klikken <i>Abonneren</i> knop waarmee u akkoord gaat <a href=\"https://account.abp.io/Account/TermsConditions\">Voorwaarden</a> En <a href=\"https://account.abp.io/Account/Privacy\">Privacybeleid</a>.",
"MeetTheABPCommunity":"Maak kennis met ABP <span class=\"gradient-community\">Gemeenschap</span>",
"MeetTheABPCommunity":"Maak kennis met ABP <span class=\"gradient-community\">Gemeenschap</span>",
"DisplayName:CommunityIndexPagePoll":"Ankieta na stronie głównej społeczności"
"DisplayName:CommunityIndexPagePoll":"Ankieta na stronie głównej społeczności",
"OrganizationOverview":"Przegląd organizacji",
"EmailPreferences":"Preferencje poczty e-mail",
"DoYouAgreePrivacyPolicy":"Klikając <i>Subskrybuj</i> przycisk, na który wyrażasz zgodę <a href=\"https://account.abp.io/Account/TermsConditions\">Warunki</a> I <a href=\"https://account.abp.io/Account/Privacy\">Polityka prywatności</a>.",
"MeetTheABPCommunity":"Conheça a ABP com a <span class=\"gradient-community\">Comunidade</span>",
"MeetTheABPCommunity":"Conheça a ABP com a <span class=\"gradient-community\">Comunidade</span>",
"DisplayName:CommunityIndexPagePoll":"Enquete da página inicial da comunidade"
"DisplayName:CommunityIndexPagePoll":"Enquete da página inicial da comunidade",
"OrganizationOverview":"Visão geral da organização",
"EmailPreferences":"Preferências de Email",
"DoYouAgreePrivacyPolicy":"Clicando <i>Se inscrever</i> botão você concorda com o <a href=\"https://account.abp.io/Account/TermsConditions\">Termos</a> e <a href=\"https://account.abp.io/Account/Privacy\">política de Privacidade</a>.",
"MeetTheABPCommunity":"Cunoaște ABP cu <span class=\"gradient-community\">Comunitatea</span>",
"MeetTheABPCommunity":"Cunoaște ABP cu <span class=\"gradient-community\">Comunitatea</span>",
"DisplayName:CommunityIndexPagePoll":"Sondajul de pe pagina de index a comunității"
"DisplayName:CommunityIndexPagePoll":"Sondajul de pe pagina de index a comunității",
"OrganizationOverview":"Prezentare a organizației",
"EmailPreferences":"preferinte de email",
"DoYouAgreePrivacyPolicy":"Dând clicuri <i>Abonati-va</i> butonul sunteți de acord cu <a href=\"https://account.abp.io/Account/TermsConditions\">Termeni</a> și <a href=\"https://account.abp.io/Account/Privacy\">Politica de confidențialitate</a>.",
"MeetTheABPCommunity":"Познакомьтесь с ABP с <span class=\"gradient-community\">Сообществом</span>",
"MeetTheABPCommunity":"Познакомьтесь с ABP с <span class=\"gradient-community\">Сообществом</span>",
"DisplayName:CommunityIndexPagePoll":"Опрос на главной странице сообщества"
"DisplayName:CommunityIndexPagePoll":"Опрос на главной странице сообщества",
"OrganizationOverview":"Обзор организации",
"EmailPreferences":"Настройки электронной почты",
"DoYouAgreePrivacyPolicy":"Кликнув <i>Подписаться</i> кнопку вы соглашаетесь с <a href=\"https://account.abp.io/Account/TermsConditions\">Условия</a> и <a href=\"https://account.abp.io/Account/Privacy\">политика конфиденциальности</a>.",
"MeetTheABPCommunity":"Spoznajte ABP s <span class=\"gradient-community\">Komunitou</span>",
"MeetTheABPCommunity":"Spoznajte ABP s <span class=\"gradient-community\">Komunitou</span>",
"DisplayName:CommunityIndexPagePoll":"Anketa na stránke indexu komunity"
"DisplayName:CommunityIndexPagePoll":"Anketa na stránke indexu komunity",
"OrganizationOverview":"Prehľad organizácie",
"EmailPreferences":"Predvoľby e-mailu",
"DoYouAgreePrivacyPolicy":"Kliknutím <i>Prihlásiť sa na odber</i> súhlasíte s <a href=\"https://account.abp.io/Account/TermsConditions\">Podmienky</a> a <a href=\"https://account.abp.io/Account/Privacy\">Zásady ochrany osobných údajov</a>.",
"MeetTheABPCommunity":"Spoznajte ABP z <span class=\"gradient-community\">Skupnostjo</span>",
"MeetTheABPCommunity":"Spoznajte ABP z <span class=\"gradient-community\">Skupnostjo</span>",
"DisplayName:CommunityIndexPagePoll":"Anketa na strani z indeksom skupnosti"
"DisplayName:CommunityIndexPagePoll":"Anketa na strani z indeksom skupnosti",
"OrganizationOverview":"Pregled organizacije",
"EmailPreferences":"E-poštne nastavitve",
"DoYouAgreePrivacyPolicy":"S klikom <i>Naročite se</i> gumb se strinjate z <a href=\"https://account.abp.io/Account/TermsConditions\">Pogoji</a> in <a href=\"https://account.abp.io/Account/Privacy\">Politika zasebnosti</a>.",
"DoYouAgreePrivacyPolicy":"<i>Abone Ol</i> butonuna tıklayarak <a href=\"https://account.abp.io/Account/TermsConditions\">Şartlar</a> ve <a href=\"https://account.abp.io/Account/Privacy\">Gizlilik Politikası</a> kurallarımızı kabul etmiş olursunuz."
"MeetTheABPCommunity":"Gặp gỡ ABP với <span class=\"gradient-community\">Cộng đồng</span>",
"MeetTheABPCommunity":"Gặp gỡ ABP với <span class=\"gradient-community\">Cộng đồng</span>",
"DisplayName:CommunityIndexPagePoll":"Bình chọn trang chủ cộng đồng"
"DisplayName:CommunityIndexPagePoll":"Bình chọn trang chủ cộng đồng",
"OrganizationOverview":"Tổng quan về tổ chức",
"EmailPreferences":"Tuỳ chọn email",
"DoYouAgreePrivacyPolicy":"Bằng cách nhấp chuột <i>Đặt mua</i> nút bạn đồng ý với <a href=\"https://account.abp.io/Account/TermsConditions\">Điều kiện</a> Và <a href=\"https://account.abp.io/Account/Privacy\">Chính sách bảo mật</a>.",
"StartupTemplates_Page_Description":"يسمح لك ABP التجاري ببناء حلول بأي مستوى من التعقيد. يوفر حلين رئيسيين لبدء التشغيل. يمكنك اختيار واحد قريب من متطلباتك وبناء الحل المخصص الخاص بك فوقه.",
"StartupTemplates_Page_Description":"يسمح لك ABP التجاري ببناء حلول بأي مستوى من التعقيد. يوفر حلين رئيسيين لبدء التشغيل. يمكنك اختيار واحد قريب من متطلباتك وبناء الحل المخصص الخاص بك فوقه.",
"MicroserviceStartupSolutionForDotnet":"حل بدء تشغيل Microservice لـ .NET",
"MicroserviceStartupSolutionForDotnet":"حل بدء تشغيل Microservice لـ .NET",
"MonolithSolutionForDotnet":"حل مترابط (معياري) لـ .NET",
"MonolithSolutionForDotnet":"حل مترابط (معياري) لـ .NET",
"TrainingDetailsHeaderInfo_TrainingHour":"{0} ساعة (ساعات)",
"StartupTemplates_Page_Description":"ABP Commercial allows you to build solutions with any level of complexity. It provides two main pre-built startup solutions. You can select the one close to your requirements and build your own custom solution on top of it.",
"StartupTemplates_Page_Description":"ABP Commercial allows you to build solutions with any level of complexity. It provides two main pre-built startup solutions. You can select the one close to your requirements and build your own custom solution on top of it.",
"MicroserviceStartupSolutionForDotnet":"Microservice Startup Solution for .NET",
"MicroserviceStartupSolutionForDotnet":"Microservice Startup Solution for .NET",
"MonolithSolutionForDotnet":"Monolith (modular) Solution for .NET",
"MonolithSolutionForDotnet":"Monolith (modular) Solution for .NET",
"Trial_Page_StartYourFreeTrial":"Start Your <span class=\"gradient-commercial\">Free Trial</span>",
"Trial_Page_StartYourFreeTrial":"Start Your <span class=\"gradient-commercial\">Free Trial</span>",
"TrialLicenseFeatures":"You'll be able to benefit from all ABP commercial features",
"TrialLicenseFeatures":"You'll be able to benefit from all ABP commercial features",
@ -1180,6 +1180,14 @@
"ReturnOfInvestmentPageAbout":"This page covers the fundamental steps of developing a software solution and explains how the ABP.IO Platform reduces your development costs at each step.",
"ReturnOfInvestmentPageAbout":"This page covers the fundamental steps of developing a software solution and explains how the ABP.IO Platform reduces your development costs at each step.",
"LearnMore":"Learn More",
"LearnMore":"Learn More",
"ReturnOfInvestment":"Return of Investment",
"ReturnOfInvestment":"Return of Investment",
"ReturnOfInvestment_Description":"Learn how to reduce your development costs by more than %50."
"ReturnOfInvestment_Description":"Learn how to reduce your development costs by more than %50.",
"StartupTemplates_Page_Description":"ABP Commercialin avulla voit rakentaa minkä tahansa monimutkaisia ratkaisuja. Se tarjoaa kaksi pääasiallista valmiiksi rakennettua käynnistysratkaisua. Voit valita tarpeitasi vastaavan ja rakentaa oman mukautetun ratkaisun sen päälle.",
"StartupTemplates_Page_Description":"ABP Commercialin avulla voit rakentaa minkä tahansa monimutkaisia ratkaisuja. Se tarjoaa kaksi pääasiallista valmiiksi rakennettua käynnistysratkaisua. Voit valita tarpeitasi vastaavan ja rakentaa oman mukautetun ratkaisun sen päälle.",
"StartupTemplates_Page_Description":"ABP Commercial omogućuje vam izradu rješenja bilo koje razine složenosti. Pruža dva glavna unaprijed izgrađena rješenja za pokretanje. Možete odabrati onaj koji je bliži vašim zahtjevima i na njemu izgraditi vlastito prilagođeno rješenje.",
"StartupTemplates_Page_Description":"ABP Commercial omogućuje vam izradu rješenja bilo koje razine složenosti. Pruža dva glavna unaprijed izgrađena rješenja za pokretanje. Možete odabrati onaj koji je bliži vašim zahtjevima i na njemu izgraditi vlastito prilagođeno rješenje.",
"MicroserviceStartupSolutionForDotnet":"Rješenje za pokretanje mikroservisa za .NET",
"MicroserviceStartupSolutionForDotnet":"Rješenje za pokretanje mikroservisa za .NET",
"MonolithSolutionForDotnet":"Monolitno (modularno) rješenje za .NET",
"MonolithSolutionForDotnet":"Monolitno (modularno) rješenje za .NET",
"Purchase_LicenseExtraDeveloperPurchaseMessage":"<span class=\"fw-6\">{0} lisansı</span> {1} geliştirici(ler) içerir. Şimdi veya daha sonra ek geliştiriciler ekleyebilirsiniz.",
"Purchase_LicenseExtraDeveloperPurchaseMessage":"<span class=\"fw-6\">{0} lisansı</span> {1} geliştirici içerir. Şimdi veya daha sonra ek geliştirici ekleyebilirsiniz.",
"StartupTemplates_Page_Title":"ABP Başlangıç Şablonları",
"StartupTemplates_Page_Title":"ABP Başlangıç Şablonları",
"StartupTemplates_Page_Description":"ABP Commercial, her düzeyde karmaşıklığa sahip projeler oluşturmanıza olanak tanır. Önceden oluşturulmuş iki ana başlangıç projesi sunar. Gereksinimlerinize yakın olanı seçebilir ve bunun üzerine kendi özel projenizi oluşturabilirsiniz.",
"StartupTemplates_Page_Description":"ABP Commercial, her düzeyde karmaşıklığa sahip projeler oluşturmanıza olanak tanır. Önceden oluşturulmuş iki ana başlangıç projesi sunar. Gereksinimlerinize yakın olanı seçebilir ve bunun üzerine kendi özel projenizi oluşturabilirsiniz.",
"MicroserviceStartupSolutionForDotnet":".NET için Mikroservis Başlatma Projesi",
"MicroserviceStartupSolutionForDotnet":".NET için Mikroservis Başlatma Projesi",
"MonolithSolutionForDotnet":".NET için Monolith (modüler) Proje",
"MonolithSolutionForDotnet":".NET için Monolith (modüler) Proje",
"ApplicationExplanation":"Domain Driven Design pratikleri üzerine oluşturulmuş çok katmanlı bir çözüm oluşturur. Bakıma ve geliştirmeye açık kod tabanına ihtiyaç duyan uzun süreli projeler için önerilir.",
"ApplicationExplanation":"Domain Driven Design pratikleri üzerine oluşturulmuş çok katmanlı bir çözüm oluşturur. Bakıma ve geliştirmeye açık kod tabanına ihtiyaç duyan uzun süreli projeler için önerilir.",
@ -227,7 +227,7 @@
"License":"Lisans",
"License":"Lisans",
"ProjectCreationSuccessMessage":"Projeniz başarıyla oluşturulmuştur",
"ProjectCreationSuccessMessage":"Projeniz başarıyla oluşturulmuştur",
"HowToRunSolution":"Uygulamayı Nasıl Çalıştırabiliriz?",
"HowToRunSolution":"Uygulamayı Nasıl Çalıştırabiliriz?",
"GettingStartedMessage":"Uygulamanızı nasıl yapılandıracağınızı ve çalıştıracağınızı öğrenmek için başlanıç dökümanına bakınız.",
"GettingStartedMessage":"Uygulamanızı nasıl yapılandıracağınızı ve çalıştıracağınızı öğrenmek için başlanıç dokümanına bakınız.",
"WebAppDevTutorialMessage":"Adım adım web uygulaması geliştirme örneği için web uygulaması geliştirme öğreticisine bakınız.",
"WebAppDevTutorialMessage":"Adım adım web uygulaması geliştirme örneği için web uygulaması geliştirme öğreticisine bakınız.",
"CommunityPosts":"Topluluk Makaleleri",
"CommunityPosts":"Topluluk Makaleleri",
@ -238,7 +238,6 @@
"ClientSideDevelopmentDocumentationMessage":"Kullanıcı arayüzü (istemci tarafı) geliştirmeyle ilgili temel noktaları öğrenmek için {0} belgesine bakın.",
"ClientSideDevelopmentDocumentationMessage":"Kullanıcı arayüzü (istemci tarafı) geliştirmeyle ilgili temel noktaları öğrenmek için {0} belgesine bakın.",
"DatabaseProviderDocumentationMessage":"Veritabanı katmanı geliştirmeyle ilgili temel noktaları öğrenmek için {0} belgesine bakın.",
"DatabaseProviderDocumentationMessage":"Veritabanı katmanı geliştirmeyle ilgili temel noktaları öğrenmek için {0} belgesine bakın.",
"ABPCommercialExplanationMessage":"ABP Commercial, ABP Framework için premium modüller, temalar, araçlar ve destek sağlar.",
"ABPCommercialExplanationMessage":"ABP Commercial, ABP Framework için premium modüller, temalar, araçlar ve destek sağlar.",
"DDDBookExplanation":"ABP Framework ile Domain Driven Design'ın uygulanması için pratik bir kılavuz.",
"DDDBookExplanation":"ABP Framework ile Domain Driven Design'ın uygulanması için pratik bir kılavuz.",
"Overview":"Genel Bakış",
"Overview":"Genel Bakış",
"DDDBookPracticalGuide":"Bu kitap Domain Driven Design'ın uygulanması için pratik bir kılavuz görevi görür. Uygulama ayrıntıları ABP Framework altyapısına dayanırken, temel kavramlar, prensipler ve modeller bir .NET çözümü olmasa bile her türlü çözümde uygulanabilir.",
"DDDBookPracticalGuide":"Bu kitap Domain Driven Design'ın uygulanması için pratik bir kılavuz görevi görür. Uygulama ayrıntıları ABP Framework altyapısına dayanırken, temel kavramlar, prensipler ve modeller bir .NET çözümü olmasa bile her türlü çözümde uygulanabilir.",
@ -290,7 +289,7 @@
"AbpNewCommandExplanation":"ABP başlangıç şablonlarını kullanarak yeni çözümler oluşturur.",
"AbpNewCommandExplanation":"ABP başlangıç şablonlarını kullanarak yeni çözümler oluşturur.",
"AbpAddModuleCommandExplanation":"Çözümünüze önceden oluşturulmuş uygulama modülleri yükler",
"AbpAddModuleCommandExplanation":"Çözümünüze önceden oluşturulmuş uygulama modülleri yükler",
"ExploreDocumentationAndGuides":"Kapsamlı belge ve kılavuzları keşfedin.",
"ExploreDocumentationAndGuides":"Kapsamlı doküman ve kılavuzları keşfedin.",
"Documentations":"Belgeler",
"Documentations":"Belgeler",
"Views":"Görünümler",
"Views":"Görünümler",
"ReadMore":"Daha fazla oku",
"ReadMore":"Daha fazla oku",
@ -428,6 +427,10 @@
"PasswordRequired":"Şifre alanı zorunludur.",
"PasswordRequired":"Şifre alanı zorunludur.",
"AddressLength":"Adres alanı maksimum uzunluğu 255 karakter olmalıdır.",
"AddressLength":"Adres alanı maksimum uzunluğu 255 karakter olmalıdır.",
"GenderRequired":"Cinsiyet alanı zorunludur.",
"GenderRequired":"Cinsiyet alanı zorunludur.",
"LeaveUsReview":"Yorumunuzu paylaşın"
"LeaveUsReview":"Yorumunuzu paylaşın",
"BuildingMicroserviceSolutionsShortDescription":"Bu kitap, ABP Framework kullanarak mikroservis tabanlı uygulamalar geliştirmek ve yönetmek için bir başvuru rehberidir.",
@ -139,7 +153,7 @@ This command should generate the following files under the `ClientProxies` folde
* `BookClientProxy.Generated.cs` is the actual generated proxy class in this example. `BookClientProxy` is a `partial` class * where you can write your custom code (ABP won't override it).
* `BookClientProxy.Generated.cs` is the actual generated proxy class in this example. `BookClientProxy` is a `partial` class * where you can write your custom code (ABP won't override it).
* `IBookAppService.cs` is the app service.
* `IBookAppService.cs` is the app service.
* `BookDto.cs` is the Dto class which uses by app service.
* `BookDto.cs` is the Dto class which uses by app service.
* `app-generate-proxy.json` contains information about the remote HTTP endpoint, so ABP can properly perform HTTP requests.
* `app-generate-proxy.json` contains information about the remote HTTP endpoint, so ABP can properly perform HTTP requests. This file must be configured as an embedded resource in your project, so that it can be found by the virtual file system.
#### Without Contracts
#### Without Contracts
@ -152,7 +166,7 @@ This command should generate the following files under the `ClientProxies` folde
* `BookClientProxy.Generated.cs` is the actual generated proxy class in this example. `BookClientProxy` is a `partial` class where you can write your custom code (ABP won't override it).
* `BookClientProxy.Generated.cs` is the actual generated proxy class in this example. `BookClientProxy` is a `partial` class where you can write your custom code (ABP won't override it).
* `app-generate-proxy.json` contains information about the remote HTTP endpoint, so ABP can properly perform HTTP requests.
* `app-generate-proxy.json` contains information about the remote HTTP endpoint, so ABP can properly perform HTTP requests. This file must be configured as an embedded resource in your project, so that it can be found by the virtual file system.
> `generate-proxy` command generates proxies for only the APIs you've defined in your application. If you are developing a modular application, you can specify the `-m` (or `--module`) parameter to specify the module you want to generate proxies. See the *generate-proxy* section in the [ABP CLI](../CLI.md) documentation for other options.
> `generate-proxy` command generates proxies for only the APIs you've defined in your application. If you are developing a modular application, you can specify the `-m` (or `--module`) parameter to specify the module you want to generate proxies. See the *generate-proxy* section in the [ABP CLI](../CLI.md) documentation for other options.
@ -30,7 +30,7 @@ The following tools should be installed on your development machine:
* An IDE (e.g. [Visual Studio](https://visualstudio.microsoft.com/vs/)) that supports [.NET 8.0+](https://dotnet.microsoft.com/download/dotnet) development.
* An IDE (e.g. [Visual Studio](https://visualstudio.microsoft.com/vs/)) that supports [.NET 8.0+](https://dotnet.microsoft.com/download/dotnet) development.
{{ if UI != "Blazor" }}
{{ if UI != "Blazor" }}
* [Node v16 or v18](https://nodejs.org/)
* [Node v16+](https://nodejs.org/)
* [Yarn v1.20+ (not v2)](https://classic.yarnpkg.com/en/docs/install) <supid="a-yarn">[1](#f-yarn)</sup> or npm v6+ (already installed with Node)
* [Yarn v1.20+ (not v2)](https://classic.yarnpkg.com/en/docs/install) <supid="a-yarn">[1](#f-yarn)</sup> or npm v6+ (already installed with Node)
@ -30,7 +30,7 @@ The following tools should be installed on your development machine:
* An IDE (e.g. [Visual Studio](https://visualstudio.microsoft.com/vs/)) that supports [.NET 8.0+](https://dotnet.microsoft.com/download/dotnet) development.
* An IDE (e.g. [Visual Studio](https://visualstudio.microsoft.com/vs/)) that supports [.NET 8.0+](https://dotnet.microsoft.com/download/dotnet) development.
{{ if UI != "Blazor" }}
{{ if UI != "Blazor" }}
* [Node v16 or v18](https://nodejs.org/)
* [Node v16+](https://nodejs.org/)
* [Yarn v1.20+ (not v2)](https://classic.yarnpkg.com/en/docs/install) <supid="a-yarn">[1](#f-yarn)</sup> or npm v6+ (already installed with Node)
* [Yarn v1.20+ (not v2)](https://classic.yarnpkg.com/en/docs/install) <supid="a-yarn">[1](#f-yarn)</sup> or npm v6+ (already installed with Node)
@ -215,6 +215,10 @@ This module implements OpenIddict stores:
- `IOpenIddictScopeStore`
- `IOpenIddictScopeStore`
- `IOpenIddictTokenStore`
- `IOpenIddictTokenStore`
#### AbpOpenIddictStoreOptions
You can configure the `PruneIsolationLevel/DeleteIsolationLevel` of `AbpOpenIddictStoreOptions` to set the isolation level for the store operations becasue different databases have different isolation levels.
##### Repositories
##### Repositories
The following custom repositories are defined in this module:
The following custom repositories are defined in this module:
"*Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects*" (Martin Fowler).
"*Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects*" (Martin Fowler).
Repositories, in practice, are used to perform database operations for domain objects (see [Entities](Entities.md)). Generally, a separated repository is used for each **aggregate root** or entity.
Repositories, in practice, are used to perform database operations for domain objects (see [Entities](Entities.md)). Generally, a separate repository is used for each **aggregate root** or entity.
## Generic Repositories
## Generic Repositories
ABP can provide a **default generic repository** for each aggregate root or entity. You can [inject](Dependency-Injection.md) `IRepository<TEntity, TKey>` into your service and perform standard **CRUD** operations.
ABP can provide a **default generic repository** for each aggregate root or entity. You can [inject](Dependency-Injection.md) `IRepository<TEntity, TKey>` into your service and perform standard **CRUD** operations.
> Database provider layer should be properly configured to be able to use the default generic repositories. It is **already done** if you've created your project using the startup templates. If not, refer to the database provider documents ([EF Core](Entity-Framework-Core.md) / [MongoDB](MongoDB.md)) to configure it.
> The database provider layer should be properly configured to be able to use the default generic repositories. It is **already done** if you've created your project using the startup templates. If not, refer to the database provider documents ([EF Core](Entity-Framework-Core.md) / [MongoDB](MongoDB.md)) to configure it.
**Example usage of a default generic repository:**
**Example usage of a default generic repository:**
@ -52,25 +52,25 @@ In this example;
### Standard Repository Methods
### Standard Repository Methods
Generic Repositories provides some standard CRUD features out of the box:
Generic Repositories provide some standard CRUD features out of the box:
* `GetAsync`: Returns a single entity by its `Id` or a predicate (lambda expression).
* `GetAsync`: Returns a single entity by its `Id` or a predicate (lambda expression).
* Throws `EntityNotFoundException` if the requested entity was not found.
* Throws `EntityNotFoundException` if the requested entity was not found.
* Throws `InvalidOperationException` if there are multiple entities with given predicate.
* Throws `InvalidOperationException` if there are multiple entities with the given predicate.
* `FindAsync`: Returns a single entity by its `Id` or a predicate (lambda expression).
* `FindAsync`: Returns a single entity by its `Id` or a predicate (lambda expression).
* Returns `null` if the requested entity was not found.
* Returns `null` if the requested entity was not found.
* Throws `InvalidOperationException` if there are multiple entities with given predicate.
* Throws `InvalidOperationException` if there are multiple entities with the given predicate.
* `InsertAsync`: Inserts a new entity to the database.
* `InsertAsync`: Inserts a new entity into the database.
* `UpdateAsync`: Updates an existing entity in the database.
* `UpdateAsync`: Updates an existing entity in the database.
* `DeleteAsync`: Deletes the given entity from database.
* `DeleteAsync`: Deletes the given entity from the database.
* This method has an overload that takes a predicate (lambda expression) to delete multiple entities satisfies the given condition.
* This method has an overload that takes a predicate (lambda expression) to delete multiple entities to satisfy the given condition.
* `GetListAsync`: Returns the list of all entities in the database.
* `GetListAsync`: Returns the list of all entities in the database.
* `GetPagedListAsync`: Returns a limited list of entities. Gets `skipCount`, `maxResultCount` and `sorting` parameters.
* `GetPagedListAsync`: Returns a limited list of entities. Gets `skipCount`, `maxResultCount`, and `sorting` parameters.
* `GetCountAsync`: Gets count of all entities in the database.
* `GetCountAsync`: Gets the count of all entities in the database.
There are overloads of these methods.
There are overloads of these methods.
* Provides `UpdateAsync` and `DeleteAsync` methods to update or delete an entity by entity object or it's id.
* Provides `UpdateAsync` and `DeleteAsync` methods to update or delete an entity by entity object or its id.
* Provides `DeleteAsync` method to delete multiple entities by a filter.
* Provides `DeleteAsync` method to delete multiple entities by a filter.
### Querying / LINQ over the Repositories
### Querying / LINQ over the Repositories
@ -142,7 +142,7 @@ Any standard LINQ method can be used over the `IQueryable` returned from the rep
> This sample uses `ToList()` method, but it is **strongly suggested to use the asynchronous methods** to perform database queries, like `ToListAsync()` for this example. See the **`IQueryable`& Async Operations** section to learn how you can do it.
> This sample uses `ToList()` method, but it is **strongly suggested to use the asynchronous methods** to perform database queries, like `ToListAsync()` for this example. See the **`IQueryable`& Async Operations** section to learn how you can do it.
> **Exposing `IQueryable` to outside of a repository** class may leak your data access logic to the application layer. If you want to strictly follow the **layered architecture** principles, you can consider to implement a custom repository class and wrap your data access logic inside your repository class. You can see the ***Custom Repositories*** section to learn how to create custom repository classes for your application.
> **Exposing `IQueryable` outside of a repository** class may leak your data access logic to the application layer. If you want to strictly follow the **layered architecture** principles, you can consider to implement a custom repository class and wrap your data access logic inside your repository class. You can see the ***Custom Repositories*** section to learn how to create custom repository classes for your application.
### Bulk Operations
### Bulk Operations
@ -158,27 +158,27 @@ These methods work with multiple entities and can take advantage of bulk operati
### Soft / Hard Delete
### Soft / Hard Delete
`DeleteAsync` method of the repository doesn't delete the entity if the entity is a **soft-delete** entity (that implements `ISoftDelete`). Soft-delete entities are marked as "deleted" in the database. Data Filter system ensures that the soft deleted entities are not retrieved from database normally.
`DeleteAsync` method of the repository doesn't delete the entity if the entity is a **soft-delete** entity (that implements `ISoftDelete`). Soft-delete entities are marked as "deleted" in the database. The Data Filter system ensures that the soft deleted entities are not retrieved from the database normally.
If your entity is a soft-delete entity, you can use the `HardDeleteAsync` method to physically delete the entity from database in case of you need it.
If your entity is a soft-delete entity, you can use the `HardDeleteAsync` method to physically delete the entity from the database in case you need it.
> See the [Data Filtering](Data-Filtering.md) documentation for more about soft-delete.
> See the [Data Filtering](Data-Filtering.md) documentation for more about soft-delete.
### Delete Direct
### Delete Direct
`DeleteDirectAsync` method of the repository deletes all entities those fit to the given predicate. It directly deletes entities from database, without fetching them.
`DeleteDirectAsync` method of the repository deletes all entities that fit to the given predicate. It directly deletes entities from the database, without fetching them.
Some features (like soft-delete, multi-tenancy and audit logging) won't work, so use this method carefully when you need it. Use the `DeleteAsync` method if you need to these features.
Some features (like soft-delete, multi-tenancy, and audit logging) won't work, so use this method carefully when you need it. Use the `DeleteAsync` method if you need these features.
> Currently only [EF Core supports it](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-7.0/whatsnew#basic-executedelete-examples), For the ORMs that don't support direct delete, we will fallback to the existing `DeleteAsync` method.
> Currently only [EF Core supports it](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-7.0/whatsnew#basic-executedelete-examples), For the ORMs that don't support direct delete, we will fallback to the existing `DeleteAsync` method.
### Ensure Entities Exists
### Ensure Entities Exist
The `EnsureExistsAsync` extension method accepts entity id or entities query expression to ensure entities exist, otherwise, it will throw `EntityNotFoundException`.
The `EnsureExistsAsync` extension method accepts entity id or entities query expression to ensure entities exist, otherwise, it will throw `EntityNotFoundException`.
### Enabling / Disabling the Change Tracking
### Enabling / Disabling the Change Tracking
ABP provides repository extension methods and attributes those can be used to control the change tracking behavior for queried entities in the underlying database provider.
ABP provides repository extension methods and attributes that can be used to control the change-tracking behavior for queried entities in the underlying database provider.
Disabling change tracking can gain performance if you query many entities from the database for read-only purposes. Querying single or a few entities won't make much performance difference, but you are free to use it whenever you like.
Disabling change tracking can gain performance if you query many entities from the database for read-only purposes. Querying single or a few entities won't make much performance difference, but you are free to use it whenever you like.
@ -215,13 +215,13 @@ public class MyDemoService : ApplicationService
}
}
````
````
> `DisableTracking` extension method returns a `IDisposable` object, so you can safely **restore** the change tracking behavior to the **previous state** one the `using` block ends. Basically, `DisableTracking` method ensures that the change tracking is disabled inside the `using` block, but doesn't affect outside of the `using` block. That means, if change tracking was already disabled, `DisableTracking` and the disposable return value do nothing.
> `DisableTracking` extension method returns an`IDisposable` object, so you can safely **restore** the change tracking behavior to the **previous state** once the `using` block ends. Basically, `DisableTracking` method ensures that the change tracking is disabled inside the `using` block, but doesn't affect outside of the `using` block. That means, if change tracking was already disabled, `DisableTracking` and the disposable return value do nothing.
`EnableTracking()` method works exactly opposite to the `DisableTracking()` method. You typically won't use it (because the change tracking is already enabled by default), but it is there in case of you need that.
`EnableTracking()` method works exactly opposite to the `DisableTracking()` method. You typically won't use it (because the change tracking is already enabled by default), but it is there in case you need that.
#### Attributes for Change Tracking
#### Attributes for Change Tracking
You typically use the `DisableTracking()` method for the application service methods those only returns data, but doesn't make any change on entities. For such cases, you can use the `DisableEntityChangeTracking` attribute on your method/class as a shortcut to disable the change tracking for whole method body.
You typically use the `DisableTracking()` method for the application service methods that only return data, but don't make any change to entities. For such cases, you can use the `DisableEntityChangeTracking` attribute on your method/class as a shortcut to disable the change tracking for the whole method body.
**Example: Using the `DisableEntityChangeTracking` attribute on a method**
**Example: Using the `DisableEntityChangeTracking` attribute on a method**
@ -240,12 +240,12 @@ public virtual async Task<List<PersonDto>> GetListAsync()
`DisableEntityChangeTracking` and `EnableEntityChangeTracking` attributes can be used on a **method** or on a **class** (which affects all of the class methods).
`DisableEntityChangeTracking` and `EnableEntityChangeTracking` attributes can be used on a **method** or on a **class** (which affects all of the class methods).
ABP uses dynamic proxying to make these attributes working. There are some rules here:
ABP uses dynamic proxying to make these attributes work. There are some rules here:
* If you are **not injecting** the service over an interface (like `IPersonAppService`), then the methods of the service must be `virtual`. Otherwise, [dynamic proxy / interception](Dynamic-Proxying-Interceptors.md) system can not work.
* If you are **not injecting** the service over an interface (like `IPersonAppService`), then the methods of the service must be `virtual`. Otherwise, [dynamic proxy / interception](Dynamic-Proxying-Interceptors.md) system can not work.
* Only `async` methods (methods returning a `Task` or `Task<T>`) are intercepted.
* Only `async` methods (methods returning a `Task` or `Task<T>`) are intercepted.
> Change tracking behavior doesn't affect tracking entity objects returned from `InsertAsync` and `UpdateAsync` methods. The objects returned from these methods are always tracked (if the underlying provider has the change tracking feature) and any change you made to these objects are saved into the database.
> Change tracking behavior doesn't affect tracking entity objects returned from `InsertAsync` and `UpdateAsync` methods. The objects returned from these methods are always tracked (if the underlying provider has the change tracking feature) and any change you make to these objects are saved into the database.
## Other Generic Repository Types
## Other Generic Repository Types
@ -255,13 +255,13 @@ Standard `IRepository<TEntity, TKey>` interface exposes the standard `IQueryable
ABP provides `IBasicRepository<TEntity, TPrimaryKey>` and `IBasicRepository<TEntity>` interfaces to support such scenarios. You can extend these interfaces (and optionally derive from `BasicRepositoryBase`) to create custom repositories for your entities.
ABP provides `IBasicRepository<TEntity, TPrimaryKey>` and `IBasicRepository<TEntity>` interfaces to support such scenarios. You can extend these interfaces (and optionally derive from `BasicRepositoryBase`) to create custom repositories for your entities.
Depending on `IBasicRepository` but not depending on `IRepository` has an advantage to make possible to work with all data sources even if they don't support `IQueryable`.
Depending on `IBasicRepository` but not depending on `IRepository` has the advantage of making it possible to work with all data sources even if they don't support `IQueryable`.
Major vendors, like Entity Framework, NHibernate or MongoDB already support `IQueryable`. So, working with `IRepository` is the **suggested** way for typical applications. But reusable module developers may consider `IBasicRepository` to support a wider range of data sources.
Major vendors, like Entity Framework, NHibernate, or MongoDB already support `IQueryable`. So, working with `IRepository` is the **suggested** way for typical applications. However reusable module developers may consider `IBasicRepository` to support a wider range of data sources.
### Read Only Repositories
### Read Only Repositories
There are also `IReadOnlyRepository<TEntity, TKey>` and `IReadOnlyBasicRepository<Tentity, TKey>` interfaces for who only want to depend on querying capabilities of the repositories.
There are also `IReadOnlyRepository<TEntity, TKey>` and `IReadOnlyBasicRepository<Tentity, TKey>` interfaces for those who only want to depend on the querying capabilities of the repositories.
The `IReadOnlyRepository<TEntity, TKey>` derives the `IReadOnlyBasicRepository<Tentity, TKey>` and provides the following properties and methods as well:
The `IReadOnlyRepository<TEntity, TKey>` derives the `IReadOnlyBasicRepository<Tentity, TKey>` and provides the following properties and methods as well:
@ -276,27 +276,27 @@ Methods:
- `WithDetails()` 1 overload
- `WithDetails()` 1 overload
- `WithDetailsAsync()` 1 overload
- `WithDetailsAsync()` 1 overload
Whereas the `IReadOnlyBasicRepository<Tentity, TKey>` provides the following methods:
Whereas the `IReadOnlyBasicRepository<Tentity, TKey>` provides the following methods:
#### Read Only Repositories behavior in Entity Framework Core
#### Read Only Repositories behavior in Entity Framework Core
Entity Framework Core read-only repository implementation uses [EF Core's No-Tracking feature](https://learn.microsoft.com/en-us/ef/core/querying/tracking#no-tracking-queries). That means the entities returned from the repository will not be tracked by the EF Core [change tracker](https://learn.microsoft.com/en-us/ef/core/change-tracking/), because it is expected that you won't update entities queried from a read-only repository. If you need to track the entities, you can still use the [AsTracking()](https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.entityframeworkqueryableextensions.astracking) extension method on the LINQ expression, or `EnableTracking()` extension method on the repository object (See *Enabling / Disabling the Change Tracking* section in this document).
Entity Framework Core read-only repository implementation uses [EF Core's No-Tracking feature](https://learn.microsoft.com/en-us/ef/core/querying/tracking#no-tracking-queries). That means the entities returned from the repository will not be tracked by the EF Core [change tracker](https://learn.microsoft.com/en-us/ef/core/change-tracking/) because it is expected that you won't update entities queried from a read-only repository. If you need to track the entities, you can still use the [AsTracking()](https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.entityframeworkqueryableextensions.astracking) extension method on the LINQ expression, or `EnableTracking()` extension method on the repository object (See *Enabling / Disabling the Change Tracking* section in this document).
> This behavior works only if the repository object is injected with one of the read-only repository interfaces (`IReadOnlyRepository<...>` or `IReadOnlyBasicRepository<...>`). It won't work if you have injected a standard repository (e.g. `IRepository<...>`) then casted it to a read-only repository interface.
> This behavior works only if the repository object is injected with one of the read-only repository interfaces (`IReadOnlyRepository<...>` or `IReadOnlyBasicRepository<...>`). It won't work if you have injected a standard repository (e.g. `IRepository<...>`) and then cast it to a read-only repository interface.
### Generic Repository without a Primary Key
### Generic Repository without a Primary Key
If your entity does not have an Id primary key (it may have a composite primary key for instance) then you cannot use the `IRepository<TEntity, TKey>` (or basic/readonly versions) defined above. In that case, you can inject and use `IRepository<TEntity>` for your entity.
If your entity does not have an Id primary key (it may have a composite primary key for instance) then you cannot use the `IRepository<TEntity, TKey>` (or basic/readonly versions) defined above. In that case, you can inject and use `IRepository<TEntity>` for your entity.
> `IRepository<TEntity>` has a few missing methods those normally works with the `Id` property of an entity. Because of the entity has no `Id` property in that case, these methods are not available. One example is the `Get` method that gets an id and returns the entity with given id. However, you can still use `IQueryable<TEntity>` features to query entities by standard LINQ methods.
> `IRepository<TEntity>` has a few missing methods that normally work with the `Id` property of an entity. Because the entity has no `Id` property in that case, these methods are not available. One example is the `Get` method which gets an id and returns the entity with the given id. However, you can still use `IQueryable<TEntity>` features to query entities by standard LINQ methods.
## Custom Repositories
## Custom Repositories
@ -304,7 +304,7 @@ Default generic repositories will be sufficient for most cases. However, you may
### Custom Repository Example
### Custom Repository Example
ABP does not force you to implement any interface or inherit from any base class for a repository. It can be just a simple POCO class. However, it's suggested to inherit existing repository interface and classes to make your work easier and get the standard methods out of the box.
ABP does not force you to implement any interface or inherit from any base class for a repository. It can be just a simple POCO class. However, it's suggested to inherit existing repository interfaces and classes to make your work easier and get the standard methods out of the box.
#### Custom Repository Interface
#### Custom Repository Interface
@ -348,7 +348,7 @@ You can directly access the data access provider (`DbContext` in this case) to p
## IQueryable & Async Operations
## IQueryable & Async Operations
`IRepository` provides `GetQueryableAsync()` to obtain an `IQueryable`, that means you can **directly use LINQ extension methods** on it, as shown in the example of the "*Querying / LINQ over the Repositories*" section above.
`IRepository` provides `GetQueryableAsync()` to obtain an `IQueryable`, which means you can **directly use LINQ extension methods** on it, as shown in the example of the "*Querying / LINQ over the Repositories*" section above.
**Example: Using the `Where(...)` and the `ToList()` extension methods**
**Example: Using the `Where(...)` and the `ToList()` extension methods**
@ -376,7 +376,7 @@ Based on your requirements and development model, you have the following options
**The easiest solution** is to directly add the EF Core package from the project you want to use these async methods.
**The easiest solution** is to directly add the EF Core package from the project you want to use these async methods.
> Add the [Volo.Abp.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore) NuGet package to your project, which indirectly reference to the EF Core package. This ensures that you use the correct version of the EF Core compatible to the rest of your application.
> Add the [Volo.Abp.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore) NuGet package to your project, which indirectly references the EF Core package. This ensures that you use the correct version of the EF Core compatible with the rest of your application.
When you add the NuGet package to your project, you can take full power of the EF Core extension methods.
When you add the NuGet package to your project, you can take full power of the EF Core extension methods.
@ -391,7 +391,7 @@ var people = queryable
This method is suggested;
This method is suggested;
* If you are developing an application and you **don't plan to change** EF Core in the future, or you can **tolerate** it if you need to change later. We believe that's reasonable if you are developing a final application.
* If you are developing an application and you **don't plan to change** EF Core in the future, or you can **tolerate** it if you need to change it later. We believe that's reasonable if you are developing a final application.
#### MongoDB Case
#### MongoDB Case
@ -432,7 +432,7 @@ var queryable = await _bookRepository.GetQueryableAsync();
var count = await queryable.Where(x => x.Name.Contains("A")).CountAsync();
var count = await queryable.Where(x => x.Name.Contains("A")).CountAsync();
```
```
This is because the `CountAsync()` method in this example is called on a `IQueryable` interface, not on the repository object. See the other options for such cases.
This is because the `CountAsync()` method in this example is called on an`IQueryable` interface, not on the repository object. See the other options for such cases.
This method is suggested **wherever possible**.
This method is suggested **wherever possible**.
@ -488,7 +488,7 @@ namespace AbpDemo
> `ApplicationService` and `DomainService` base classes already have `AsyncExecuter` properties pre-injected and usable without needing an explicit constructor injection.
> `ApplicationService` and `DomainService` base classes already have `AsyncExecuter` properties pre-injected and usable without needing an explicit constructor injection.
ABP Framework executes the query asynchronously using the actual database provider's API. While that is not a usual way to execute a query, it is the best way to use the async API without depending on the database provider.
ABP Framework executes the query asynchronously using the actual database provider's API. While that is not the usual way to execute a query, it is the best way to use the async API without depending on the database provider.
This method is suggested;
This method is suggested;
@ -499,7 +499,7 @@ For example, ABP Framework uses the `IAsyncQueryableExecuter` in the `CrudAppSer
### Option-4: Custom Repository Methods
### Option-4: Custom Repository Methods
You can always create custom repository methods and use the database providerspecific APIs, like async extension methods here. See [EF Core](Entity-Framework-Core.md) or [MongoDb](MongoDB.md) document for more info about the custom repositories.
You can always create custom repository methods and use the database provider-specific APIs, like async extension methods here. See [EF Core](Entity-Framework-Core.md) or [MongoDb](MongoDB.md) document for more info about the custom repositories.
* Improvements on the existing features and provide more guides.
* Improvements on the existing features and provide more guides.
See the [8.1 milestone](https://github.com/abpframework/abp/milestone/94) for all the issues we've planned to work on.
See the [8.2 milestone](https://github.com/abpframework/abp/milestone/95) for all the issues we've planned to work on.
## Backlog Items
## Backlog Items
The *Next Versions* section above shows the main focus of the planned versions. However, in each release we add new features to the core framework and the [application modules](Modules/Index.md).
The *Next Versions* section above shows the main focus of the planned versions. However, in each release, we add new features to the core framework and the [application modules](Modules/Index.md).
Here is a list of major items in the backlog we are considering working on in the next versions.
Here is a list of major items in the backlog we are considering working on in the next versions.
* [#6655](https://github.com/abpframework/abp/pull/6655) / Use Typescript for the MVC UI
* [#236](https://github.com/abpframework/abp/issues/236) / Resource based authorization system
* [#236](https://github.com/abpframework/abp/issues/236) / Resource based authorization system
* [#2882](https://github.com/abpframework/abp/issues/2882) / Providing a gRPC integration infrastructure (while it is [already possible](https://github.com/abpframework/abp-samples/tree/master/GrpcDemo) to create or consume gRPC endpoints for your application, we plan to create endpoints for the [standard application modules](https://docs.abp.io/en/abp/latest/Modules/Index))
* [#2882](https://github.com/abpframework/abp/issues/2882) / Providing a gRPC integration infrastructure (while it is [already possible](https://github.com/abpframework/abp-samples/tree/master/GrpcDemo) to create or consume gRPC endpoints for your application, we plan to create endpoints for the [standard application modules](https://docs.abp.io/en/abp/latest/Modules/Index))
@ -36,7 +36,7 @@ There are more than one test project, organized by the layers;
* `Domain.Tests` is used to test your Domain Layer objects (like [Domain Services](Domain-Services.md) and [Entities](Entities.md)).
* `Domain.Tests` is used to test your Domain Layer objects (like [Domain Services](Domain-Services.md) and [Entities](Entities.md)).
* `Application.Tests` is used to test your Application Layer (like [Application Services](Application-Services.md)).
* `Application.Tests` is used to test your Application Layer (like [Application Services](Application-Services.md)).
* `EntityFrameworkCore.Tests` is used to test your custom repository implementations or EF Core mappings (this project will be different if you use another [Database Provider](Data-Access.md)).
* `EntityFrameworkCore.Tests` is used to implement abstract test classes and test your custom repository implementations or EF Core mappings (this project will be different if you use another [Database Provider](Data-Access.md)).
* `Web.Tests` is used to test the UI Layer (like Pages, Controllers and View Components). This project does exists only for MVC / Razor Page applications.
* `Web.Tests` is used to test the UI Layer (like Pages, Controllers and View Components). This project does exists only for MVC / Razor Page applications.
* `TestBase` contains some classes those are shared/used by the other projects.
* `TestBase` contains some classes those are shared/used by the other projects.
@ -537,12 +537,13 @@ using Xunit;
namespace MyProject.Issues
namespace MyProject.Issues
{
{
public class IssueManager_Integration_Tests : MyProjectDomainTestBase
public abstract class IssueManager_Integration_Tests<TStartupModule> : MyProjectDomainTestBase<TStartupModule>
> The `IssueManager_Integration_Tests` class is an abstract class, and tests in this class are not seen on the tests explorer, see the **Implementing unit tests in EF Core and MongoDB** section below to learn how to list tests in the test explorer and run them.
* First test method assigns the issue to the User 1, which has already assigned to 3 issues in the Data Seed code. So, it throws a `BusinessException`.
* First test method assigns the issue to the User 1, which has already assigned to 3 issues in the Data Seed code. So, it throws a `BusinessException`.
* Second test method assigns the issue to User 2, which has only 1 issue assigned. So, the method succeeds.
* Second test method assigns the issue to User 2, which has only 1 issue assigned. So, the method succeeds.
@ -625,11 +628,12 @@ using Xunit;
namespace MyProject.Issues
namespace MyProject.Issues
{
{
public class IssueAppService_Tests : MyProjectApplicationTestBase
public abstract class IssueAppService_Tests<TStartupModule> : MyProjectApplicationTestBase<TStartupModule>
> The `IssueAppService_Tests` class is an abstract, and tests in this class are not seen on the tests explorer, see the **Implementing unit tests in EF Core and MongoDB** section below to learn how to list tests in the test explorer and run them.
It's that simple. This test method tests everything, including the application service, EF Core mapping, object to object mapping and the repository implementation. In this way, you can fully test the Application Layer and the Domain Layer of your solution.
It's that simple. This test method tests everything, including the application service, EF Core mapping, object to object mapping and the repository implementation. In this way, you can fully test the Application Layer and the Domain Layer of your solution.
### Dealing with Unit of Work in Integration Tests
### Dealing with Unit of Work in Integration Tests
@ -658,11 +664,12 @@ In the ABP Framework, all the database operations must be performed inside a uni
In some cases, you may need to manually control the unit of work scope. Consider the following test method:
In some cases, you may need to manually control the unit of work scope. Consider the following test method:
````csharp
````csharp
public class IssueRepository_Tests : MyProjectDomainTestBase
public abstract class IssueRepository_Tests<TStartupModule> : MyProjectDomainTestBase<TStartupModule>
@ -676,17 +683,20 @@ public class IssueRepository_Tests : MyProjectDomainTestBase
}
}
````
````
> The `IssueRepository_Tests` class is an abstract, and tests in this class are not seen on the tests explorer, see the **Implementing unit tests in EF Core and MongoDB** section below to learn how to list tests in the test explorer and run them.
We are using `_issueRepository.GetQueryableAsync` to obtain an `IQueryable<Issue>` object. Then, we are using the `FirstOrDefaultAsync` method to query an issue by its title. The database query is executed at this point, and you get an exception indicating that there is no active unit of work.
We are using `_issueRepository.GetQueryableAsync` to obtain an `IQueryable<Issue>` object. Then, we are using the `FirstOrDefaultAsync` method to query an issue by its title. The database query is executed at this point, and you get an exception indicating that there is no active unit of work.
To make that test properly working, you should manually start a unit of work scope as shown in the following example:
To make that test properly working, you should manually start a unit of work scope as shown in the following example:
````csharp
````csharp
public class IssueRepository_Tests : MyProjectDomainTestBase
public abstract class IssueRepository_Tests<TStartupModule> : MyProjectDomainTestBase<TStartupModule>
@ -740,10 +751,33 @@ public class MyDbContext_Tests : MyProjectDomainTestBase
}
}
````
````
> The `MyDbContext_Tests` class is an abstract, and tests in this class are not seen on the tests explorer, see the **Implementing unit tests in EF Core and MongoDB** section below to learn how to list tests in the test explorer and run them.
Just like we've done in the *Dealing with Unit of Work in Integration Tests* section, we should perform `DbContext` operations inside an active unit of work.
Just like we've done in the *Dealing with Unit of Work in Integration Tests* section, we should perform `DbContext` operations inside an active unit of work.
For [MongoDB](MongoDB.md), you can use the `IMongoDbContextProvider<T>` service to obtain a `DbContext` object and directly use MongoDB APIs in your test methods.
For [MongoDB](MongoDB.md), you can use the `IMongoDbContextProvider<T>` service to obtain a `DbContext` object and directly use MongoDB APIs in your test methods.
## Implementing unit tests in EF Core and MongoDB
The unit test classes in the `.Domain.Test` and `.Application.Tests` projects are all abstract classes. Therefore, we need to implement the test classes in EF Core or MongoDB test projects to run the tests, otherwise they will be ignored.
An example implementation for the `IssueManager_Integration_Tests` class in the `.EntityFrameworkCore.Tests` project is shown below:
As you can see from the folder structure, all tests are clearly placed into the related subfolders, and they will be seen in the test explorer with this separation. Thus, you can clearly see which tests are related to which layers and projects.