Browse Source

Merge remote-tracking branch 'origin/dev' into cms-kit/refactoring

pull/7085/head
enisn 5 years ago
parent
commit
8fe9a59e1f
  1. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  2. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json
  3. 8
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
  4. 45
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
  5. 31
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json
  6. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json
  7. 2
      docs/en/Background-Workers.md
  8. 2
      docs/en/Blob-Storing.md
  9. 140
      docs/en/Community-Articles/2020-08-12-Patch-Chrome-Login-Issue-For-IdentityServer4/POST.md
  10. 6
      docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/POST.md
  11. 2
      docs/en/Modules/Index.md
  12. 2
      docs/en/Modules/Setting-Management.md
  13. 2
      docs/en/Text-Templating.md
  14. 28
      docs/en/UI/Angular/Authorization.md
  15. 10
      docs/en/UI/Angular/Multi-Tenancy.md
  16. 64
      docs/en/UI/Angular/Page-Alerts.md
  17. 377
      docs/en/UI/Angular/Testing.md
  18. BIN
      docs/en/UI/Angular/images/page-alert-warning-example.png
  19. BIN
      docs/en/UI/Angular/images/page-alert-with-params-example.png
  20. 12
      docs/en/docs-nav.json
  21. 2
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LanguageSwitch.razor
  22. 2
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor.cs
  23. 2
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/NavMenu.razor.cs
  24. 2
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/NavToolbar.razor.cs
  25. 25
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Toolbars/ToolbarConfigurationContext.cs
  26. 7
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributor.cs
  27. 2
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/FormTenantResolveContributor.cs
  28. 2
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributerBase.cs
  29. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo.Abp.AspNetCore.Mvc.Client.Common.csproj
  30. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCommonModule.cs
  31. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteFeatureChecker.cs
  32. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj
  33. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs
  34. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs
  35. 13
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClientHelper.cs
  36. 34
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCurrentApplicationConfigurationCacheResetEventHandler.cs
  37. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.csproj
  38. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcContractsModule.cs
  39. 10
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentApplicationConfigurationCacheResetEventData.cs
  40. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbTagHelperService.cs
  41. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs
  42. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs
  43. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs
  44. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs
  45. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs
  46. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs
  47. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
  48. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
  49. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelperService.cs
  50. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs
  51. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabDropdownTagHelperService.cs
  52. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabTagHelperService.cs
  53. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabsTagHelperService.cs
  54. 30
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleConfigurationContext.cs
  55. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelperService.cs
  56. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleTagHelperService.cs
  57. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs
  58. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperStyleService.cs
  59. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/TagHelpers/AbpComponentDemoSectionTagHelper.cs
  60. 29
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarConfigurationContext.cs
  61. 87
      framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs
  62. 1
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj
  63. 20
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpActionContextExtensions.cs
  64. 4
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs
  65. 86
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpController.cs
  66. 47
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpViewComponent.cs
  67. 21
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs
  68. 25
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs
  69. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Content/RemoteStreamContentOutputFormatter.cs
  70. 48
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs
  71. 45
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs
  72. 17
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeatureActionFilter.cs
  73. 16
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeaturePageFilter.cs
  74. 10
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeatureActionFilter.cs
  75. 10
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeaturePageFilter.cs
  76. 15
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs
  77. 73
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOptionsSetup.cs
  78. 14
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs
  79. 67
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs
  80. 26
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs
  81. 25
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs
  82. 9
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/AbpValidationActionFilter.cs
  83. 87
      framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpHub.cs
  84. 2
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs
  85. 48
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs
  86. 2
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs
  87. 2
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AuthorizationInterceptor.cs
  88. 10
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Localization/nl.json
  89. 4
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs
  90. 2
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/PermissionRequirementHandler.cs
  91. 4
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/ClientPermissionValueProvider.cs
  92. 4
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RolePermissionValueProvider.cs
  93. 4
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/UserPermissionValueProvider.cs
  94. 2
      framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs
  95. 4
      framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs
  96. 29
      framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerBase.cs
  97. 4
      framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs
  98. 2
      framework/src/Volo.Abp.BlazoriseUI/Components/EntityAction.razor.cs
  99. 6
      framework/src/Volo.Abp.BlazoriseUI/Volo.Abp.BlazoriseUI.csproj
  100. 2
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs

5
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json

@ -197,6 +197,7 @@
"RemoveCache": "Remove Cache",
"Language": "Language",
"Optional": "Optional",
"CreateArticleLanguageInfo": "The language in which the article is written"
"CreateArticleLanguageInfo": "The language in which the post is written",
"Enum:ContentSource:2": "Video Post"
}
}
}

2
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json

@ -27,6 +27,8 @@
"Blog": "博客",
"Commercial": "商业版",
"MyAccount": "我的账户",
"Permission:License": "许可",
"Permission:UserInfo": "用户信息",
"SeeDocuments": "查看文档",
"Samples": "示例"
}

8
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json

@ -28,8 +28,12 @@
"MyOrganizations": "我的组织",
"ApiKey": "API key",
"UserNameNotFound": "没有用户名为{0}的用户",
"SuccessfullyAddedToNewsletter": "感谢你订阅我们的新闻讯!",
"SuccessfullyAddedToNewsletter": "感谢你订阅我们的新闻讯!",
"MyProfile": "我的资料",
"EmailNotValid": "请输入有效的电子邮件地址"
"EmailNotValid": "请输入有效的电子邮件地址",
"JoinOurMarketingNewsletter": "加入我们的营销简讯",
"WouldLikeToReceiveMarketingMaterials": "我想收到市场营销资料,例如产品交易和特别优惠.",
"StartUsingYourLicenseNow": "立即开始使用你的许可证",
"WelcomePage": "欢迎页面"
}
}

45
abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json

@ -25,18 +25,17 @@
"MostRead": "Most Read",
"Latest": "Latest",
"ContributeAbpCommunity": "Contribute to the ABP Community",
"SubmitYourArticle": "Submit Your Article",
"SubmitYourArticle": "Submit Your Post",
"ContributionGuide": "Contribution Guide",
"BugReport": "Bug Report",
"SeeAllArticles": "See All Articles",
"SeeAllArticles": "See All Posts",
"WelcomeToABPCommunity!": "Welcome to the ABP Community!",
"MyProfile": "My profile",
"MyOrganizations": "My organizations",
"EmailNotValid": "Please enter a valid email address.",
"FeatureRequest": "Feature Request",
"CreateArticleTitleInfo": "Title of the article to be shown on the article list.",
"CreateArticleUrlInfo": "Original GitHub/External URL of the article.",
"CreateArticleSummaryInfo": "A short summary of the article to be shown on the article list.",
"CreateArticleTitleInfo": "Title of the post to be shown on the post list.",
"CreateArticleSummaryInfo": "A short summary of the post to be shown on the post list.",
"CreateArticleCoverInfo": "For creating an effective article, add a cover photo. Upload 16:9 aspect ratio pictures for the best view. Maximum file size: 1MB.",
"ThisExtensionIsNotAllowed": "This extension is not allowed.",
"TheFileIsTooLarge": "The file is too large.",
@ -87,7 +86,7 @@
"PlannedReleaseDate": "Planned release date",
"CommunityArticleRequestErrorMessage": "Could not get the latest article request from Github.",
"ArticleRequestFromGithubIssue": "There are not any article requests now.",
"LatestArticles": "Latest Articles",
"LatestArticles": "Latest Posts",
"ArticleRequests": "Article Requests",
"AllArticleRequests": "See All Article Requests",
"SubscribeToTheNewsletter": "Subscribe to the Newsletter",
@ -101,6 +100,38 @@
"ArticleRequestMessageTitle": "<a href=\"https://github.com/abpframework/abp/issues/new\">Open an issue</a> on the GitHub to request an article/tutorial you want to see on this web site.",
"ArticleRequestMessageBody": "Here, the list of the requested articles by the community. Do you want to write a requested article? Please click to the request and join to the discussion.",
"Language": "Language",
"CreateArticleLanguageInfo": "The language in which the article is written"
"CreateArticleLanguageInfo": "The language for the post content.",
"VideoPost": "Video Post",
"Article": "Article",
"Read": "Read",
"CreateGithubArticleUrlInfo": "Original GitHub URL of the article.",
"CreateVideoContentUrlInfo": "Original Youtube URL of the post.",
"CreateExternalArticleUrlInfo": "Original External Url of the article.",
"VideoContentForm": "Submit Video on YouTube",
"GithubPostForm": "Submit Article on GitHub",
"ExternalPostForm": "Submit an External Content",
"HowToPost": "How to Post?",
"Posts": "Posts",
"VideoUrl": "Video Url",
"GithubArticleUrl": "Github Article Url",
"ExternalArticleUrl": "External Article Url",
"CreatePostCoverInfo": "For creating an effective post, add a cover photo. Upload 16:9 aspect ratio pictures for the best view. Maximum file size: 1MB.",
"ThankYouForContribution": "Thank you for contributing to the ABP Community.",
"GithubArticle": "Github Article",
"GithubArticleSubmitStepOne": "<span class=\"font-weight-bold\">1.</span> Write an article on any public GitHub repository with the Markdown format. <a target=\"_blank\" href=\"https://github.com/abpframework/abp/blob/dev/docs/en/Community-Articles/2020-12-04-Event-Organizer/Post.md\">example</a>",
"GithubArticleSubmitStepTwo": "<span class=\"font-weight-bold\">2.</span> Submit your article URL using the form.",
"GithubArticleSubmitStepThree": "<span class=\"font-weight-bold\">3.</span> Your article will be rendered in this web site.",
"YoutubeVideo": "Youtube Video",
"YoutubeVideoSubmitStepOne": "<span class=\"font-weight-bold\">1.</span> Publish your video on YouTube.",
"YoutubeVideoSubmitStepTwo": "<span class=\"font-weight-bold\">2.</span> Submit the video URL using the form.",
"YoutubeVideoSubmitStepThree": "<span class=\"font-weight-bold\">3.</span> Visitors will be able to watch your video content directly on this website.",
"ExternalContent": "External Content",
"ExternalContentSubmitStepOne": "<span class=\"font-weight-bold\">1.</span> Create a content on any public platform (medium, your own blog or anywhere you like).",
"ExternalContentSubmitStepTwo": "<span class=\"font-weight-bold\">2.</span> Submit your content URL using the form.",
"ExternalContentSubmitStepThree": "<span class=\"font-weight-bold\">3.</span> Visitors are redirected to the content on the original website.",
"ChooseYourContentType": "Please choose the way you want to add your content.",
"PostContentViaGithub": "I want to add my article with <span class=\"font-weight-bold\"><i class=\"fa fa-github\"></i> GitHub</span> in accordance with the markdown rules.",
"PostContentViaYoutube": "I want to share my videos available on <span class=\"font-weight-bold\"><i class=\"fa fa-youtube\"></i> Youtube</span> here.",
"PostContentViaExternalSource": "I want to add the content I published on <span class=\"font-weight-bold\">another platform</span> here."
}
}

31
abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json

@ -35,7 +35,6 @@
"EmailNotValid": "请输入有效的电子邮箱地址.",
"FeatureRequest": "功能请求",
"CreateArticleTitleInfo": "文章标题显示在文章列表中.",
"CreateArticleUrlInfo": "文章的原始GitHub/外部URL.",
"CreateArticleSummaryInfo": "文章的简短摘要将显示在文章列表中.",
"CreateArticleCoverInfo": "为了创建有效的文章,请添加封面图. 仅支持16:9的图片!",
"ThisExtensionIsNotAllowed": "不允许此扩展名.",
@ -84,6 +83,34 @@
"Edit": "修改",
"ProfileImageChange": "更改资料图片",
"BlogItemErrorMessage": "无法从ABP获取最新的博客文章详细信息.",
"PlannedReleaseDate": "计划发布日期"
"PlannedReleaseDate": "计划发布日期",
"CommunityArticleRequestErrorMessage": "无法从Github获取最新的文章请求.",
"ArticleRequestFromGithubIssue": "现在没有任何文章请求.",
"LatestArticles": "最新的帖子",
"ArticleRequests": "文章请求",
"AllArticleRequests": "查看所有文章请求",
"SubscribeToTheNewsletter": "订阅简讯",
"NewsletterEmailDefinition": "获取有关ABP发生的信息,例如新版本,免费资源,文章等.",
"NoThanks": "不用了,谢谢",
"MaybeLater": "以后再说",
"JoinOurArticleNewsletter": "加入我们的文章简讯",
"Community": "社区",
"Marketing": "营销",
"CommunityPrivacyPolicyConfirmation": "我同意条款和条件以及<a href=\"https://commercial.abp.io/Privacy\">隐私政策</a>.",
"ArticleRequestMessageTitle": "<a href=\"https://github.com/abpframework/abp/issues/new\">在GitHub上创建一个Issue</a>,以请求你要在此网站上查看的文章/教程.",
"ArticleRequestMessageBody": "在这里,是社区请求的文章列表. 您要写一篇要求的文章吗? 请单击该请求并加入讨论.",
"Language": "语言",
"CreateArticleLanguageInfo": "本文所用的语言",
"VideoPost": "视频",
"Article": "文章",
"Read": "阅读",
"CreateGithubArticleUrlInfo": "文章的原始GitHub链接.",
"CreateVideoContentUrlInfo": "文章的原始Youtube链接.",
"CreateExternalArticleUrlInfo": "本文的原始外部网址",
"VideoContentForm": "视频内容来源",
"GithubPostForm": "Github文章来源",
"ExternalPostForm": "外部文章来源",
"PostSourceTypeChooses": "我们接受文章的三种来源类型;",
"Posts": "文章"
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json

@ -192,6 +192,7 @@
"MultipleUIOptions": "多个UI选项",
"MultipleDBOptions": "多个数据库提供程序",
"MultipleUIOptionsExplanation": "核心框架设计为独立与UI,可以和任何类型的UI系统一起使用. 同时提供了多个开箱即用的预构建集成选项.",
"SelectLanguage": "選擇語言"
"MultipleDBOptionsExplanation": "该框架可以使用任何数据源,并且以下提供程序已得到正式开发和支持;",
"SelectLanguage": "选择语言"
}
}
}

2
docs/en/Background-Workers.md

@ -45,7 +45,7 @@ Assume that we want to make a user passive, if the user has not logged in to the
public class PassiveUserCheckerWorker : AsyncPeriodicBackgroundWorkerBase
{
public PassiveUserCheckerWorker(
AbpTimer timer,
AbpAsyncTimer timer,
IServiceScopeFactory serviceScopeFactory
) : base(
timer,

2
docs/en/Blob-Storing.md

@ -14,7 +14,7 @@ ABP BLOB Storage system is also compatible to other ABP Framework features like
## BLOB Storage Providers
The ABP Framework has already the following storage provider implementations;
The ABP Framework has already the following storage provider implementations:
* [File System](Blob-Storing-File-System.md): Stores BLOBs in a folder of the local file system, as standard files.
* [Database](Blob-Storing-Database.md): Stores BLOBs in a database.

140
docs/en/Community-Articles/2020-08-12-Patch-Chrome-Login-Issue-For-IdentityServer4/POST.md

@ -11,157 +11,75 @@ When you use HTTP on your Identity Server 4 enabled website, users may not login
Create the below extension in your ***.Web** project.
```csharp
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.Extensions.DependencyInjection
{
public static class SameSiteCookiesServiceCollectionExtensions
{
/// <summary>
/// -1 defines the unspecified value, which tells ASPNET Core to NOT
/// send the SameSite attribute. With ASPNET Core 3.1 the
/// <seealso cref="SameSiteMode" /> enum will have a definition for
/// Unspecified.
/// </summary>
private const SameSiteMode Unspecified = (SameSiteMode)(-1);
/// <summary>
/// Configures a cookie policy to properly set the SameSite attribute
/// for Browsers that handle unknown values as Strict. Ensure that you
/// add the <seealso cref="Microsoft.AspNetCore.CookiePolicy.CookiePolicyMiddleware" />
/// into the pipeline before sending any cookies!
/// </summary>
/// <remarks>
/// Minimum ASPNET Core Version required for this code:
/// - 2.1.14
/// - 2.2.8
/// - 3.0.1
/// - 3.1.0-preview1
/// Starting with version 80 of Chrome (to be released in February 2020)
/// cookies with NO SameSite attribute are treated as SameSite=Lax.
/// In order to always get the cookies send they need to be set to
/// SameSite=None. But since the current standard only defines Lax and
/// Strict as valid values there are some browsers that treat invalid
/// values as SameSite=Strict. We therefore need to check the browser
/// and either send SameSite=None or prevent the sending of SameSite=None.
/// Relevant links:
/// - https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-4.1
/// - https://tools.ietf.org/html/draft-west-cookie-incrementalism-00
/// - https://www.chromium.org/updates/same-site
/// - https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
/// - https://bugs.webkit.org/show_bug.cgi?id=198181
/// </remarks>
/// <param name="services">The service collection to register <see cref="CookiePolicyOptions" /> into.</param>
/// <returns>The modified <see cref="IServiceCollection" />.</returns>
public static IServiceCollection ConfigureNonBreakingSameSiteCookies(this IServiceCollection services)
public static IServiceCollection AddSameSiteCookiePolicy(this IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.MinimumSameSitePolicy = Unspecified;
options.OnAppendCookie = cookieContext =>
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
options.OnDeleteCookie = cookieContext =>
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
options.OnAppendCookie = cookieContext =>
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
options.OnDeleteCookie = cookieContext =>
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
});
return services;
}
private static void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
if (options.SameSite == SameSiteMode.None)
{
var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
if (DisallowsSameSiteNone(userAgent))
if (!httpContext.Request.IsHttps || DisallowsSameSiteNone(userAgent))
{
options.SameSite = Unspecified;
// For .NET Core < 3.1 set SameSite = (SameSiteMode)(-1)
options.SameSite = SameSiteMode.Unspecified;
}
}
}
/// <summary>
/// Checks if the UserAgent is known to interpret an unknown value as Strict.
/// For those the <see cref="CookieOptions.SameSite" /> property should be
/// set to <see cref="Unspecified" />.
/// </summary>
/// <remarks>
/// This code is taken from Microsoft:
/// https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
/// </remarks>
/// <param name="userAgent">The user agent string to check.</param>
/// <returns>Whether the specified user agent (browser) accepts SameSite=None or not.</returns>
private static bool DisallowsSameSiteNone(string userAgent)
{
// Cover all iOS based browsers here. This includes:
// - Safari on iOS 12 for iPhone, iPod Touch, iPad
// - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
// - Chrome on iOS 12 for iPhone, iPod Touch, iPad
// All of which are broken by SameSite=None, because they use the
// iOS networking stack.
// Notes from Thinktecture:
// Regarding https://caniuse.com/#search=samesite iOS versions lower
// than 12 are not supporting SameSite at all. Starting with version 13
// unknown values are NOT treated as strict anymore. Therefore we only
// need to check version 12.
if (userAgent.Contains("CPU iPhone OS 12")
|| userAgent.Contains("iPad; CPU OS 12"))
// - Safari on iOS 12 for iPhone, iPod Touch, iPad
// - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
// - Chrome on iOS 12 for iPhone, iPod Touch, iPad
// All of which are broken by SameSite=None, because they use the iOS networking stack
if (userAgent.Contains("CPU iPhone OS 12") || userAgent.Contains("iPad; CPU OS 12"))
{
return true;
}
// Cover Mac OS X based browsers that use the Mac OS networking stack.
// This includes:
// - Safari on Mac OS X.
// Cover Mac OS X based browsers that use the Mac OS networking stack. This includes:
// - Safari on Mac OS X.
// This does not include:
// - Chrome on Mac OS X
// because they do not use the Mac OS networking stack.
// Notes from Thinktecture:
// Regarding https://caniuse.com/#search=samesite MacOS X versions lower
// than 10.14 are not supporting SameSite at all. Starting with version
// 10.15 unknown values are NOT treated as strict anymore. Therefore we
// only need to check version 10.14.
if (userAgent.Contains("Safari")
&& userAgent.Contains("Macintosh; Intel Mac OS X 10_14")
&& userAgent.Contains("Version/"))
// - Chrome on Mac OS X
// Because they do not use the Mac OS networking stack.
if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") &&
userAgent.Contains("Version/") && userAgent.Contains("Safari"))
{
return true;
}
// Cover Chrome 50-69, because some versions are broken by SameSite=None
// Cover Chrome 50-69, because some versions are broken by SameSite=None,
// and none in this range require it.
// Note: this covers some pre-Chromium Edge versions,
// Note: this covers some pre-Chromium Edge versions,
// but pre-Chromium Edge does not require SameSite=None.
// Notes from Thinktecture:
// We can not validate this assumption, but we trust Microsofts
// evaluation. And overall not sending a SameSite value equals to the same
// behavior as SameSite=None for these old versions anyways.
if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
{
return true;
}
if (GetChromeVersion(userAgent) >= 80)
{
return true;
}
return false;
}
private static int GetChromeVersion(string userAgent)
{
try
{
return Convert.ToInt32(userAgent.Split("Chrome/")[1].Split('.')[0]);
}
catch (Exception)
{
return 0;
}
}
}
}
```
@ -173,7 +91,7 @@ Assume that your project name is *Acme.BookStore*. Then open `AcmeBookStoreWebMo
Add the following line to `ConfigureServices()` method.
```csharp
context.Services.ConfigureNonBreakingSameSiteCookies();
context.Services.AddSameSiteCookiePolicy(); // cookie policy to deal with temporary browser incompatibilities
```
### Step-3
@ -195,18 +113,14 @@ public override void OnApplicationInitialization(ApplicationInitializationContex
app.UseHsts();
}
app.UseCookiePolicy(); //<--- added this --->
app.UseCookiePolicy(); // added this, Before UseAuthentication or anything else that writes cookies.
//....
}
```
It's all! You are ready to go!
---
Referenced from https://www.thinktecture.com/en/identity/samesite/prepare-your-identityserver/
Referenced from https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/

6
docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/POST.md

@ -260,7 +260,7 @@ import { MatFormFieldModule } from "@angular/material/form-field";
import { MatInputModule } from "@angular/material/input";
import { MatSelectModule } from "@angular/material/select";
import { MatIconModule } from "@angular/material/icon";
import { MatNativeDateModule } from '@angular/material/core';
import { MatNativeDateModule } from "@angular/material/core";
@NgModule({
imports: [
@ -1576,6 +1576,10 @@ Final UI looks as shown below:
![Author With Books](./author-with-books.gif)
## The Source Code
You can download the source code from [here](https://github.com/abpframework/abp-samples/tree/master/AcmeBookStoreAngularMaterial).
## Conclusion
We implemented Angular Material Components to our angular application which was created with ABP Framework. There is no blocker case of using angular libraries with the ABP framework.

2
docs/en/Modules/Index.md

@ -2,7 +2,7 @@
ABP is a **modular application framework** which consists of dozens of **NuGet & NPM packages**. It also provides a complete infrastructure to build your own application modules which may have entities, services, database integration, APIs, UI components and so on.
There are **two types of modules.** They don't have any structural difference but categorized by functionality and purpose:
There are **two types of modules.** They don't have any structural difference but are categorized by functionality and purpose:
* [**Framework modules**](https://github.com/abpframework/abp/tree/master/framework/src): These are **core modules of the framework** like caching, emailing, theming, security, serialization, validation, EF Core integration, MongoDB integration... etc. They do not have application/business functionalities but makes your daily development easier by providing common infrastructure, integration and abstractions.
* [**Application modules**](https://github.com/abpframework/abp/tree/master/modules): These modules implement specific application/business functionalities like blogging, document management, identity management, tenant management... etc. They generally have their own entities, services, APIs and UI components.

2
docs/en/Modules/Setting-Management.md

@ -75,7 +75,7 @@ Setting values are cached using the [distributed cache](../Caching.md) system. A
## Setting Management Providers
Setting Management module is extensible, just like the [setting system](../Settings.md). You can extend it by defining setting management providers. There are 5 pre-built setting management providers registered by the order below:
Setting Management module is extensible, just like the [setting system](../Settings.md). You can extend it by defining setting management providers. There are 5 pre-built setting management providers registered it the following order:
* `DefaultValueSettingManagementProvider`: Gets the value from the default value of the setting definition. It can not set the default value since default values are hard-coded on the setting definition.
* `ConfigurationSettingManagementProvider`: Gets the value from the [IConfiguration service](../Configuration.md). It can not set the configuration value because it is not possible to change the configuration values on runtime.

2
docs/en/Text-Templating.md

@ -423,7 +423,7 @@ This example simply adds a header and footer to the template and renders the con
**3)** Configure the embedded resources in the `.csproj` file
* Add [Microsoft.Extensions.FileProviders.Embedded](https://www.nuget.org/packages/Microsoft.Extensions.FileProviders.Embedded) NuGet package to the project.
* Add `<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>` into the `<PropertyConfig>...</PropertyConfig>` section of your `.csproj` file.
* Add `<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>` into the `<PropertyGroup>...</PropertyGroup>` section of your `.csproj` file.
* Add the following code into your `.csproj` file:
````xml

28
docs/en/UI/Angular/Authorization.md

@ -0,0 +1,28 @@
# Authorization in Angular UI
OAuth is preconfigured in Angular application templates. So, when you start a project using the CLI (or Suite, for that matter), authorization already works. You can find **OAuth configuration** in the _environment.ts_ files.
```js
import { Config } from '@abp/ng.core';
const baseUrl = 'http://localhost:4200';
export const environment = {
// other options removed for sake of brevity
oAuthConfig: {
issuer: 'https://localhost:44305',
redirectUri: baseUrl,
clientId: 'MyProjectName_App',
responseType: 'code',
scope: 'offline_access MyProjectName',
},
// other options removed for sake of brevity
} as Config.Environment;
```
This configuration results in an [OAuth authorization code flow with PKCE](https://tools.ietf.org/html/rfc7636) and we are using [angular-oauth2-oidc library](https://github.com/manfredsteyer/angular-oauth2-oidc#logging-in) for managing OAuth in the Angular client.
According to this flow, the user is redirected to an external login page which is built with MVC. So, if you need **to customize the login page**, please follow [this community article](https://community.abp.io/articles/how-to-customize-the-login-page-for-mvc-razor-page-applications-9a40f3cd).

10
docs/en/UI/Angular/Multi-Tenancy.md

@ -1,4 +1,4 @@
# Multi Tenancy in Angular UI
# Multi-Tenancy in Angular UI
ABP Angular UI supports the multi-tenancy. The following features related to multi-tenancy are available in the startup templates.
@ -8,7 +8,7 @@ ABP Angular UI supports the multi-tenancy. The following features related to mul
On the page above, you can;
- See the all tenants.
- See all tenants.
- Create a new tenant.
- Edit an existing tenant.
- Delete a tenant.
@ -17,9 +17,11 @@ On the page above, you can;
<p style="font-size:small;text-align:center;">Tenant Switching Component</p>
You can switch between existing tenants by using the tenant switching component in the child pages of the `AccountLayoutComponent` (like Login page). Angular UI sends the selected tenant id to the backend as `__tenant` header on each request.
You can switch between existing tenants by using the tenant switching box in the child pages of the MVC Account Public Module (like Login page). Angular UI gets selected tenant from `application-configuration` response and sends the tenant id to the backend as `__tenant` header on each request.
## Domain Tenant Resolver
## Domain/Subdomain Tenant Resolver
> **Note:** If you are going to implement the steps below, you should also implement the domain/subdomain tenant resolver feature for the backend. See the [Domain/Subdomain Tenant Resolver section in Multi-Tenancy document](../../Multi-Tenancy#domain-subdomain-tenant-resolver) to learn the backend implementation.
Angular UI can get the tenant name from the app running URL. You can determine the current tenant by subdomain (like mytenant1.mydomain.com) or by the whole domain (like mytenant.com). To do this, you need to set the `application.baseUrl` property in the environment:

64
docs/en/UI/Angular/Page-Alerts.md

@ -0,0 +1,64 @@
# Page Alerts
A page alert is useful for displaying an important message to the user. The ABP Framework provides an easy way to show the following alert to the user.
![angular-page-alert-example](./images/page-alert-warning-example.png)
You can simply import `PageAlertService` from `@abp/ng.theme.shared` and utilize it as follows:
```typescript
import { PageAlertService } from '@abp/ng.theme.shared';
@Component({
// ...
})
export class MyComponent {
constructor(private service: PageAlertService) {}
showWarning() {
this.service.show({
type: 'warning',
message:
'We will have a service interruption between 02:00 AM and 04:00 AM at October 23, 2023!',
title: 'Service Interruption',
});
}
}
```
## `SHOW`
The method `show` accepts a single object that is type of `PageAlert`
```typescript
export interface PageAlert {
type: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'light' | 'dark';
message: string;
title?: string;
dismissible?: boolean;
messageLocalizationParams?: string[];
titleLocalizationParams?: string[];
}
```
* `type` (Required): Defines what type of alert will be shown
* `message` (Required): The message who will be shown, also works with localization as well.
* `title` (Optional): The title of the message. If it is not provided, the title will be hidden.
* `dismissible` (Optional): Default is `true`. If enabled, a button on the top right corner will be shown to the users so that they can dismiss the message.
* `messageLocalizationParams` and `titleLocalizationParams` (Optional): If the message and/or the title is a key for localization service and contains some parameters, these fields could be used to pass those parameters.
### An example with Localization
```typescript
this.service.show({
type: 'danger',
message: 'AbpAccount::PagerInfo{0}{1}{2}',
messageLocalizationParams: ['10', '20', '30'],
title: 'AbpAccount::EntityNotFoundErrorMessage',
titleLocalizationParams: ['Test', 'id123'],
});
```
![angular-page-alert-with-params-example](./images/page-alert-with-params-example.png)

377
docs/en/UI/Angular/Testing.md

@ -1,3 +1,376 @@
# Angular UI: Testing
# Unit Testing Angular UI
TODO
ABP Angular UI is tested like any other Angular application. So, [the guide here](https://angular.io/guide/testing) applies to ABP too. That said, we would like to point out some **unit testing topics specific to ABP Angular applications**.
## Setup
In Angular, unit tests use [Karma](https://karma-runner.github.io/) and [Jasmine](https://jasmine.github.io) by default. Although we like Jest more, we chose not to deviate from these defaults, so **the application template you download will have Karma and Jasmine preconfigured**. You can find the Karma configuration inside the _karma.conf.js_ file in the root folder. You don't have to do anything. Adding a spec file and running `npm test` will work.
## Basics
An over-simplified spec file looks like this:
```ts
import { CoreTestingModule } from "@abp/ng.core/testing";
import { ThemeBasicTestingModule } from "@abp/ng.theme.basic/testing";
import { ThemeSharedTestingModule } from "@abp/ng.theme.shared/testing";
import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing";
import { NgxValidateCoreModule } from "@ngx-validate/core";
import { MyComponent } from "./my.component";
describe("MyComponent", () => {
let fixture: ComponentFixture<MyComponent>;
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [MyComponent],
imports: [
CoreTestingModule.withConfig(),
ThemeSharedTestingModule.withConfig(),
ThemeBasicTestingModule.withConfig(),
NgxValidateCoreModule,
],
providers: [
/* mock providers here */
],
}).compileComponents();
})
);
beforeEach(() => {
fixture = TestBed.createComponent(MyComponent);
fixture.detectChanges();
});
it("should be initiated", () => {
expect(fixture.componentInstance).toBeTruthy();
});
});
```
If you take a look at the imports, you will notice that we have prepared some testing modules to replace built-in ABP modules. This is necessary for providing mocks for some features which otherwise would break your tests. Please remember to **use testing modules** and **call their `withConfig` static method**.
## Tips
### Angular Testing Library
Although you can test your code with Angular TestBed, you may find [Angular Testing Library](https://testing-library.com/docs/angular-testing-library/intro) a good alternative.
The simple example above can be written with Angular Testing Library as follows:
```ts
import { CoreTestingModule } from "@abp/ng.core/testing";
import { ThemeBasicTestingModule } from "@abp/ng.theme.basic/testing";
import { ThemeSharedTestingModule } from "@abp/ng.theme.shared/testing";
import { ComponentFixture } from "@angular/core/testing";
import { NgxValidateCoreModule } from "@ngx-validate/core";
import { render } from "@testing-library/angular";
import { MyComponent } from "./my.component";
describe("MyComponent", () => {
let fixture: ComponentFixture<MyComponent>;
beforeEach(async () => {
const result = await render(MyComponent, {
imports: [
CoreTestingModule.withConfig(),
ThemeSharedTestingModule.withConfig(),
ThemeBasicTestingModule.withConfig(),
NgxValidateCoreModule,
],
providers: [
/* mock providers here */
],
});
fixture = result.fixture;
});
it("should be initiated", () => {
expect(fixture.componentInstance).toBeTruthy();
});
});
```
Very similar, as you can see. The real difference kicks in when we use queries and fire events.
```ts
// other imports
import { getByLabelText, screen } from "@testing-library/angular";
import userEvent from "@testing-library/user-event";
describe("MyComponent", () => {
beforeEach(/* removed for sake of brevity */);
it("should display advanced filters", () => {
const filters = screen.getByTestId("author-filters");
const nameInput = getByLabelText(filters, /name/i) as HTMLInputElement;
expect(nameInput.offsetWidth).toBe(0);
const advancedFiltersBtn = screen.getByRole("link", { name: /advanced/i });
userEvent.click(advancedFiltersBtn);
expect(nameInput.offsetWidth).toBeGreaterThan(0);
userEvent.type(nameInput, "fooo{backspace}");
expect(nameInput.value).toBe("foo");
});
});
```
The **queries in Angular Testing Library follow practices for maintainable tests**, the user event package provides a **human-like interaction** with the DOM, and the library in general has **a clear API** that simplifies component testing. Please find some useful links below:
- [Queries](https://testing-library.com/docs/dom-testing-library/api-queries)
- [User Event](https://testing-library.com/docs/ecosystem-user-event)
- [Examples](https://github.com/testing-library/angular-testing-library/tree/master/apps/example-app/app/examples)
### Clearing DOM After Each Spec
One thing to remember is that Karma runs tests in real browser instances. That means, you will be able to see the result of your test code, but also have problems with components attached to the document body which may not get cleared after each test, even when you configure Karma to do so.
We have prepared a simple function with which you can clear any leftover DOM elements after each test.
```ts
// other imports
import { clearPage } from "@abp/ng.core/testing";
describe("MyComponent", () => {
let fixture: ComponentFixture<MyComponent>;
afterEach(() => clearPage(fixture));
beforeEach(async () => {
const result = await render(MyComponent, {
/* removed for sake of brevity */
});
fixture = result.fixture;
});
// specs here
});
```
Please make sure you use it because Karma will fail to remove dialogs otherwise and you will have multiple copies of modals, confirmation boxes, and alike.
### Waiting
Some components, modals, in particular, work off-detection-cycle. In other words, you cannot reach DOM elements inserted by these components immediately after opening them. Similarly, inserted elements are not immediately destroyed upon closing them.
For this purpose, we have prepared a `wait` function.
```ts
// other imports
import { wait } from "@abp/ng.core/testing";
describe("MyComponent", () => {
beforeEach(/* removed for sake of brevity */);
it("should open a modal", async () => {
const openModalBtn = screen.getByRole("button", { name: "Open Modal" });
userEvent.click(openModalBtn);
await wait(fixture);
const modal = screen.getByRole("dialog");
expect(modal).toBeTruthy();
/* wait again after closing the modal */
});
});
```
The `wait` function takes a second parameter, i.e. timeout (default: `0`). Try not to use it though. Using a timeout bigger than `0` is usually a signal that something is not quite right.
## Testing Example
Here is an example test suite. It doesn't cover all, but gives quite a good idea about what the testing experience will be like.
```ts
import { clearPage, CoreTestingModule, wait } from "@abp/ng.core/testing";
import { ThemeBasicTestingModule } from "@abp/ng.theme.basic/testing";
import { ThemeSharedTestingModule } from "@abp/ng.theme.shared/testing";
import { ComponentFixture } from "@angular/core/testing";
import {
NgbCollapseModule,
NgbDatepickerModule,
NgbDropdownModule,
} from "@ng-bootstrap/ng-bootstrap";
import { NgxValidateCoreModule } from "@ngx-validate/core";
import { CountryService } from "@proxy/countries";
import {
findByText,
getByLabelText,
getByRole,
getByText,
queryByRole,
render,
screen,
} from "@testing-library/angular";
import userEvent from "@testing-library/user-event";
import { BehaviorSubject, of } from "rxjs";
import { CountryComponent } from "./country.component";
const list$ = new BehaviorSubject({
items: [{ id: "ID_US", name: "United States of America" }],
totalCount: 1,
});
describe("Country", () => {
let fixture: ComponentFixture<CountryComponent>;
afterEach(() => clearPage(fixture));
beforeEach(async () => {
const result = await render(CountryComponent, {
imports: [
CoreTestingModule.withConfig(),
ThemeSharedTestingModule.withConfig(),
ThemeBasicTestingModule.withConfig(),
NgxValidateCoreModule,
NgbCollapseModule,
NgbDatepickerModule,
NgbDropdownModule,
],
providers: [
{
provide: CountryService,
useValue: {
getList: () => list$,
},
},
],
});
fixture = result.fixture;
});
it("should display advanced filters", () => {
const filters = screen.getByTestId("country-filters");
const nameInput = getByLabelText(filters, /name/i) as HTMLInputElement;
expect(nameInput.offsetWidth).toBe(0);
const advancedFiltersBtn = screen.getByRole("link", { name: /advanced/i });
userEvent.click(advancedFiltersBtn);
expect(nameInput.offsetWidth).toBeGreaterThan(0);
userEvent.type(nameInput, "fooo{backspace}");
expect(nameInput.value).toBe("foo");
userEvent.click(advancedFiltersBtn);
expect(nameInput.offsetWidth).toBe(0);
});
it("should have a heading", () => {
const heading = screen.getByRole("heading", { name: "Countries" });
expect(heading).toBeTruthy();
});
it("should render list in table", async () => {
const table = await screen.findByTestId("country-table");
const name = getByText(table, "United States of America");
expect(name).toBeTruthy();
});
it("should display edit modal", async () => {
const actionsBtn = screen.queryByRole("button", { name: /actions/i });
userEvent.click(actionsBtn);
const editBtn = screen.getByRole("button", { name: /edit/i });
userEvent.click(editBtn);
await wait(fixture);
const modal = screen.getByRole("dialog");
const modalHeading = queryByRole(modal, "heading", { name: /edit/i });
expect(modalHeading).toBeTruthy();
const closeBtn = getByText(modal, "×");
userEvent.click(closeBtn);
await wait(fixture);
expect(screen.queryByRole("dialog")).toBeFalsy();
});
it("should display create modal", async () => {
const newBtn = screen.getByRole("button", { name: /new/i });
userEvent.click(newBtn);
await wait(fixture);
const modal = screen.getByRole("dialog");
const modalHeading = queryByRole(modal, "heading", { name: /new/i });
expect(modalHeading).toBeTruthy();
});
it("should validate required name field", async () => {
const newBtn = screen.getByRole("button", { name: /new/i });
userEvent.click(newBtn);
await wait(fixture);
const modal = screen.getByRole("dialog");
const nameInput = getByRole(modal, "textbox", {
name: /^name/i,
}) as HTMLInputElement;
userEvent.type(nameInput, "x");
userEvent.type(nameInput, "{backspace}");
const nameError = await findByText(modal, /required/i);
expect(nameError).toBeTruthy();
});
it("should delete a country", () => {
const getSpy = spyOn(fixture.componentInstance.list, "get");
const deleteSpy = jasmine.createSpy().and.returnValue(of(null));
fixture.componentInstance.service.delete = deleteSpy;
const actionsBtn = screen.queryByRole("button", { name: /actions/i });
userEvent.click(actionsBtn);
const deleteBtn = screen.getByRole("button", { name: /delete/i });
userEvent.click(deleteBtn);
const confirmText = screen.getByText("AreYouSure");
expect(confirmText).toBeTruthy();
const confirmBtn = screen.getByRole("button", { name: "Yes" });
userEvent.click(confirmBtn);
expect(deleteSpy).toHaveBeenCalledWith(list$.value.items[0].id);
expect(getSpy).toHaveBeenCalledTimes(1);
});
});
```
## CI Configuration
You would need a different configuration for your CI environment. To set up a new configuration for your unit tests, find the test project in _angular.json_ file and add one as seen below:
```json
// angular.json
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": { /* several options here */ },
"configurations": {
"production": {
"karmaConfig": "karma.conf.prod.js"
}
}
}
```
Now you can copy the _karma.conf.js_ as _karma.conf.prod.js_ and use any configuration you like in it. Please check [Karma configuration file document](http://karma-runner.github.io/5.2/config/configuration-file.html) for config options.
Finally, don't forget to run your CI tests with the following command:
```sh
npm test -- --prod
```

BIN
docs/en/UI/Angular/images/page-alert-warning-example.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
docs/en/UI/Angular/images/page-alert-with-params-example.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

12
docs/en/docs-nav.json

@ -740,6 +740,10 @@
{
"text": "PWA Configuration",
"path": "UI/Angular/PWA-Configuration.md"
},
{
"text": "Unit Testing",
"path": "UI/Angular/Testing.md"
}
]
},
@ -750,6 +754,10 @@
"text": "Config State Service",
"path": "UI/Angular/Config-State-Service.md"
},
{
"text": "Authorization",
"path": "UI/Angular/Authorization.md"
},
{
"text": "HTTP Requests",
"path": "UI/Angular/HTTP-Requests.md"
@ -814,6 +822,10 @@
{
"text": "Toast Overlay",
"path": "UI/Angular/Toaster-Service.md"
},
{
"text": "Page Alerts",
"path": "UI/Angular/Page-Alerts.md"
}
]
},

2
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LanguageSwitch.razor

@ -21,7 +21,7 @@
private IReadOnlyList<LanguageInfo> _otherLanguages;
private LanguageInfo _currentLanguage;
protected async override Task OnInitializedAsync()
protected override async Task OnInitializedAsync()
{
var selectedLanguageName = await JsRuntime.InvokeAsync<string>(
"localStorage.getItem",

2
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor.cs

@ -13,7 +13,7 @@ namespace Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic
protected ApplicationMenu Menu { get; set; }
protected async override Task OnInitializedAsync()
protected override async Task OnInitializedAsync()
{
Menu = await MenuManager.GetAsync(StandardMenus.User);

2
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/NavMenu.razor.cs

@ -11,7 +11,7 @@ namespace Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic
protected ApplicationMenu Menu { get; set; }
protected async override Task OnInitializedAsync()
protected override async Task OnInitializedAsync()
{
Menu = await MenuManager.GetAsync(StandardMenus.Main);
}

2
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/NavToolbar.razor.cs

@ -12,7 +12,7 @@ namespace Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic
private List<RenderFragment> ToolbarItemRenders { get; set; } = new List<RenderFragment>();
protected async override Task OnInitializedAsync()
protected override async Task OnInitializedAsync()
{
var toolbar = await ToolbarManager.GetAsync(StandardToolbars.Main);

25
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Toolbars/ToolbarConfigurationContext.cs

@ -4,35 +4,19 @@ using JetBrains.Annotations;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming.Toolbars
{
public class ToolbarConfigurationContext : IToolbarConfigurationContext
{
public IServiceProvider ServiceProvider { get; }
private readonly object _serviceProviderLock = new object();
private TRef LazyGetRequiredService<TRef>(Type serviceType, ref TRef reference)
{
if (reference == null)
{
lock (_serviceProviderLock)
{
if (reference == null)
{
reference = (TRef)ServiceProvider.GetRequiredService(serviceType);
}
}
}
return reference;
}
private readonly IAbpLazyServiceProvider _lazyServiceProvider;
public IAuthorizationService AuthorizationService => LazyGetRequiredService(typeof(IAuthorizationService), ref _authorizationService);
private IAuthorizationService _authorizationService;
public IAuthorizationService AuthorizationService => _lazyServiceProvider.LazyGetRequiredService<IAuthorizationService>();
private IStringLocalizerFactory _stringLocalizerFactory;
public IStringLocalizerFactory StringLocalizerFactory => LazyGetRequiredService(typeof(IStringLocalizerFactory),ref _stringLocalizerFactory);
public IStringLocalizerFactory StringLocalizerFactory => _lazyServiceProvider.LazyGetRequiredService<IStringLocalizerFactory>();
public Toolbar Toolbar { get; }
@ -40,6 +24,7 @@ namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming.Toolbars
{
Toolbar = toolbar;
ServiceProvider = serviceProvider;
_lazyServiceProvider = ServiceProvider.GetRequiredService<IAbpLazyServiceProvider>();
}
public Task<bool> IsGrantedAsync(string policyName)

7
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/DomainTenantResolveContributor.cs

@ -25,7 +25,12 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
protected override Task<string> GetTenantIdOrNameFromHttpContextOrNullAsync(ITenantResolveContext context, HttpContext httpContext)
{
var hostName = httpContext.Request.Host.Host.RemovePreFix(ProtocolPrefixes);
if (!httpContext.Request.Host.HasValue)
{
return Task.FromResult<string>(null);
}
var hostName = httpContext.Request.Host.Value.RemovePreFix(ProtocolPrefixes);
var extractResult = FormattedStringValueExtracter.Extract(hostName, _domainFormat, ignoreCase: true);
context.Handled = true;

2
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/FormTenantResolveContributor.cs

@ -11,7 +11,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
public override string Name => ContributorName;
protected async override Task<string> GetTenantIdOrNameFromHttpContextOrNullAsync(ITenantResolveContext context, HttpContext httpContext)
protected override async Task<string> GetTenantIdOrNameFromHttpContextOrNullAsync(ITenantResolveContext context, HttpContext httpContext)
{
if (!httpContext.Request.HasFormContentType)
{

2
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/HttpTenantResolveContributerBase.cs

@ -10,7 +10,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
{
public abstract class HttpTenantResolveContributorBase : TenantResolveContributorBase
{
public async override Task ResolveAsync(ITenantResolveContext context)
public override async Task ResolveAsync(ITenantResolveContext context)
{
var httpContext = context.GetHttpContext();
if (httpContext == null)

2
framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo.Abp.AspNetCore.Mvc.Client.Common.csproj

@ -16,7 +16,9 @@
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc.Contracts\Volo.Abp.AspNetCore.Mvc.Contracts.csproj" />
<ProjectReference Include="..\Volo.Abp.Authorization\Volo.Abp.Authorization.csproj" />
<ProjectReference Include="..\Volo.Abp.Caching\Volo.Abp.Caching.csproj" />
<ProjectReference Include="..\Volo.Abp.Features\Volo.Abp.Features.csproj" />
<ProjectReference Include="..\Volo.Abp.Http.Client\Volo.Abp.Http.Client.csproj" />
<ProjectReference Include="..\Volo.Abp.Localization\Volo.Abp.Localization.csproj" />
</ItemGroup>

6
framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCommonModule.cs

@ -1,5 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Authorization;
using Volo.Abp.Caching;
using Volo.Abp.Features;
using Volo.Abp.Http.Client;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
@ -10,7 +12,9 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
typeof(AbpHttpClientModule),
typeof(AbpAspNetCoreMvcContractsModule),
typeof(AbpCachingModule),
typeof(AbpLocalizationModule)
typeof(AbpLocalizationModule),
typeof(AbpAuthorizationModule),
typeof(AbpFeaturesModule)
)]
public class AbpAspNetCoreMvcClientCommonModule : AbpModule
{

2
framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteFeatureChecker.cs

@ -13,7 +13,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
ConfigurationClient = configurationClient;
}
public async override Task<string> GetOrNullAsync(string name)
public override async Task<string> GetOrNullAsync(string name)
{
var configuration = await ConfigurationClient.GetAsync();
return configuration.Features.Values.GetOrDefault(name);

1
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj

@ -18,6 +18,7 @@
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc.Client.Common\Volo.Abp.AspNetCore.Mvc.Client.Common.csproj" />
<ProjectReference Include="..\Volo.Abp.EventBus\Volo.Abp.EventBus.csproj" />
</ItemGroup>
</Project>

6
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs

@ -1,9 +1,11 @@
using Volo.Abp.Modularity;
using Volo.Abp.EventBus;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
[DependsOn(
typeof(AbpAspNetCoreMvcClientCommonModule)
typeof(AbpAspNetCoreMvcClientCommonModule),
typeof(AbpEventBusModule)
)]
public class AbpAspNetCoreMvcClientModule : AbpModule
{

4
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs

@ -56,7 +56,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
async () => await Proxy.Service.GetAsync(),
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(120) //TODO: Should be configurable. Default value should be higher (5 mins would be good).
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(300) //TODO: Should be configurable.
}
);
@ -83,7 +83,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
protected virtual string CreateCacheKey()
{
return $"ApplicationConfiguration_{CurrentUser.Id?.ToString("N") ?? "Anonymous"}_{CultureInfo.CurrentUICulture.Name}";
return MvcCachedApplicationConfigurationClientHelper.CreateCacheKey(CurrentUser);
}
}
}

13
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClientHelper.cs

@ -0,0 +1,13 @@
using System.Globalization;
using Volo.Abp.Users;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
internal static class MvcCachedApplicationConfigurationClientHelper
{
public static string CreateCacheKey(ICurrentUser currentUser)
{
return $"ApplicationConfiguration_{currentUser.Id?.ToString("N") ?? "Anonymous"}_{CultureInfo.CurrentUICulture.Name}";
}
}
}

34
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCurrentApplicationConfigurationCacheResetEventHandler.cs

@ -0,0 +1,34 @@
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus;
using Volo.Abp.Users;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
public class MvcCurrentApplicationConfigurationCacheResetEventHandler :
ILocalEventHandler<CurrentApplicationConfigurationCacheResetEventData>,
ITransientDependency
{
protected ICurrentUser CurrentUser { get; }
protected IDistributedCache<ApplicationConfigurationDto> Cache { get; }
public MvcCurrentApplicationConfigurationCacheResetEventHandler(ICurrentUser currentUser,
IDistributedCache<ApplicationConfigurationDto> cache)
{
CurrentUser = currentUser;
Cache = cache;
}
public virtual async Task HandleEventAsync(CurrentApplicationConfigurationCacheResetEventData eventData)
{
await Cache.RemoveAsync(CreateCacheKey());
}
protected virtual string CreateCacheKey()
{
return MvcCachedApplicationConfigurationClientHelper.CreateCacheKey(CurrentUser);
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.csproj

@ -15,7 +15,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Ddd.Application\Volo.Abp.Ddd.Application.csproj" />
<ProjectReference Include="..\Volo.Abp.Ddd.Application.Contracts\Volo.Abp.Ddd.Application.Contracts.csproj" />
</ItemGroup>
</Project>

2
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcContractsModule.cs

@ -4,7 +4,7 @@ using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc
{
[DependsOn(
typeof(AbpDddApplicationModule)
typeof(AbpDddApplicationContractsModule)
)]
public class AbpAspNetCoreMvcContractsModule : AbpModule
{

10
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentApplicationConfigurationCacheResetEventData.cs

@ -0,0 +1,10 @@
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
{
/// <summary>
/// This event is used to invalidate current user's cached configuration.
/// </summary>
public class CurrentApplicationConfigurationCacheResetEventData
{
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbTagHelperService.cs

@ -8,7 +8,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Breadcrumb
{
public class AbpBreadcrumbTagHelperService : AbpTagHelperService<AbpBreadcrumbTagHelper>
{
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "nav";
output.Attributes.Add("aria-label", "breadcrumb");

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs

@ -19,7 +19,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Carousel
L = localizer;
}
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "div";

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs

@ -9,7 +9,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
{
public class AbpAccordionItemTagHelperService : AbpTagHelperService<AbpAccordionItemTagHelper>
{
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
SetRandomIdIfNotProvided();

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs

@ -17,7 +17,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
HtmlGenerator = htmlGenerator;
}
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
SetRandomIdIfNotProvided();

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs

@ -6,7 +6,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse
{
public class AbpCollapseBodyTagHelperService : AbpTagHelperService<AbpCollapseBodyTagHelper>
{
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "div";
output.Attributes.AddClass("collapse");

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs

@ -24,7 +24,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown
_serviceProvider = serviceProvider;
}
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var content = await output.GetChildContentAsync();

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs

@ -36,7 +36,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
_localizer = localizer;
}
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var list = InitilizeFormGroupContentsContext(context, output);

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs

@ -26,7 +26,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
_tagHelperLocalizer = tagHelperLocalizer;
}
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var (innerHtml, isCheckBox) = await GetFormInputGroupAsHtmlAsync(context, output);

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs

@ -36,7 +36,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
_stringLocalizerFactory = stringLocalizerFactory;
}
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var innerHtml = await GetFormInputGroupAsHtmlAsync(context, output);

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalTagHelperService.cs

@ -8,7 +8,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
{
public class AbpModalTagHelperService : AbpTagHelperService<AbpModalTagHelper>
{
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = null;

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs

@ -32,7 +32,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
_stringLocalizerFactory = stringLocalizerFactory;
}
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (TagHelper.Model.ShownItemsCount <= 0)
{

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabDropdownTagHelperService.cs

@ -9,7 +9,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
{
public class AbpTabDropdownTagHelperService : AbpTagHelperService<AbpTabDropdownTagHelper>
{
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (string.IsNullOrWhiteSpace(TagHelper.Name))
{

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabTagHelperService.cs

@ -9,7 +9,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
{
public class AbpTabTagHelperService : AbpTagHelperService<AbpTabTagHelper>
{
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
SetPlaceholderForNameIfNotProvided();

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabsTagHelperService.cs

@ -20,7 +20,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
HtmlGenerator = htmlGenerator;
}
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
SetRandomNameIfNotProvided();

30
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleConfigurationContext.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Localization;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
@ -13,35 +14,18 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
public IFileProvider FileProvider { get; }
public IServiceProvider ServiceProvider { get; }
private readonly IAbpLazyServiceProvider _lazyServiceProvider;
public BundleConfigurationContext(IServiceProvider serviceProvider, IFileProvider fileProvider)
{
Files = new List<string>();
ServiceProvider = serviceProvider;
_lazyServiceProvider = ServiceProvider.GetRequiredService<IAbpLazyServiceProvider>();
FileProvider = fileProvider;
}
public IServiceProvider ServiceProvider { get; }
private readonly object _serviceProviderLock = new object();
private TRef LazyGetRequiredService<TRef>(Type serviceType, ref TRef reference)
{
if (reference == null)
{
lock (_serviceProviderLock)
{
if (reference == null)
{
reference = (TRef)ServiceProvider.GetRequiredService(serviceType);
}
}
}
return reference;
}
private IOptions<AbpLocalizationOptions> _abpLocalizationOptions;
public AbpLocalizationOptions LocalizationOptions =>
LazyGetRequiredService(typeof(IOptions<AbpLocalizationOptions>), ref _abpLocalizationOptions).Value;
public AbpLocalizationOptions LocalizationOptions => _lazyServiceProvider.LazyGetRequiredService<IOptions<AbpLocalizationOptions>>().Value;
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelperService.cs

@ -16,7 +16,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
ResourceService = resourceService;
}
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var tagHelperItems = context.Items.GetOrDefault(AbpTagHelperConsts.ContextBundleItemListKey) as List<BundleTagHelperItem>;
if (tagHelperItems != null)

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleTagHelperService.cs

@ -16,7 +16,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
ResourceService = resourceService;
}
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
await ResourceService.ProcessAsync(
TagHelper.ViewContext,

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs

@ -38,7 +38,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
);
}
protected async override Task<IReadOnlyList<string>> GetBundleFilesAsync(string bundleName)
protected override async Task<IReadOnlyList<string>> GetBundleFilesAsync(string bundleName)
{
return await BundleManager.GetScriptBundleFilesAsync(bundleName);
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperStyleService.cs

@ -38,7 +38,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers
);
}
protected async override Task<IReadOnlyList<string>> GetBundleFilesAsync(string bundleName)
protected override async Task<IReadOnlyList<string>> GetBundleFilesAsync(string bundleName)
{
return await BundleManager.GetStyleBundleFilesAsync(bundleName);
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Views/Components/Themes/Shared/TagHelpers/AbpComponentDemoSectionTagHelper.cs

@ -28,7 +28,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.Views.Components.Themes.S
_guidGenerator = guidGenerator;
}
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = null;

29
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarConfigurationContext.cs

@ -5,35 +5,19 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Theming;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars
{
public class ToolbarConfigurationContext : IToolbarConfigurationContext
{
public IServiceProvider ServiceProvider { get; }
private readonly object _serviceProviderLock = new object();
private TRef LazyGetRequiredService<TRef>(Type serviceType, ref TRef reference)
{
if (reference == null)
{
lock (_serviceProviderLock)
{
if (reference == null)
{
reference = (TRef)ServiceProvider.GetRequiredService(serviceType);
}
}
}
return reference;
}
private readonly IAbpLazyServiceProvider _lazyServiceProvider;
public IAuthorizationService AuthorizationService => LazyGetRequiredService(typeof(IAuthorizationService), ref _authorizationService);
private IAuthorizationService _authorizationService;
public IAuthorizationService AuthorizationService => _lazyServiceProvider.LazyGetRequiredService<IAuthorizationService>();
private IStringLocalizerFactory _stringLocalizerFactory;
public IStringLocalizerFactory StringLocalizerFactory => LazyGetRequiredService(typeof(IStringLocalizerFactory),ref _stringLocalizerFactory);
public IStringLocalizerFactory StringLocalizerFactory => _lazyServiceProvider.LazyGetRequiredService<IStringLocalizerFactory>();
public ITheme Theme { get; }
@ -44,8 +28,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars
Theme = currentTheme;
Toolbar = toolbar;
ServiceProvider = serviceProvider;
_lazyServiceProvider = ServiceProvider.GetRequiredService<IAbpLazyServiceProvider>();
}
public Task<bool> IsGrantedAsync(string policyName)
{
return AuthorizationService.IsGrantedAsync(policyName);
@ -62,7 +47,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars
{
return StringLocalizerFactory.Create<T>();
}
[NotNull]
public IStringLocalizer GetLocalizer(Type resourceType)
{

87
framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs

@ -10,6 +10,7 @@ using System;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc.UI.Alerts;
using Volo.Abp.AspNetCore.Mvc.Validation;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
@ -24,67 +25,27 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.RazorPages
{
public abstract class AbpPageModel : PageModel
{
public IServiceProvider ServiceProvider { get; set; }
protected readonly object ServiceProviderLock = new object();
protected TService LazyGetRequiredService<TService>(ref TService reference)
=> LazyGetRequiredService(typeof(TService), ref reference);
public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
protected TRef LazyGetRequiredService<TRef>(Type serviceType, ref TRef reference)
{
if (reference == null)
{
lock (ServiceProviderLock)
{
if (reference == null)
{
reference = (TRef)ServiceProvider.GetRequiredService(serviceType);
}
}
}
return reference;
}
public IServiceProvider ServiceProvider { get; set; }
protected IClock Clock => LazyGetRequiredService(ref _clock);
private IClock _clock;
protected IClock Clock => LazyServiceProvider.LazyGetRequiredService<IClock>();
protected AlertList Alerts => AlertManager.Alerts;
protected IUnitOfWorkManager UnitOfWorkManager => LazyGetRequiredService(ref _unitOfWorkManager);
private IUnitOfWorkManager _unitOfWorkManager;
protected IUnitOfWorkManager UnitOfWorkManager => LazyServiceProvider.LazyGetRequiredService<IUnitOfWorkManager>();
protected Type ObjectMapperContext { get; set; }
protected IObjectMapper ObjectMapper
{
get
{
if (_objectMapper != null)
{
return _objectMapper;
}
if (ObjectMapperContext == null)
{
return LazyGetRequiredService(ref _objectMapper);
}
return LazyGetRequiredService(
typeof(IObjectMapper<>).MakeGenericType(ObjectMapperContext),
ref _objectMapper
);
}
}
private IObjectMapper _objectMapper;
protected IObjectMapper ObjectMapper => LazyServiceProvider.LazyGetService<IObjectMapper>(provider =>
ObjectMapperContext == null
? provider.GetRequiredService<IObjectMapper>()
: (IObjectMapper) provider.GetRequiredService(typeof(IObjectMapper<>).MakeGenericType(ObjectMapperContext)));
protected IGuidGenerator GuidGenerator => LazyGetRequiredService(ref _guidGenerator);
private IGuidGenerator _guidGenerator;
protected IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetService<IGuidGenerator>(SimpleGuidGenerator.Instance);
protected ILoggerFactory LoggerFactory => LazyGetRequiredService(ref _loggerFactory);
private ILoggerFactory _loggerFactory;
protected ILoggerFactory LoggerFactory => LazyServiceProvider.LazyGetRequiredService<ILoggerFactory>();
protected IStringLocalizerFactory StringLocalizerFactory => LazyGetRequiredService(ref _stringLocalizerFactory);
private IStringLocalizerFactory _stringLocalizerFactory;
protected IStringLocalizerFactory StringLocalizerFactory => LazyServiceProvider.LazyGetRequiredService<IStringLocalizerFactory>();
protected IStringLocalizer L
{
@ -103,31 +64,23 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.RazorPages
protected Type LocalizationResourceType { get; set; }
protected ICurrentUser CurrentUser => LazyGetRequiredService(ref _currentUser);
private ICurrentUser _currentUser;
protected ICurrentUser CurrentUser => LazyServiceProvider.LazyGetRequiredService<ICurrentUser>();
protected ICurrentTenant CurrentTenant => LazyGetRequiredService(ref _currentTenant);
private ICurrentTenant _currentTenant;
protected ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
protected ISettingProvider SettingProvider => LazyGetRequiredService(ref _settingProvider);
private ISettingProvider _settingProvider;
protected ISettingProvider SettingProvider => LazyServiceProvider.LazyGetRequiredService<ISettingProvider>();
protected IModelStateValidator ModelValidator => LazyGetRequiredService(ref _modelValidator);
private IModelStateValidator _modelValidator;
protected IModelStateValidator ModelValidator => LazyServiceProvider.LazyGetRequiredService<IModelStateValidator>();
protected IAuthorizationService AuthorizationService => LazyGetRequiredService(ref _authorizationService);
private IAuthorizationService _authorizationService;
protected IAuthorizationService AuthorizationService => LazyServiceProvider.LazyGetRequiredService<IAuthorizationService>();
protected IAlertManager AlertManager => LazyGetRequiredService(ref _alertManager);
private IAlertManager _alertManager;
protected IAlertManager AlertManager => LazyServiceProvider.LazyGetRequiredService<IAlertManager>();
protected IUnitOfWork CurrentUnitOfWork => UnitOfWorkManager?.Current;
protected ILogger Logger => _lazyLogger.Value;
private Lazy<ILogger> _lazyLogger => new Lazy<ILogger>(() => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance, true);
protected ILogger Logger => LazyServiceProvider.LazyGetService<ILogger>(provider => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance);
protected IAppUrlProvider AppUrlProvider => LazyGetRequiredService(ref _appUrlProvider);
private IAppUrlProvider _appUrlProvider;
protected IAppUrlProvider AppUrlProvider => LazyServiceProvider.LazyGetRequiredService<IAppUrlProvider>();
protected virtual NoContentResult NoContent() //TODO: Is that true to return empty result like that?
{

1
framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj

@ -21,6 +21,7 @@
<ProjectReference Include="..\Volo.Abp.ApiVersioning.Abstractions\Volo.Abp.ApiVersioning.Abstractions.csproj" />
<ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc.Contracts\Volo.Abp.AspNetCore.Mvc.Contracts.csproj" />
<ProjectReference Include="..\Volo.Abp.AspNetCore\Volo.Abp.AspNetCore.csproj" />
<ProjectReference Include="..\Volo.Abp.Ddd.Application\Volo.Abp.Ddd.Application.csproj" />
<ProjectReference Include="..\Volo.Abp.GlobalFeatures\Volo.Abp.GlobalFeatures.csproj" />
<ProjectReference Include="..\Volo.Abp.Localization\Volo.Abp.Localization.csproj" />
<ProjectReference Include="..\Volo.Abp.UI.Navigation\Volo.Abp.UI.Navigation.csproj" />

20
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpActionContextExtensions.cs

@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc
{
internal static class AbpActionContextExtensions
{
public static T GetRequiredService<T>(this FilterContext context)
where T : class
{
return context.HttpContext.RequestServices.GetRequiredService<T>();
}
public static T GetService<T>(this FilterContext context, T defaultValue = default)
where T : class
{
return context.HttpContext.RequestServices.GetService<T>() ?? defaultValue;
}
}
}

4
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs

@ -22,6 +22,7 @@ using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Localization;
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.Conventions;
@ -49,7 +50,8 @@ namespace Volo.Abp.AspNetCore.Mvc
typeof(AbpApiVersioningAbstractionsModule),
typeof(AbpAspNetCoreMvcContractsModule),
typeof(AbpUiNavigationModule),
typeof(AbpGlobalFeaturesModule)
typeof(AbpGlobalFeaturesModule),
typeof(AbpDddApplicationModule)
)]
public class AbpAspNetCoreMvcModule : AbpModule
{

86
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpController.cs

@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Aspects;
using Volo.Abp.AspNetCore.Mvc.Validation;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
using Volo.Abp.Guids;
using Volo.Abp.Localization;
@ -22,85 +23,41 @@ namespace Volo.Abp.AspNetCore.Mvc
{
public abstract class AbpController : Controller, IAvoidDuplicateCrossCuttingConcerns
{
public IServiceProvider ServiceProvider { get; set; }
protected readonly object ServiceProviderLock = new object();
protected TService LazyGetRequiredService<TService>(ref TService reference)
=> LazyGetRequiredService(typeof(TService), ref reference);
protected TRef LazyGetRequiredService<TRef>(Type serviceType, ref TRef reference)
{
if (reference == null)
{
lock (ServiceProviderLock)
{
if (reference == null)
{
reference = (TRef)ServiceProvider.GetRequiredService(serviceType);
}
}
}
public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
return reference;
}
public IServiceProvider ServiceProvider { get; set; }
protected IUnitOfWorkManager UnitOfWorkManager => LazyGetRequiredService(ref _unitOfWorkManager);
private IUnitOfWorkManager _unitOfWorkManager;
protected IUnitOfWorkManager UnitOfWorkManager => LazyServiceProvider.LazyGetRequiredService<IUnitOfWorkManager>();
protected Type ObjectMapperContext { get; set; }
protected IObjectMapper ObjectMapper
{
get
{
if (_objectMapper != null)
{
return _objectMapper;
}
protected IObjectMapper ObjectMapper => LazyServiceProvider.LazyGetService<IObjectMapper>(provider =>
ObjectMapperContext == null
? provider.GetRequiredService<IObjectMapper>()
: (IObjectMapper) provider.GetRequiredService(typeof(IObjectMapper<>).MakeGenericType(ObjectMapperContext)));
if (ObjectMapperContext == null)
{
return LazyGetRequiredService(ref _objectMapper);
}
protected IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetService<IGuidGenerator>(SimpleGuidGenerator.Instance);
return LazyGetRequiredService(
typeof(IObjectMapper<>).MakeGenericType(ObjectMapperContext),
ref _objectMapper
);
}
}
private IObjectMapper _objectMapper;
protected IGuidGenerator GuidGenerator => LazyGetRequiredService(ref _guidGenerator);
private IGuidGenerator _guidGenerator;
protected ILoggerFactory LoggerFactory => LazyGetRequiredService(ref _loggerFactory);
private ILoggerFactory _loggerFactory;
protected ILoggerFactory LoggerFactory => LazyServiceProvider.LazyGetRequiredService<ILoggerFactory>();
protected ILogger Logger => _lazyLogger.Value;
private Lazy<ILogger> _lazyLogger => new Lazy<ILogger>(() => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance, true);
protected ILogger Logger => LazyServiceProvider.LazyGetService<ILogger>(provider => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance);
protected ICurrentUser CurrentUser => LazyGetRequiredService(ref _currentUser);
private ICurrentUser _currentUser;
protected ICurrentUser CurrentUser => LazyServiceProvider.LazyGetRequiredService<ICurrentUser>();
protected ICurrentTenant CurrentTenant => LazyGetRequiredService(ref _currentTenant);
private ICurrentTenant _currentTenant;
protected ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
protected IAuthorizationService AuthorizationService => LazyGetRequiredService(ref _authorizationService);
private IAuthorizationService _authorizationService;
protected IAuthorizationService AuthorizationService => LazyServiceProvider.LazyGetRequiredService<IAuthorizationService>();
protected IUnitOfWork CurrentUnitOfWork => UnitOfWorkManager?.Current;
protected IClock Clock => LazyGetRequiredService(ref _clock);
private IClock _clock;
protected IClock Clock => LazyServiceProvider.LazyGetRequiredService<IClock>();
protected IModelStateValidator ModelValidator => LazyGetRequiredService(ref _modelValidator);
private IModelStateValidator _modelValidator;
protected IModelStateValidator ModelValidator => LazyServiceProvider.LazyGetRequiredService<IModelStateValidator>();
protected IFeatureChecker FeatureChecker => LazyGetRequiredService(ref _featureChecker);
private IFeatureChecker _featureChecker;
protected IFeatureChecker FeatureChecker => LazyServiceProvider.LazyGetRequiredService<IFeatureChecker>();
protected IStringLocalizerFactory StringLocalizerFactory => LazyGetRequiredService(ref _stringLocalizerFactory);
private IStringLocalizerFactory _stringLocalizerFactory;
protected IAppUrlProvider AppUrlProvider => LazyServiceProvider.LazyGetRequiredService<IAppUrlProvider>();
protected IStringLocalizerFactory StringLocalizerFactory => LazyServiceProvider.LazyGetRequiredService<IStringLocalizerFactory>();
protected IStringLocalizer L
{
@ -116,9 +73,6 @@ namespace Volo.Abp.AspNetCore.Mvc
}
private IStringLocalizer _localizer;
protected IAppUrlProvider AppUrlProvider => LazyGetRequiredService(ref _appUrlProvider);
private IAppUrlProvider _appUrlProvider;
protected Type LocalizationResource
{
get => _localizationResource;

47
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpViewComponent.cs

@ -1,55 +1,22 @@
using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
using Volo.Abp.ObjectMapping;
namespace Volo.Abp.AspNetCore.Mvc
{
public abstract class AbpViewComponent : ViewComponent
{
public IServiceProvider ServiceProvider { get; set; }
protected readonly object ServiceProviderLock = new object();
protected TService LazyGetRequiredService<TService>(ref TService reference)
=> LazyGetRequiredService(typeof(TService), ref reference);
protected TRef LazyGetRequiredService<TRef>(Type serviceType, ref TRef reference)
{
if (reference == null)
{
lock (ServiceProviderLock)
{
if (reference == null)
{
reference = (TRef)ServiceProvider.GetRequiredService(serviceType);
}
}
}
public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
return reference;
}
public IServiceProvider ServiceProvider { get; set; }
protected Type ObjectMapperContext { get; set; }
protected IObjectMapper ObjectMapper
{
get
{
if (_objectMapper != null)
{
return _objectMapper;
}
if (ObjectMapperContext == null)
{
return LazyGetRequiredService(ref _objectMapper);
}
return LazyGetRequiredService(
typeof(IObjectMapper<>).MakeGenericType(ObjectMapperContext),
ref _objectMapper
);
}
}
private IObjectMapper _objectMapper;
protected IObjectMapper ObjectMapper => LazyServiceProvider.LazyGetService<IObjectMapper>(provider =>
ObjectMapperContext == null
? provider.GetRequiredService<IObjectMapper>()
: (IObjectMapper) provider.GetRequiredService(typeof(IObjectMapper<>).MakeGenericType(ObjectMapperContext)));
}
}

21
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs

@ -12,17 +12,6 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing
{
public class AbpAuditActionFilter : IAsyncActionFilter, ITransientDependency
{
protected AbpAuditingOptions Options { get; }
private readonly IAuditingHelper _auditingHelper;
private readonly IAuditingManager _auditingManager;
public AbpAuditActionFilter(IOptions<AbpAuditingOptions> options, IAuditingHelper auditingHelper, IAuditingManager auditingManager)
{
Options = options.Value;
_auditingHelper = auditingHelper;
_auditingManager = auditingManager;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
if (!ShouldSaveAudit(context, out var auditLog, out var auditLogAction))
@ -63,7 +52,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing
auditLog = null;
auditLogAction = null;
if (!Options.IsEnabled)
var options = context.GetRequiredService<IOptions<AbpAuditingOptions>>().Value;
if (!options.IsEnabled)
{
return false;
}
@ -73,19 +63,20 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing
return false;
}
var auditLogScope = _auditingManager.Current;
var auditLogScope = context.GetRequiredService<IAuditingManager>().Current;
if (auditLogScope == null)
{
return false;
}
if (!_auditingHelper.ShouldSaveAudit(context.ActionDescriptor.GetMethodInfo(), true))
var auditingHelper = context.GetRequiredService<IAuditingHelper>();
if (!auditingHelper.ShouldSaveAudit(context.ActionDescriptor.GetMethodInfo(), true))
{
return false;
}
auditLog = auditLogScope.Log;
auditLogAction = _auditingHelper.CreateAuditLogAction(
auditLogAction = auditingHelper.CreateAuditLogAction(
auditLog,
context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType(),
context.ActionDescriptor.AsControllerActionDescriptor().MethodInfo,

25
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs

@ -12,22 +12,11 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing
{
public class AbpAuditPageFilter : IAsyncPageFilter, ITransientDependency
{
protected AbpAuditingOptions Options { get; }
private readonly IAuditingHelper _auditingHelper;
private readonly IAuditingManager _auditingManager;
public AbpAuditPageFilter(IOptions<AbpAuditingOptions> options, IAuditingHelper auditingHelper, IAuditingManager auditingManager)
{
Options = options.Value;
_auditingHelper = auditingHelper;
_auditingManager = auditingManager;
}
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{
return Task.CompletedTask;
}
public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next)
{
if (context.HandlerMethod == null || !ShouldSaveAudit(context, out var auditLog, out var auditLogAction))
@ -68,7 +57,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing
auditLog = null;
auditLogAction = null;
if (!Options.IsEnabled)
var options = context.GetRequiredService<IOptions<AbpAuditingOptions>>().Value;
if (!options.IsEnabled)
{
return false;
}
@ -78,19 +68,20 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing
return false;
}
var auditLogScope = _auditingManager.Current;
var auditLogScope = context.GetRequiredService<IAuditingManager>().Current;
if (auditLogScope == null)
{
return false;
}
if (!_auditingHelper.ShouldSaveAudit(context.HandlerMethod.MethodInfo, true))
var auditingHelper = context.GetRequiredService<IAuditingHelper>();
if (!auditingHelper.ShouldSaveAudit(context.HandlerMethod.MethodInfo, true))
{
return false;
}
auditLog = auditLogScope.Log;
auditLogAction = _auditingHelper.CreateAuditLogAction(
auditLogAction = auditingHelper.CreateAuditLogAction(
auditLog,
context.HandlerMethod.GetType(),
context.HandlerMethod.MethodInfo,
@ -100,4 +91,4 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing
return true;
}
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Content/RemoteStreamContentOutputFormatter.cs

@ -18,7 +18,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Content
return typeof(IRemoteStreamContent).IsAssignableFrom(type);
}
public async override Task WriteResponseBodyAsync(OutputFormatterWriteContext context)
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context)
{
var remoteStream = (IRemoteStreamContent)context.Object;
using (var stream = remoteStream.GetStream())

48
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs

@ -1,11 +1,10 @@
using System;
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
@ -19,27 +18,6 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling
{
public class AbpExceptionFilter : IAsyncExceptionFilter, ITransientDependency
{
public ILogger<AbpExceptionFilter> Logger { get; set; }
private readonly IExceptionToErrorInfoConverter _errorInfoConverter;
private readonly IHttpExceptionStatusCodeFinder _statusCodeFinder;
private readonly IJsonSerializer _jsonSerializer;
private readonly AbpExceptionHandlingOptions _exceptionHandlingOptions;
public AbpExceptionFilter(
IExceptionToErrorInfoConverter errorInfoConverter,
IHttpExceptionStatusCodeFinder statusCodeFinder,
IJsonSerializer jsonSerializer,
IOptions<AbpExceptionHandlingOptions> exceptionHandlingOptions)
{
_errorInfoConverter = errorInfoConverter;
_statusCodeFinder = statusCodeFinder;
_jsonSerializer = jsonSerializer;
_exceptionHandlingOptions = exceptionHandlingOptions.Value;
Logger = NullLogger<AbpExceptionFilter>.Instance;
}
public async Task OnExceptionAsync(ExceptionContext context)
{
if (!ShouldHandleException(context))
@ -78,9 +56,13 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling
//TODO: Trigger an AbpExceptionHandled event or something like that.
context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true");
context.HttpContext.Response.StatusCode = (int)_statusCodeFinder.GetStatusCode(context.HttpContext, context.Exception);
context.HttpContext.Response.StatusCode = (int) context
.GetRequiredService<IHttpExceptionStatusCodeFinder>()
.GetStatusCode(context.HttpContext, context.Exception);
var remoteServiceErrorInfo = _errorInfoConverter.Convert(context.Exception, _exceptionHandlingOptions.SendExceptionsDetailsToClients);
var exceptionHandlingOptions = context.GetRequiredService<IOptions<AbpExceptionHandlingOptions>>().Value;
var exceptionToErrorInfoConverter = context.GetRequiredService<IExceptionToErrorInfoConverter>();
var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, exceptionHandlingOptions.SendExceptionsDetailsToClients);
context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo));
@ -88,17 +70,15 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling
var remoteServiceErrorInfoBuilder = new StringBuilder();
remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------");
remoteServiceErrorInfoBuilder.AppendLine( _jsonSerializer.Serialize(remoteServiceErrorInfo, indented: true));
Logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString());
remoteServiceErrorInfoBuilder.AppendLine(context.GetRequiredService<IJsonSerializer>().Serialize(remoteServiceErrorInfo, indented: true));
var logger = context.GetService<ILogger<AbpExceptionFilter>>(NullLogger<AbpExceptionFilter>.Instance);
logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString());
Logger.LogException(context.Exception, logLevel);
logger.LogException(context.Exception, logLevel);
await context.HttpContext
.RequestServices
.GetRequiredService<IExceptionNotifier>()
.NotifyAsync(
new ExceptionNotificationContext(context.Exception)
);
await context.GetRequiredService<IExceptionNotifier>().NotifyAsync(new ExceptionNotificationContext(context.Exception));
context.Exception = null; //Handled!
}

45
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs

@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
@ -19,27 +18,6 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling
{
public class AbpExceptionPageFilter : IAsyncPageFilter, ITransientDependency
{
public ILogger<AbpExceptionPageFilter> Logger { get; set; }
private readonly IExceptionToErrorInfoConverter _errorInfoConverter;
private readonly IHttpExceptionStatusCodeFinder _statusCodeFinder;
private readonly IJsonSerializer _jsonSerializer;
private readonly AbpExceptionHandlingOptions _exceptionHandlingOptions;
public AbpExceptionPageFilter(
IExceptionToErrorInfoConverter errorInfoConverter,
IHttpExceptionStatusCodeFinder statusCodeFinder,
IJsonSerializer jsonSerializer,
IOptions<AbpExceptionHandlingOptions> exceptionHandlingOptions)
{
_errorInfoConverter = errorInfoConverter;
_statusCodeFinder = statusCodeFinder;
_jsonSerializer = jsonSerializer;
_exceptionHandlingOptions = exceptionHandlingOptions.Value;
Logger = NullLogger<AbpExceptionPageFilter>.Instance;
}
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{
return Task.CompletedTask;
@ -90,9 +68,13 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling
//TODO: Trigger an AbpExceptionHandled event or something like that.
context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true");
context.HttpContext.Response.StatusCode = (int)_statusCodeFinder.GetStatusCode(context.HttpContext, context.Exception);
context.HttpContext.Response.StatusCode = (int) context
.GetRequiredService<IHttpExceptionStatusCodeFinder>()
.GetStatusCode(context.HttpContext, context.Exception);
var remoteServiceErrorInfo = _errorInfoConverter.Convert(context.Exception, _exceptionHandlingOptions.SendExceptionsDetailsToClients);
var exceptionHandlingOptions = context.GetRequiredService<IOptions<AbpExceptionHandlingOptions>>().Value;
var exceptionToErrorInfoConverter = context.GetRequiredService<IExceptionToErrorInfoConverter>();
var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, exceptionHandlingOptions.SendExceptionsDetailsToClients);
context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo));
@ -100,17 +82,14 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling
var remoteServiceErrorInfoBuilder = new StringBuilder();
remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------");
remoteServiceErrorInfoBuilder.AppendLine( _jsonSerializer.Serialize(remoteServiceErrorInfo, indented: true));
Logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString());
remoteServiceErrorInfoBuilder.AppendLine(context.GetRequiredService<IJsonSerializer>().Serialize(remoteServiceErrorInfo, indented: true));
var logger = context.GetService<ILogger<AbpExceptionFilter>>(NullLogger<AbpExceptionFilter>.Instance);
logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString());
Logger.LogException(context.Exception, logLevel);
logger.LogException(context.Exception, logLevel);
await context.HttpContext
.RequestServices
.GetRequiredService<IExceptionNotifier>()
.NotifyAsync(
new ExceptionNotificationContext(context.Exception)
);
await context.GetRequiredService<IExceptionNotifier>().NotifyAsync(new ExceptionNotificationContext(context.Exception));
context.Exception = null; //Handled!
}

17
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeatureActionFilter.cs

@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Volo.Abp.Aspects;
@ -10,16 +9,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Features
{
public class AbpFeatureActionFilter : IAsyncActionFilter, ITransientDependency
{
private readonly IMethodInvocationFeatureCheckerService _methodInvocationAuthorizationService;
public AbpFeatureActionFilter(IMethodInvocationFeatureCheckerService methodInvocationAuthorizationService)
{
_methodInvocationAuthorizationService = methodInvocationAuthorizationService;
}
public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
if (!context.ActionDescriptor.IsControllerAction())
{
@ -31,9 +21,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Features
using (AbpCrossCuttingConcerns.Applying(context.Controller, AbpCrossCuttingConcerns.FeatureChecking))
{
await _methodInvocationAuthorizationService.CheckAsync(
new MethodInvocationFeatureCheckerContext(methodInfo)
);
var methodInvocationFeatureCheckerService = context.GetRequiredService<IMethodInvocationFeatureCheckerService>();
await methodInvocationFeatureCheckerService.CheckAsync(new MethodInvocationFeatureCheckerContext(methodInfo));
await next();
}

16
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeaturePageFilter.cs

@ -9,18 +9,11 @@ namespace Volo.Abp.AspNetCore.Mvc.Features
{
public class AbpFeaturePageFilter : IAsyncPageFilter, ITransientDependency
{
private readonly IMethodInvocationFeatureCheckerService _methodInvocationAuthorizationService;
public AbpFeaturePageFilter(IMethodInvocationFeatureCheckerService methodInvocationAuthorizationService)
{
_methodInvocationAuthorizationService = methodInvocationAuthorizationService;
}
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{
return Task.CompletedTask;
}
public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next)
{
if (context.HandlerMethod == null || !context.ActionDescriptor.IsPageAction())
@ -33,12 +26,11 @@ namespace Volo.Abp.AspNetCore.Mvc.Features
using (AbpCrossCuttingConcerns.Applying(context.HandlerInstance, AbpCrossCuttingConcerns.FeatureChecking))
{
await _methodInvocationAuthorizationService.CheckAsync(
new MethodInvocationFeatureCheckerContext(methodInfo)
);
var methodInvocationFeatureCheckerService = context.GetRequiredService<IMethodInvocationFeatureCheckerService>();
await methodInvocationFeatureCheckerService.CheckAsync(new MethodInvocationFeatureCheckerContext(methodInfo));
await next();
}
}
}
}
}

10
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeatureActionFilter.cs

@ -13,13 +13,6 @@ namespace Volo.Abp.AspNetCore.Mvc.GlobalFeatures
{
public class GlobalFeatureActionFilter : IAsyncActionFilter, ITransientDependency
{
public ILogger<GlobalFeatureActionFilter> Logger { get; set; }
public GlobalFeatureActionFilter()
{
Logger = NullLogger<GlobalFeatureActionFilter>.Instance;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
if (!context.ActionDescriptor.IsControllerAction())
@ -30,7 +23,8 @@ namespace Volo.Abp.AspNetCore.Mvc.GlobalFeatures
if (!IsGlobalFeatureEnabled(context.Controller.GetType(), out var attribute))
{
Logger.LogWarning($"The '{context.Controller.GetType().FullName}' controller needs to enable '{attribute.Name}' feature.");
var logger = context.GetService<ILogger<GlobalFeatureActionFilter>>(NullLogger<GlobalFeatureActionFilter>.Instance);
logger.LogWarning($"The '{context.Controller.GetType().FullName}' controller needs to enable '{attribute.Name}' feature.");
context.Result = new NotFoundResult();
return;
}

10
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeaturePageFilter.cs

@ -13,13 +13,6 @@ namespace Volo.Abp.AspNetCore.Mvc.GlobalFeatures
{
public class GlobalFeaturePageFilter: IAsyncPageFilter, ITransientDependency
{
public ILogger<GlobalFeaturePageFilter> Logger { get; set; }
public GlobalFeaturePageFilter()
{
Logger = NullLogger<GlobalFeaturePageFilter>.Instance;
}
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{
return Task.CompletedTask;
@ -35,7 +28,8 @@ namespace Volo.Abp.AspNetCore.Mvc.GlobalFeatures
if (!IsGlobalFeatureEnabled(context.HandlerInstance.GetType(), out var attribute))
{
Logger.LogWarning($"The '{context.HandlerInstance.GetType().FullName}' page needs to enable '{attribute.Name}' feature.");
var logger = context.GetService<ILogger<GlobalFeatureActionFilter>>(NullLogger<GlobalFeatureActionFilter>.Instance);
logger.LogWarning($"The '{context.HandlerInstance.GetType().FullName}' page needs to enable '{attribute.Name}' feature.");
context.Result = new NotFoundResult();
return;
}

15
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs

@ -8,8 +8,14 @@ namespace Volo.Abp.AspNetCore.Mvc.Json
{
public class AbpHybridJsonInputFormatter : TextInputFormatter, IInputFormatterExceptionPolicy
{
public AbpHybridJsonInputFormatter()
private readonly SystemTextJsonInputFormatter _systemTextJsonInputFormatter;
private readonly NewtonsoftJsonInputFormatter _newtonsoftJsonInputFormatter;
public AbpHybridJsonInputFormatter(SystemTextJsonInputFormatter systemTextJsonInputFormatter, NewtonsoftJsonInputFormatter newtonsoftJsonInputFormatter)
{
_systemTextJsonInputFormatter = systemTextJsonInputFormatter;
_newtonsoftJsonInputFormatter = newtonsoftJsonInputFormatter;
SupportedEncodings.Add(UTF8EncodingWithoutBOM);
SupportedEncodings.Add(UTF16EncodingLittleEndian);
@ -18,7 +24,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Json
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax);
}
public async override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
{
return await GetTextInputFormatter(context).ReadRequestBodyAsync(context, encoding);
}
@ -26,12 +32,13 @@ namespace Volo.Abp.AspNetCore.Mvc.Json
protected virtual TextInputFormatter GetTextInputFormatter(InputFormatterContext context)
{
var typesMatcher = context.HttpContext.RequestServices.GetRequiredService<AbpSystemTextJsonUnsupportedTypeMatcher>();
if (!typesMatcher.Match(context.ModelType))
{
return context.HttpContext.RequestServices.GetRequiredService<SystemTextJsonInputFormatter>();
return _systemTextJsonInputFormatter;
}
return context.HttpContext.RequestServices.GetRequiredService<NewtonsoftJsonInputFormatter>();
return _newtonsoftJsonInputFormatter;
}
public virtual InputFormatterExceptionPolicy ExceptionPolicy => InputFormatterExceptionPolicy.MalformedInputExceptions;

73
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOptionsSetup.cs

@ -0,0 +1,73 @@
using System.Buffers;
using System.Text.Encodings.Web;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.ObjectPool;
using Microsoft.Extensions.Options;
namespace Volo.Abp.AspNetCore.Mvc.Json
{
public class AbpHybridJsonOptionsSetup : IConfigureOptions<MvcOptions>
{
private readonly IOptions<JsonOptions> _jsonOptions;
private readonly IOptions<MvcNewtonsoftJsonOptions> _mvcNewtonsoftJsonOptions;
private readonly ILoggerFactory _loggerFactory;
private readonly ArrayPool<char> _charPool;
private readonly ObjectPoolProvider _objectPoolProvider;
public AbpHybridJsonOptionsSetup(
IOptions<JsonOptions> jsonOptions,
IOptions<MvcNewtonsoftJsonOptions> mvcNewtonsoftJsonOptions,
ILoggerFactory loggerFactory,
ArrayPool<char> charPool,
ObjectPoolProvider objectPoolProvider)
{
_jsonOptions = jsonOptions;
_mvcNewtonsoftJsonOptions = mvcNewtonsoftJsonOptions;
_loggerFactory = loggerFactory;
_charPool = charPool;
_objectPoolProvider = objectPoolProvider;
}
public void Configure(MvcOptions options)
{
var systemTextJsonInputFormatter = new SystemTextJsonInputFormatter(
_jsonOptions.Value,
_loggerFactory.CreateLogger<SystemTextJsonInputFormatter>());
var newtonsoftJsonInputFormatter = new NewtonsoftJsonInputFormatter(
_loggerFactory.CreateLogger<NewtonsoftJsonInputFormatter>(),
_mvcNewtonsoftJsonOptions.Value.SerializerSettings,
_charPool,
_objectPoolProvider,
options,
_mvcNewtonsoftJsonOptions.Value);
options.InputFormatters.RemoveType<SystemTextJsonInputFormatter>();
options.InputFormatters.RemoveType<NewtonsoftJsonInputFormatter>();
options.InputFormatters.Add(new AbpHybridJsonInputFormatter(systemTextJsonInputFormatter, newtonsoftJsonInputFormatter));
var jsonSerializerOptions = _jsonOptions.Value.JsonSerializerOptions;
if (jsonSerializerOptions.Encoder is null)
{
// If the user hasn't explicitly configured the encoder, use the less strict encoder that does not encode all non-ASCII characters.
jsonSerializerOptions = new JsonSerializerOptions(jsonSerializerOptions)
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
};
}
var systemTextJsonOutputFormatter = new SystemTextJsonOutputFormatter(jsonSerializerOptions);
var newtonsoftJsonOutputFormatter = new NewtonsoftJsonOutputFormatter(
_mvcNewtonsoftJsonOptions.Value.SerializerSettings,
_charPool,
options);
options.OutputFormatters.RemoveType<SystemTextJsonOutputFormatter>();
options.OutputFormatters.RemoveType<NewtonsoftJsonOutputFormatter>();
options.OutputFormatters.Add(new AbpHybridJsonOutputFormatter(systemTextJsonOutputFormatter, newtonsoftJsonOutputFormatter));
}
}
}

14
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs

@ -8,8 +8,14 @@ namespace Volo.Abp.AspNetCore.Mvc.Json
{
public class AbpHybridJsonOutputFormatter : TextOutputFormatter
{
public AbpHybridJsonOutputFormatter()
private readonly SystemTextJsonOutputFormatter _systemTextJsonOutputFormatter;
private readonly NewtonsoftJsonOutputFormatter _newtonsoftJsonOutputFormatter;
public AbpHybridJsonOutputFormatter(SystemTextJsonOutputFormatter systemTextJsonOutputFormatter, NewtonsoftJsonOutputFormatter newtonsoftJsonOutputFormatter)
{
_systemTextJsonOutputFormatter = systemTextJsonOutputFormatter;
_newtonsoftJsonOutputFormatter = newtonsoftJsonOutputFormatter;
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
@ -18,7 +24,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Json
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax);
}
public async override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
await GetTextInputFormatter(context).WriteResponseBodyAsync(context, selectedEncoding);
}
@ -28,10 +34,10 @@ namespace Volo.Abp.AspNetCore.Mvc.Json
var typesMatcher = context.HttpContext.RequestServices.GetRequiredService<AbpSystemTextJsonUnsupportedTypeMatcher>();
if (!typesMatcher.Match(context.ObjectType))
{
return context.HttpContext.RequestServices.GetRequiredService<SystemTextJsonOutputFormatter>();
return _systemTextJsonOutputFormatter;
}
return context.HttpContext.RequestServices.GetRequiredService<NewtonsoftJsonOutputFormatter>();
return _newtonsoftJsonOutputFormatter;
}
}
}

67
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs

@ -1,12 +1,7 @@
using System.Buffers;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using System.Text.Encodings.Web;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.ObjectPool;
using Volo.Abp.Json;
@ -24,68 +19,10 @@ namespace Volo.Abp.AspNetCore.Mvc.Json
return builder;
}
//SystemTextJsonInputFormatter
builder.Services.AddTransient(provider =>
{
var jsonOptions = provider.GetRequiredService<IOptions<JsonOptions>>();
var logger = provider.GetRequiredService<ILoggerFactory>().CreateLogger<SystemTextJsonInputFormatter>();
return new SystemTextJsonInputFormatter(jsonOptions.Value, logger);
});
builder.Services.TryAddTransient<DefaultObjectPoolProvider>();
//NewtonsoftJsonInputFormatter
builder.Services.AddTransient(provider =>
{
var jsonOptions = provider.GetRequiredService<IOptions<MvcNewtonsoftJsonOptions>>().Value;
return new NewtonsoftJsonInputFormatter(
provider.GetRequiredService<ILoggerFactory>().CreateLogger<NewtonsoftJsonInputFormatter>(),
jsonOptions.SerializerSettings,
provider.GetRequiredService<ArrayPool<char>>(),
provider.GetRequiredService<DefaultObjectPoolProvider>(),
provider.GetRequiredService<IOptions<MvcOptions>>().Value,
jsonOptions);
});
//SystemTextJsonOutputFormatter
builder.Services.AddTransient(provider =>
{
var jsonSerializerOptions = provider.GetRequiredService<IOptions<JsonOptions>>().Value.JsonSerializerOptions;
if (jsonSerializerOptions.Encoder is null)
{
// If the user hasn't explicitly configured the encoder, use the less strict encoder that does not encode all non-ASCII characters.
jsonSerializerOptions = new JsonSerializerOptions(jsonSerializerOptions)
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
};
}
return new SystemTextJsonOutputFormatter(jsonSerializerOptions);
});
//NewtonsoftJsonOutputFormatter
builder.Services.AddTransient(provider =>
{
var jsonOptions = provider.GetRequiredService<IOptions<MvcNewtonsoftJsonOptions>>().Value;
return new NewtonsoftJsonOutputFormatter(
jsonOptions.SerializerSettings,
provider.GetRequiredService<ArrayPool<char>>(),
provider.GetRequiredService<IOptions<MvcOptions>>().Value);
});
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<JsonOptions>, AbpJsonOptionsSetup>());
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<MvcNewtonsoftJsonOptions>, AbpMvcNewtonsoftJsonOptionsSetup>());
builder.Services.Configure<MvcOptions>(options =>
{
options.InputFormatters.RemoveType<SystemTextJsonInputFormatter>();
options.InputFormatters.RemoveType<NewtonsoftJsonInputFormatter>();
options.InputFormatters.Add(new AbpHybridJsonInputFormatter());
options.OutputFormatters.RemoveType<SystemTextJsonOutputFormatter>();
options.OutputFormatters.RemoveType<NewtonsoftJsonOutputFormatter>();
options.OutputFormatters.Add(new AbpHybridJsonOutputFormatter());
});
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, AbpHybridJsonOptionsSetup>());
return builder;
}
}

26
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs

@ -1,4 +1,4 @@
using System;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
@ -12,15 +12,6 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow
{
public class AbpUowActionFilter : IAsyncActionFilter, ITransientDependency
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly AbpUnitOfWorkDefaultOptions _defaultOptions;
public AbpUowActionFilter(IUnitOfWorkManager unitOfWorkManager, IOptions<AbpUnitOfWorkDefaultOptions> options)
{
_unitOfWorkManager = unitOfWorkManager;
_defaultOptions = options.Value;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
if (!context.ActionDescriptor.IsControllerAction())
@ -45,20 +36,22 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow
var options = CreateOptions(context, unitOfWorkAttr);
var unitOfWorkManager = context.GetRequiredService<IUnitOfWorkManager>();
//Trying to begin a reserved UOW by AbpUnitOfWorkMiddleware
if (_unitOfWorkManager.TryBeginReserved(UnitOfWork.UnitOfWorkReservationName, options))
if (unitOfWorkManager.TryBeginReserved(UnitOfWork.UnitOfWorkReservationName, options))
{
var result = await next();
if (!Succeed(result))
{
await RollbackAsync(context);
await RollbackAsync(context, unitOfWorkManager);
}
return;
}
//Begin a new, independent unit of work
using (var uow = _unitOfWorkManager.Begin(options))
using (var uow = unitOfWorkManager.Begin(options))
{
var result = await next();
if (Succeed(result))
@ -76,7 +69,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow
if (unitOfWorkAttribute?.IsTransactional == null)
{
options.IsTransactional = _defaultOptions.CalculateIsTransactional(
var abpUnitOfWorkDefaultOptions = context.GetRequiredService<IOptions<AbpUnitOfWorkDefaultOptions>>().Value;
options.IsTransactional = abpUnitOfWorkDefaultOptions.CalculateIsTransactional(
autoValue: !string.Equals(context.HttpContext.Request.Method, HttpMethod.Get.Method, StringComparison.OrdinalIgnoreCase)
);
}
@ -84,9 +78,9 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow
return options;
}
private async Task RollbackAsync(ActionExecutingContext context)
private async Task RollbackAsync(ActionExecutingContext context, IUnitOfWorkManager unitOfWorkManager)
{
var currentUow = _unitOfWorkManager.Current;
var currentUow = unitOfWorkManager.Current;
if (currentUow != null)
{
await currentUow.RollbackAsync(context.HttpContext.RequestAborted);

25
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs

@ -1,4 +1,4 @@
using System;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
@ -12,14 +12,6 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow
{
public class AbpUowPageFilter : IAsyncPageFilter, ITransientDependency
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly AbpUnitOfWorkDefaultOptions _defaultOptions;
public AbpUowPageFilter(IUnitOfWorkManager unitOfWorkManager, IOptions<AbpUnitOfWorkDefaultOptions> options)
{
_unitOfWorkManager = unitOfWorkManager;
_defaultOptions = options.Value;
}
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{
return Task.CompletedTask;
@ -49,20 +41,22 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow
var options = CreateOptions(context, unitOfWorkAttr);
var unitOfWorkManager = context.GetRequiredService<IUnitOfWorkManager>();
//Trying to begin a reserved UOW by AbpUnitOfWorkMiddleware
if (_unitOfWorkManager.TryBeginReserved(UnitOfWork.UnitOfWorkReservationName, options))
if (unitOfWorkManager.TryBeginReserved(UnitOfWork.UnitOfWorkReservationName, options))
{
var result = await next();
if (!Succeed(result))
{
await RollbackAsync(context);
await RollbackAsync(context, unitOfWorkManager);
}
return;
}
//Begin a new, independent unit of work
using (var uow = _unitOfWorkManager.Begin(options))
using (var uow = unitOfWorkManager.Begin(options))
{
var result = await next();
if (Succeed(result))
@ -80,7 +74,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow
if (unitOfWorkAttribute?.IsTransactional == null)
{
options.IsTransactional = _defaultOptions.CalculateIsTransactional(
var abpUnitOfWorkDefaultOptions = context.GetRequiredService<IOptions<AbpUnitOfWorkDefaultOptions>>().Value;
options.IsTransactional = abpUnitOfWorkDefaultOptions.CalculateIsTransactional(
autoValue: !string.Equals(context.HttpContext.Request.Method, HttpMethod.Get.Method, StringComparison.OrdinalIgnoreCase)
);
}
@ -88,9 +83,9 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow
return options;
}
private async Task RollbackAsync(PageHandlerExecutingContext context)
private async Task RollbackAsync(PageHandlerExecutingContext context, IUnitOfWorkManager unitOfWorkManager)
{
var currentUow = _unitOfWorkManager.Current;
var currentUow = unitOfWorkManager.Current;
if (currentUow != null)
{
await currentUow.RollbackAsync(context.HttpContext.RequestAborted);

9
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/AbpValidationActionFilter.cs

@ -7,13 +7,6 @@ namespace Volo.Abp.AspNetCore.Mvc.Validation
{
public class AbpValidationActionFilter : IAsyncActionFilter, ITransientDependency
{
private readonly IModelStateValidator _validator;
public AbpValidationActionFilter(IModelStateValidator validator)
{
_validator = validator;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
//TODO: Configuration to disable validation for controllers..?
@ -25,7 +18,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Validation
return;
}
_validator.Validate(context.ModelState);
context.GetRequiredService<IModelStateValidator>().Validate(context.ModelState);
await next();
}
}

87
framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpHub.cs

@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Timing;
@ -14,48 +15,23 @@ namespace Volo.Abp.AspNetCore.SignalR
{
public abstract class AbpHub : Hub
{
public IServiceProvider ServiceProvider { get; set; }
protected readonly object ServiceProviderLock = new object();
protected TService LazyGetRequiredService<TService>(ref TService reference)
=> LazyGetRequiredService(typeof(TService), ref reference);
protected TRef LazyGetRequiredService<TRef>(Type serviceType, ref TRef reference)
{
if (reference == null)
{
lock (ServiceProviderLock)
{
if (reference == null)
{
reference = (TRef)ServiceProvider.GetRequiredService(serviceType);
}
}
}
public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
return reference;
}
public IServiceProvider ServiceProvider { get; set; }
protected ILoggerFactory LoggerFactory => LazyGetRequiredService(ref _loggerFactory);
private ILoggerFactory _loggerFactory;
protected ILoggerFactory LoggerFactory => LazyServiceProvider.LazyGetService<ILoggerFactory>();
protected ILogger Logger => _lazyLogger.Value;
private Lazy<ILogger> _lazyLogger => new Lazy<ILogger>(() => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance, true);
protected ILogger Logger => LazyServiceProvider.LazyGetService<ILogger>(provider => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance);
protected ICurrentUser CurrentUser => LazyGetRequiredService(ref _currentUser);
private ICurrentUser _currentUser;
protected ICurrentUser CurrentUser => LazyServiceProvider.LazyGetService<ICurrentUser>();
protected ICurrentTenant CurrentTenant => LazyGetRequiredService(ref _currentTenant);
private ICurrentTenant _currentTenant;
protected ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetService<ICurrentTenant>();
protected IAuthorizationService AuthorizationService => LazyGetRequiredService(ref _authorizationService);
private IAuthorizationService _authorizationService;
protected IAuthorizationService AuthorizationService => LazyServiceProvider.LazyGetService<IAuthorizationService>();
protected IClock Clock => LazyGetRequiredService(ref _clock);
private IClock _clock;
protected IClock Clock => LazyServiceProvider.LazyGetService<IClock>();
protected IStringLocalizerFactory StringLocalizerFactory => LazyGetRequiredService(ref _stringLocalizerFactory);
private IStringLocalizerFactory _stringLocalizerFactory;
protected IStringLocalizerFactory StringLocalizerFactory => LazyServiceProvider.LazyGetService<IStringLocalizerFactory>();
protected IStringLocalizer L
{
@ -102,48 +78,23 @@ namespace Volo.Abp.AspNetCore.SignalR
public abstract class AbpHub<T> : Hub<T>
where T : class
{
public IServiceProvider ServiceProvider { get; set; }
protected readonly object ServiceProviderLock = new object();
protected TService LazyGetRequiredService<TService>(ref TService reference)
=> LazyGetRequiredService(typeof(TService), ref reference);
protected TRef LazyGetRequiredService<TRef>(Type serviceType, ref TRef reference)
{
if (reference == null)
{
lock (ServiceProviderLock)
{
if (reference == null)
{
reference = (TRef)ServiceProvider.GetRequiredService(serviceType);
}
}
}
public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
return reference;
}
public IServiceProvider ServiceProvider { get; set; }
protected ILoggerFactory LoggerFactory => LazyGetRequiredService(ref _loggerFactory);
private ILoggerFactory _loggerFactory;
protected ILoggerFactory LoggerFactory => LazyServiceProvider.LazyGetService<ILoggerFactory>();
protected ILogger Logger => _lazyLogger.Value;
private Lazy<ILogger> _lazyLogger => new Lazy<ILogger>(() => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance, true);
protected ILogger Logger => LazyServiceProvider.LazyGetService<ILogger>(provider => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance);
protected ICurrentUser CurrentUser => LazyGetRequiredService(ref _currentUser);
private ICurrentUser _currentUser;
protected ICurrentUser CurrentUser => LazyServiceProvider.LazyGetService<ICurrentUser>();
protected ICurrentTenant CurrentTenant => LazyGetRequiredService(ref _currentTenant);
private ICurrentTenant _currentTenant;
protected ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetService<ICurrentTenant>();
protected IAuthorizationService AuthorizationService => LazyGetRequiredService(ref _authorizationService);
private IAuthorizationService _authorizationService;
protected IAuthorizationService AuthorizationService => LazyServiceProvider.LazyGetService<IAuthorizationService>();
protected IClock Clock => LazyGetRequiredService(ref _clock);
private IClock _clock;
protected IClock Clock => LazyServiceProvider.LazyGetService<IClock>();
protected IStringLocalizerFactory StringLocalizerFactory => LazyGetRequiredService(ref _stringLocalizerFactory);
private IStringLocalizerFactory _stringLocalizerFactory;
protected IStringLocalizerFactory StringLocalizerFactory => LazyServiceProvider.LazyGetService<IStringLocalizerFactory>();
protected IStringLocalizer L
{

2
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs

@ -48,7 +48,7 @@ namespace Volo.Abp.AspNetCore.SecurityLog
WebClientInfoProvider = webClientInfoProvider;
}
protected async override Task<SecurityLogInfo> CreateAsync()
protected override async Task<SecurityLogInfo> CreateAsync()
{
var securityLogInfo = await base.CreateAsync();

48
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs

@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Aspects;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;
@ -9,16 +10,14 @@ namespace Volo.Abp.Auditing
{
public class AuditingInterceptor : AbpInterceptor, ITransientDependency
{
private readonly IAuditingHelper _auditingHelper;
private readonly IAuditingManager _auditingManager;
private readonly IServiceScopeFactory _serviceScopeFactory;
public AuditingInterceptor(IAuditingHelper auditingHelper, IAuditingManager auditingManager)
public AuditingInterceptor(IServiceScopeFactory serviceScopeFactory)
{
_auditingHelper = auditingHelper;
_auditingManager = auditingManager;
_serviceScopeFactory = serviceScopeFactory;
}
public async override Task InterceptAsync(IAbpMethodInvocation invocation)
public override async Task InterceptAsync(IAbpMethodInvocation invocation)
{
if (!ShouldIntercept(invocation, out var auditLog, out var auditLogAction))
{
@ -58,26 +57,31 @@ namespace Volo.Abp.Auditing
return false;
}
var auditLogScope = _auditingManager.Current;
if (auditLogScope == null)
using (var scope = _serviceScopeFactory.CreateScope())
{
return false;
}
var auditingManager = scope.ServiceProvider.GetRequiredService<IAuditingManager>();
var auditLogScope = auditingManager.Current;
if (auditLogScope == null)
{
return false;
}
if (!_auditingHelper.ShouldSaveAudit(invocation.Method))
{
return false;
}
var auditingHelper = scope.ServiceProvider.GetRequiredService<IAuditingHelper>();
if (!auditingHelper.ShouldSaveAudit(invocation.Method))
{
return false;
}
auditLog = auditLogScope.Log;
auditLogAction = _auditingHelper.CreateAuditLogAction(
auditLog,
invocation.TargetObject.GetType(),
invocation.Method,
invocation.Arguments
);
auditLog = auditLogScope.Log;
auditLogAction = auditingHelper.CreateAuditLogAction(
auditLog,
invocation.TargetObject.GetType(),
invocation.Method,
invocation.Arguments
);
return true;
return true;
}
}
}
}

2
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs

@ -23,7 +23,7 @@ namespace Volo.Abp.Authorization
_options = options.Value;
}
public async override Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
public override async Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
var policy = await base.GetPolicyAsync(policyName);
if (policy != null)

2
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AuthorizationInterceptor.cs

@ -13,7 +13,7 @@ namespace Volo.Abp.Authorization
_methodInvocationAuthorizationService = methodInvocationAuthorizationService;
}
public async override Task InterceptAsync(IAbpMethodInvocation invocation)
public override async Task InterceptAsync(IAbpMethodInvocation invocation)
{
await AuthorizeAsync(invocation);
await invocation.ProceedAsync();

10
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Localization/nl.json

@ -0,0 +1,10 @@
{
"culture": "nl",
"texts": {
"Volo.Authorization:010001": "Autorisatie mislukt! De benodigde policy is niet aan u verleend.",
"Volo.Authorization:010002": "Autorisatie mislukt! De benodigde policy: '{PolicyName}' is niet aan u verleend.",
"Volo.Authorization:010003": "Autorisatie mislukt! De benodigde policy is niet aan de opgegeven resource: '{ResourceName}' verleend.",
"Volo.Authorization:010004": "Autorisatie mislukt! De benodigde requirement is niet aan de opgegeven resource: '{ResourceName}' verleend.",
"Volo.Authorization:010005": "Autorisatie mislukt! De benodigde requirements zijn niet aan de opgegeven resource: '{ResourceName}' verleend."
}
}

4
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs

@ -36,7 +36,7 @@ namespace Volo.Abp.Authorization
{
return;
}
await _abpAuthorizationService.CheckAsync(authorizationPolicy);
}
@ -64,4 +64,4 @@ namespace Volo.Abp.Authorization
return attributes;
}
}
}
}

2
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/PermissionRequirementHandler.cs

@ -13,7 +13,7 @@ namespace Volo.Abp.Authorization
_permissionChecker = permissionChecker;
}
protected async override Task HandleRequirementAsync(
protected override async Task HandleRequirementAsync(
AuthorizationHandlerContext context,
PermissionRequirement requirement)
{

4
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/ClientPermissionValueProvider.cs

@ -19,7 +19,7 @@ namespace Volo.Abp.Authorization.Permissions
CurrentTenant = currentTenant;
}
public async override Task<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context)
public override async Task<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context)
{
var clientId = context.Principal?.FindFirst(AbpClaimTypes.ClientId)?.Value;
@ -36,7 +36,7 @@ namespace Volo.Abp.Authorization.Permissions
}
}
public async override Task<MultiplePermissionGrantResult> CheckAsync(PermissionValuesCheckContext context)
public override async Task<MultiplePermissionGrantResult> CheckAsync(PermissionValuesCheckContext context)
{
var permissionNames = context.Permissions.Select(x => x.Name).ToArray();

4
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RolePermissionValueProvider.cs

@ -17,7 +17,7 @@ namespace Volo.Abp.Authorization.Permissions
}
public async override Task<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context)
public override async Task<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context)
{
var roles = context.Principal?.FindAll(AbpClaimTypes.Role).Select(c => c.Value).ToArray();
@ -37,7 +37,7 @@ namespace Volo.Abp.Authorization.Permissions
return PermissionGrantResult.Undefined;
}
public async override Task<MultiplePermissionGrantResult> CheckAsync(PermissionValuesCheckContext context)
public override async Task<MultiplePermissionGrantResult> CheckAsync(PermissionValuesCheckContext context)
{
var permissionNames = context.Permissions.Select(x => x.Name).ToList();
var result = new MultiplePermissionGrantResult(permissionNames.ToArray());

4
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/UserPermissionValueProvider.cs

@ -16,7 +16,7 @@ namespace Volo.Abp.Authorization.Permissions
}
public async override Task<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context)
public override async Task<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context)
{
var userId = context.Principal?.FindFirst(AbpClaimTypes.UserId)?.Value;
@ -30,7 +30,7 @@ namespace Volo.Abp.Authorization.Permissions
: PermissionGrantResult.Undefined;
}
public async override Task<MultiplePermissionGrantResult> CheckAsync(PermissionValuesCheckContext context)
public override async Task<MultiplePermissionGrantResult> CheckAsync(PermissionValuesCheckContext context)
{
var permissionNames = context.Permissions.Select(x => x.Name).ToArray();

2
framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs

@ -30,7 +30,7 @@ namespace Volo.Abp.BackgroundJobs
Timer.Period = WorkerOptions.JobPollPeriod;
}
protected async override Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
{
var store = workerContext.ServiceProvider.GetRequiredService<IBackgroundJobStore>();

4
framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs

@ -22,13 +22,13 @@ namespace Volo.Abp.BackgroundWorkers
Timer.Elapsed = Timer_Elapsed;
}
public async override Task StartAsync(CancellationToken cancellationToken = default)
public override async Task StartAsync(CancellationToken cancellationToken = default)
{
await base.StartAsync(cancellationToken);
Timer.Start(cancellationToken);
}
public async override Task StopAsync(CancellationToken cancellationToken = default)
public override async Task StopAsync(CancellationToken cancellationToken = default)
{
Timer.Stop(cancellationToken);
await base.StopAsync(cancellationToken);

29
framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerBase.cs

@ -1,9 +1,9 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BackgroundWorkers
{
@ -13,33 +13,14 @@ namespace Volo.Abp.BackgroundWorkers
public abstract class BackgroundWorkerBase : IBackgroundWorker
{
//TODO: Add UOW, Localization and other useful properties..?
public IServiceProvider ServiceProvider { get; set; }
protected readonly object ServiceProviderLock = new object();
protected TService LazyGetRequiredService<TService>(ref TService reference)
=> LazyGetRequiredService(typeof(TService), ref reference);
public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
protected TRef LazyGetRequiredService<TRef>(Type serviceType, ref TRef reference)
{
if (reference == null)
{
lock (ServiceProviderLock)
{
if (reference == null)
{
reference = (TRef)ServiceProvider.GetRequiredService(serviceType);
}
}
}
return reference;
}
public IServiceProvider ServiceProvider { get; set; }
protected ILoggerFactory LoggerFactory => LazyGetRequiredService(ref _loggerFactory);
private ILoggerFactory _loggerFactory;
protected ILoggerFactory LoggerFactory => LazyServiceProvider.LazyGetRequiredService<ILoggerFactory>();
protected ILogger Logger => _lazyLogger.Value;
private Lazy<ILogger> _lazyLogger => new Lazy<ILogger>(() => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance, true);
protected ILogger Logger => LazyServiceProvider.LazyGetService<ILogger>(provider => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance);
public virtual Task StartAsync(CancellationToken cancellationToken = default)
{

4
framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs

@ -25,13 +25,13 @@ namespace Volo.Abp.BackgroundWorkers
Timer.Elapsed += Timer_Elapsed;
}
public async override Task StartAsync(CancellationToken cancellationToken = default)
public override async Task StartAsync(CancellationToken cancellationToken = default)
{
await base.StartAsync(cancellationToken);
Timer.Start(cancellationToken);
}
public async override Task StopAsync(CancellationToken cancellationToken = default)
public override async Task StopAsync(CancellationToken cancellationToken = default)
{
Timer.Stop(cancellationToken);
await base.StopAsync(cancellationToken);

2
framework/src/Volo.Abp.BlazoriseUI/Components/EntityAction.razor.cs

@ -41,7 +41,7 @@ namespace Volo.Abp.BlazoriseUI.Components
[Inject]
protected IUiMessageService UiMessageService { get; set; }
protected async override Task OnInitializedAsync()
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
await SetDefaultValuesAsync();

6
framework/src/Volo.Abp.BlazoriseUI/Volo.Abp.BlazoriseUI.csproj

@ -12,9 +12,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Blazorise" Version="0.9.3-preview4" />
<PackageReference Include="Blazorise.DataGrid" Version="0.9.3-preview4" />
<PackageReference Include="Blazorise.Snackbar" Version="0.9.3-preview4" />
<PackageReference Include="Blazorise" Version="0.9.3-preview6" />
<PackageReference Include="Blazorise.DataGrid" Version="0.9.3-preview6" />
<PackageReference Include="Blazorise.Snackbar" Version="0.9.3-preview6" />
</ItemGroup>
</Project>

2
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs

@ -73,7 +73,7 @@ namespace Volo.Abp.BlobStoring.Aliyun
return Task.FromResult(BlobExists(ossClient, containerName, blobName));
}
public async override Task<Stream> GetOrNullAsync(BlobProviderGetArgs args)
public override async Task<Stream> GetOrNullAsync(BlobProviderGetArgs args)
{
var containerName = GetContainerName(args);
var blobName = AliyunBlobNameCalculator.Calculate(args);

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save