@ -0,0 +1,13 @@ |
|||
{ |
|||
"culture": "zh-Hant", |
|||
"texts": { |
|||
"Account": "帳號", |
|||
"Welcome": "歡迎", |
|||
"UseOneOfTheFollowingLinksToContinue": "使用下面的連結繼續", |
|||
"FrameworkHomePage": "框架首頁", |
|||
"FrameworkDocumentation": "框架文件", |
|||
"OfficialBlog": "官方部落格", |
|||
"CommercialHomePage": "商業版首頁", |
|||
"CommercialSupportWebSite": "商業版支援網站" |
|||
} |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
{ |
|||
"culture": "zh-Hant", |
|||
"texts": { |
|||
"Permission:NpmPackages": "NPM套件", |
|||
"Permission:NugetPackages": "Nuget套件", |
|||
"Permission:Maintenance": "維護", |
|||
"Permission:Maintain": "維護", |
|||
"Permission:ClearCaches": "清除快取", |
|||
"Permission:Modules": "模組", |
|||
"Permission:Packages": "套件", |
|||
"Permission:Edit": "編輯", |
|||
"Permission:Delete": "刪除", |
|||
"Permission:Create": "建立", |
|||
"Menu:Packages": "套件", |
|||
"NpmPackageDeletionWarningMessage": "該NPM套件將會被刪除. 你確定嗎?", |
|||
"NugetPackageDeletionWarningMessage": "該Nuget套件將會被刪除. 你確定嗎?", |
|||
"ModuleDeletionWarningMessage": "該模組將會被刪除. 你確定嗎?", |
|||
"Name": "名稱", |
|||
"DisplayName": "顯示名稱", |
|||
"ShortDescription": "簡述", |
|||
"NameFilter": "名稱", |
|||
"CreationTime": "建立時間", |
|||
"IsPro": "是否為專業版", |
|||
"EfCoreConfigureMethodName": "設定方法", |
|||
"IsProFilter": "是否為專業版", |
|||
"ApplicationType": "應用程式類型", |
|||
"Target": "目標", |
|||
"TargetFilter": "目標", |
|||
"ModuleClass": "模組分類", |
|||
"NugetPackageTarget.DomainShared": "Domain Shared", |
|||
"NugetPackageTarget.Domain": "Domain", |
|||
"NugetPackageTarget.Application": "Application", |
|||
"NugetPackageTarget.ApplicationContracts": "Application Contracts", |
|||
"NugetPackageTarget.HttpApi": "Http Api", |
|||
"NugetPackageTarget.HttpApiClient": "Http Api Client", |
|||
"NugetPackageTarget.Web": "Web", |
|||
"NugetPackageTarget.EntityFrameworkCore": "EntityFramework Core", |
|||
"NugetPackageTarget.MongoDB": "MongoDB", |
|||
"Edit": "編輯", |
|||
"Delete": "刪除", |
|||
"Refresh": "刷新", |
|||
"NpmPackages": "NPM套件", |
|||
"NugetPackages": "Nuget套件", |
|||
"NpmPackageCount": "NPM套件數量", |
|||
"NugetPackageCount": "Nuget套件數量", |
|||
"Module": "模組", |
|||
"ModuleInfo": "模組信息", |
|||
"CreateANpmPackage": "建立NPM套件", |
|||
"CreateAModule": "建立模組", |
|||
"CreateANugetPackage": "建立Nuget套件", |
|||
"AddNew": "建立", |
|||
"PackageAlreadyExist{0}": "\"{0}\"已經被添加.", |
|||
"ClearCache": "清除快取", |
|||
"SuccessfullyCleared": "清除成功", |
|||
"Menu:NpmPackages": "NPM套件", |
|||
"Menu:Modules": "模組", |
|||
"Menu:Maintenance": "維護", |
|||
"Menu:NugetPackages": "Nuget套件" |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
{ |
|||
"culture": "zh-Hant", |
|||
"texts": { |
|||
"Volo.AbpIo.Domain:010004": "超過最大成員數!", |
|||
"Volo.AbpIo.Domain:010005": "超過最大擁有者數!", |
|||
"Volo.AbpIo.Domain:010006": "使用者已經是該組織的擁有者!", |
|||
"Volo.AbpIo.Domain:010007": "該使用者已經是該組織的開發者!", |
|||
"Volo.AbpIo.Domain:010008": "允許的開發者數量不能低於當前開發者數量!", |
|||
"Volo.AbpIo.Domain:010009": "允許的開發者數量不能小於零!", |
|||
"Volo.AbpIo.Domain:010010": "超出了最大mac地址數!", |
|||
"Volo.AbpIo.Domain:010011": "個人許可不允許超過1個開發者!", |
|||
"Volo.AbpIo.Domain:010012": "許可過期後許可不可延長1個月!", |
|||
"Volo.AbpIo.Domain:020001": "不能刪除該NPM套件因為\"{NugetPackages}\"Nuget套件依賴此套件.", |
|||
"Volo.AbpIo.Domain:020002": "不能刪除該NPM套件因為\"{Modules}\"模組正在使用此套件.", |
|||
"Volo.AbpIo.Domain:020003": "不能刪除該NPM套件因為\"{Modules}\"模組正在使用此套件並且\"{NugetPackages}\"Nuget套件依賴此套件.", |
|||
"Volo.AbpIo.Domain:020004": "不能刪除該Nuget套件因為\"{Modules}\"模組正在使用此套件.", |
|||
"WantToLearn?": "想學習嗎?", |
|||
"ReadyToGetStarted?": "準備開始了嗎?", |
|||
"JoinOurCommunity": "加入我們的社群", |
|||
"GetStartedUpper": "開始", |
|||
"ForkMeOnGitHub": "Fork me on GitHub", |
|||
"Features": "功能", |
|||
"GetStarted": "開始", |
|||
"Documents": "文件", |
|||
"Community": "社群", |
|||
"ContributionGuide": "貢獻指南", |
|||
"Blog": "部落格", |
|||
"Commercial": "商業版", |
|||
"SeeDocuments": "查看文件" |
|||
} |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
{ |
|||
"culture": "zh-Hant", |
|||
"texts": { |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
{ |
|||
"culture": "zh-Hant", |
|||
"texts": { |
|||
"OrganizationManagement": "組織管理", |
|||
"OrganizationList": "組織列表", |
|||
"Volo.AbpIo.Commercial:010003": "您不是該組織的擁有者!", |
|||
"OrganizationNotFoundMessage": "找不到任何組織!", |
|||
"DeveloperCount": "開發者數量", |
|||
"Owners": "擁有者", |
|||
"AddMember": "加入成員", |
|||
"AddOwner": "加入擁有者", |
|||
"AddDeveloper": "加入開發者", |
|||
"UserName": "使用者名稱", |
|||
"Name": "名稱", |
|||
"EmailAddress": "電子信箱地址", |
|||
"Developers": "開發者", |
|||
"LicenseType": "許可證類型", |
|||
"Manage": "管理", |
|||
"StartDate": "開始日期", |
|||
"EndDate": "結束日期", |
|||
"Modules": "模組", |
|||
"LicenseExtendMessage": "您的許可已經延長至{0}", |
|||
"LicenseUpgradeMessage": "您的許可已升級為{0}", |
|||
"LicenseAddDeveloperMessage": "{0}個開發者已加入到您的許可", |
|||
"Volo.AbpIo.Commercial:010004": "不能找到指定的使用者! 使用者必須已經註冊.", |
|||
"MyOrganizations": "我的組織", |
|||
"ApiKey": "API key", |
|||
"UserNameNotFound": "沒有使用者名稱為{0}的使用者" |
|||
} |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
{ |
|||
"culture": "zh-Hant", |
|||
"texts": { |
|||
} |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
{ |
|||
"culture": "zh-Hant", |
|||
"texts": { |
|||
} |
|||
} |
|||
@ -0,0 +1,159 @@ |
|||
{ |
|||
"culture": "zh-Hant", |
|||
"texts": { |
|||
"GetStarted": "開始", |
|||
"Create": "建立", |
|||
"NewProject": "新專案", |
|||
"DirectDownload": "直接下載", |
|||
"ProjectName": "專案名稱", |
|||
"ProjectType": "專案類型", |
|||
"DatabaseProvider": "資料庫提供者", |
|||
"NTier": "N層", |
|||
"IncludeUserInterface": "包含使用者介面", |
|||
"CreateNow": "現在建立", |
|||
"TheStartupProject": "起始專案", |
|||
"Tutorial": "教學", |
|||
"UsingCLI": "使用CLI", |
|||
"SeeDetails": "看詳細", |
|||
"AbpShortDescription": "ABP是用於建立現代Web應用程式的完整架構和強大的基礎設施! 遵循最佳實作和約定,為您提供SOLID開發經驗.", |
|||
"SourceCodeUpper": "原始碼", |
|||
"LatestReleaseLogs": "最新發佈日誌", |
|||
"Infrastructure": "基礎設施", |
|||
"Architecture": "架構", |
|||
"Modular": "模組化", |
|||
"DontRepeatYourself": "不要重複工作", |
|||
"DeveloperFocused": "專注於開發者", |
|||
"FullStackApplicationInfrastructure": "全端應用程式基礎設施", |
|||
"DomainDrivenDesign": "領域驅動設計", |
|||
"DomainDrivenDesignExplanation": "依據DDD模式和準則進行設計和開發. 為您的應用程式提供分層模型.", |
|||
"Authorization": "授權", |
|||
"AuthorizationExplanation": "具有使用者,角色和細膩度權限系統的高級授權. 建立於Microsoft Identity套件上.", |
|||
"MultiTenancy": "多租戶", |
|||
"MultiTenancyExplanationShort": "SaaS應用程式變得簡單! 從資料庫到UI的多租戶整合.", |
|||
"CrossCuttingConcerns": "橫切關注點", |
|||
"CrossCuttingConcernsExplanationShort": "完整的基礎架構,用於授權,驗證,異常處理,快取,稽核日誌,交易管理等.", |
|||
"BuiltInBundlingMinification": "內建Bundling & Minification", |
|||
"BuiltInBundlingMinificationExplanation": "無須使用外部工具進行Bundling & Minification. ABP提供了一種更簡單,動態,功能強大,模組化和內建的方式!", |
|||
"VirtualFileSystem": "虛擬文件系統", |
|||
"VirtualFileSystemExplanation": "將檢視,腳本,樣式,圖片...嵌入到套件/類別庫中,並在不同的應用程式中重複使用.", |
|||
"Theming": "主題", |
|||
"ThemingExplanationShort": "使用和訂製基於bootstrap的標準UI主題,或建立自己的主題.", |
|||
"BootstrapTagHelpersDynamicForms": "Bootstrap Tag Helpers和動態表單", |
|||
"BootstrapTagHelpersDynamicFormsExplanation": "內建的背景作業系統可以整合到Hangfire,RabbitMQ或您喜歡的任何工具中.", //TODO explanation doesn't match. |
|||
"HTTPAPIsDynamicProxies": "HTTP APIs和動態代理", |
|||
"HTTPAPIsDynamicProxiesExplanation": "自動將應用程式服務公開為REST樣式的HTTP API,並與動態JavaScript和C#代理一起使用.", |
|||
"CompleteArchitectureInfo": "現在架構用來建立可維護的軟體解決方案.", |
|||
"DomainDrivenDesignBasedLayeringModelExplanation": "幫助您實現基於DDD的分層架構並建構可維護的程式碼.", |
|||
"DomainDrivenDesignBasedLayeringModelExplanationCont": "提供啟動模板,抽象,基礎類別,服務,文件和指南以幫助您開發基於DDD模式和準則的應用程式.", |
|||
"MicroserviceCompatibleModelExplanation": "核心框架和預先建構模組在設計時就考慮了微服務架構.", |
|||
"MicroserviceCompatibleModelExplanationCont": "提供基礎結構,整合,範例和文件,以更輕鬆地實現微服務解決方案,而如果您要使用整體應用程式,也不會帶來額外的複雜性.", |
|||
"ModularInfo": "ABP提供了完整的模組化系統,使您能夠開發可重複使用的應用程式模組.", |
|||
"PreBuiltModulesThemes": "預先建構模組和主題", |
|||
"PreBuiltModulesThemesExplanation": "開源和商業模組和主題已準備好在您的業務應用程式中使用.", |
|||
"NuGetNPMPackages": "NuGet和NPM套件", |
|||
"NuGetNPMPackagesExplanation": "作為NuGet和NPM套件發佈.易於安裝和升級.", |
|||
"ExtensibleReplaceable": "可擴展/可替換", |
|||
"ExtensibleReplaceableExplanation": "所有服務和模組在設計時都考慮了可擴展性.您可以替換服務,頁面,樣式,組件...", |
|||
"CrossCuttingConcernsExplanation2": "保持原始碼整潔,專注於您自己的業務邏輯.", |
|||
"CrossCuttingConcernsExplanation3": "不要浪費時間一次又一次地實作共通用的應用程式需求.", |
|||
"AuthenticationAuthorization": "認證與授權", |
|||
"ExceptionHandling": "異常處理", |
|||
"Validation": "驗證", |
|||
"DatabaseConnection": "資料庫連接", |
|||
"TransactionManagement": "交易管理", |
|||
"AuditLogging": "稽核日誌", |
|||
"Caching": "快取", |
|||
"Multitenancy": "多租戶", |
|||
"DataFiltering": "資料過濾", |
|||
"ConventionOverConfiguration": "習慣優於設定", |
|||
"ConventionOverConfigurationExplanation": "預設情況下,ABP使用最小或零設定實現共通用的應用程式.", |
|||
"ConventionOverConfigurationExplanationList1": "自動註冊已知服務以進行依賴注入.", |
|||
"ConventionOverConfigurationExplanationList2": "通過命名習慣將應用程式服務公開為HTTP API.", |
|||
"ConventionOverConfigurationExplanationList3": "為C#和JavaScript建立動態HTTP客戶端代理.", |
|||
"ConventionOverConfigurationExplanationList4": "為您的實體提供預設Repository.", |
|||
"ConventionOverConfigurationExplanationList5": "根據Web請求或應用程式服務方法管理工作單元.", |
|||
"ConventionOverConfigurationExplanationList6": "為實體發佈建立,更新和刪除事件.", |
|||
"BaseClasses": "基礎類別", |
|||
"BaseClassesExplanation": "共通用應用程式模式的預先建構基礎類別.", |
|||
"DeveloperFocusedExplanation": "ABP是為了開發者", |
|||
"DeveloperFocusedExplanationCont": "它旨在簡化您的日常軟體開發,同時又不限制您在需要時進行底層工作。", |
|||
"SeeAllFeatures": "瀏覽所有功能", |
|||
"CLI_CommandLineInterface": "CLI (命令列介面)", |
|||
"CLI_CommandLineInterfaceExplanation": "CLI會自動建立新專案並將模組添加到您的應用程式.", |
|||
"StartupTemplates": "起始模板", |
|||
"StartupTemplatesExplanation": "各種起始模板為您提供了完整設定的解結方案,以快速啟動您的開發.", |
|||
"BasedOnFamiliarTools": "基於熟悉的工具", |
|||
"BasedOnFamiliarToolsExplanation": "建立在您已經知道的主流工具上並與其整合.學習曲線低,適應性強,舒適的開發.", |
|||
"ORMIndependent": "ORM獨立", |
|||
"ORMIndependentExplanation": "核心框架獨立於ORM/資料庫,並且可以與任何資料庫一起使用.Entity Framework Core和MongoDB提供者已經可用.", |
|||
"Features": "功能", |
|||
"ABPCLI": "ABP CLI", |
|||
"Modularity": "模組化", |
|||
"BootstrapTagHelpers": "Bootstrap Tag Helpers", |
|||
"DynamicForms": "動態表單", |
|||
"BundlingMinification": "Bundling & Minification", |
|||
"BackgroundJobs": "背景作業", |
|||
"DDDInfrastructure": "DDD基礎設施", |
|||
"DomainDrivenDesignInfrastructure": "Domain Driven Design基礎設施", |
|||
"AutoRESTAPIs": "自動REST APIs", |
|||
"DynamicClientProxies": "動態客戶端代理", |
|||
"DistributedEventBus": "分散式事件匯流排", |
|||
"DistributedEventBusWithRabbitMQIntegration": "具有RabbitMQ整合的分散式事件匯流排", |
|||
"TestInfrastructure": "測試基礎設施", |
|||
"AuditLoggingEntityHistories": "稽核日誌和實體歷史", |
|||
"ObjectToObjectMapping": "物件對應", |
|||
"EmailSMSAbstractions": "電子郵件和簡訊抽象", |
|||
"EmailSMSAbstractionsWithTemplatingSupport": "具有模板支援的電子郵件和簡訊抽象", |
|||
"Localization": "本地化", |
|||
"SettingManagement": "設定管理", |
|||
"ExtensionMethods": "擴充方法", |
|||
"ExtensionMethodsHelpers": "擴充方法和助手", |
|||
"AspectOrientedProgramming": "切面導向設計", |
|||
"DependencyInjection": "依賴注入", |
|||
"DependencyInjectionByConventions": "依照習慣的依賴注入", |
|||
"ABPCLIExplanation": "ABP CLI(命令列介面)是用於對ABP解決方案執行常見操作的命令列工具.", |
|||
"ModularityExplanation": "ABP提供了一個完整的基礎設施來建構您自己的應用程式模組,這些模組可能具有實體,服務,資料庫整合,API,UI組件等.", //TODO: strong "your own application modules",- |
|||
"MultiTenancyExplanation": "ABP框建不僅支援開發多租戶應用程式,而且使您的程式碼幾乎無須知道多租戶.", |
|||
"MultiTenancyExplanation2": "可以自動確定當前租戶,將不同租戶的資料互相隔離.", |
|||
"MultiTenancyExplanation3": "支援單一資料庫,或每個租戶單獨資料庫或者混合方式.", |
|||
"MultiTenancyExplanation4": "您專注於業務邏輯,並讓該框架為您處理多租戶.", |
|||
"BootstrapTagHelpersExplanation": "與其手動撰寫重複細節的bootstrap組件,不如使用ABP的tag helper來簡化它並利用自動完成.您當然也可以在需要時直接使用Bootstrap.", |
|||
"DynamicFormsExplanation": "動態表單和tag helpers可以利用C#類別做為模型來建立完整的表單.", |
|||
"AuthenticationAuthorizationExplanation": "整合到ASP.NET Core Identity和IdentityServer4的豐富身份驗證和授權選項.提供可擴展且詳細的權限系統.", |
|||
"CrossCuttingConcernsExplanation": "部要重複資幾一次又一次地實作所有這寫常見的東西.專注於您的業務邏輯,並讓ABP按照習慣自動執行.", |
|||
"DatabaseConnectionTransactionManagement": "資料庫連接和交易管理", |
|||
"CorrelationIdTracking": "關聯ID追蹤", |
|||
"BundlingMinificationExplanation": "ABP提供了一個簡單,動態,功能強大,模組化的內建Bundling & Minification系統.", |
|||
"VirtualFileSystemnExplanation": "虛擬文件系統使管理文件系統(硬碟)上不存在的文件成為可能.它主要用於將(js,css,image,cshtml...)文件嵌入到組件(Assembly)中,並在運行時像實體文件一樣使用他們.", |
|||
"ThemingExplanation": "主題系統允許通過基於最新的Bootstrap框架定義一組通用基礎類別庫和佈局來獨立開發應用程式和模組主題.", |
|||
"DomainDrivenDesignInfrastructureExplanation": "基於領域驅動設計模式和準則建構分層應用程式的完整基礎設施;", |
|||
"Specification": "規範", |
|||
"Repository": "倉儲", |
|||
"DomainService": "領域服務", |
|||
"ValueObject": "值對象", |
|||
"ApplicationService": "應用服務", |
|||
"DataTransferObject": "資料傳輸對象", |
|||
"AggregateRootEntity": "聚合根, 實體", |
|||
"AutoRESTAPIsExplanation": "ABP可以依照習慣自動將您的應用服務設定為API控制器.", |
|||
"DynamicClientProxiesExplanation": "從JavaScript和C#客戶端輕鬆使用您的API.", |
|||
"DistributedEventBusWithRabbitMQIntegrationExplanation": "使用帶有RabbitMQ整合的內建分散式事件匯流排,可以輕鬆發佈和使用分散式事件.", |
|||
"TestInfrastructureExplanation": "框架已經考慮了單元和整合測試.為您提供基礎類別,使其更容易.起始模板已預先設定用於測試.", |
|||
"AuditLoggingEntityHistoriesExplanation": "針對關鍵業務應用的內建稽核日誌紀錄.請求,服務,方法級別的稽核日誌紀錄以及具有屬性級別詳細資訊的實體歷史紀錄.", |
|||
"EmailSMSAbstractionsWithTemplatingSupportExplanation": "IEmailSender和ISmsSender抽象使您的應用程式邏輯與基礎設施解耦.先進的電子郵件模板系統允許建立和在地化電子郵件模板,並在需要實輕鬆使用.", |
|||
"LocalizationExplanation": "在地化系統允許在純JSON文件中建立資源,並使用它們來在地化UI.它支援繼承,擴展和JavaScript整合等高級方案,同時與AspNet Core的在地化系統完全兼容.", |
|||
"SettingManagementExplanation": "定義應用程式的設定,並根據當前設定,租戶和使用者在運行時獲取值.", |
|||
"ExtensionMethodsHelpersExplanation": "即使式瑣碎的程式碼部分,也不要重複.標準類型的擴展方法和助手使您的程式碼更加清晰和易於撰寫.", |
|||
"AspectOrientedProgrammingExplanation": "提供合適的基礎設施來建立動態代理並實現切面導向設計.攔截任何類別,並在每次方法執行之前和之後執行程式碼.", |
|||
"DependencyInjectionByConventionsExplanation": "無須手動註冊類別以進行依賴注入.按照習慣自動註冊常用服務類型.對於其他類型的服務,您可以使用介面和屬性來使其變得更輕鬆.", |
|||
"DataFilteringExplanation": "定義和使用資料過濾器,這些過濾器在您從資料庫中查詢實體時會自動應用.當您實現簡單的介面時,可立即使用軟刪除功能和多租戶過濾器.", |
|||
"PublishEvents": "發佈事件", |
|||
"HandleEvents": "處理事件", |
|||
"AndMore": "更多...", |
|||
"Code": "編碼", |
|||
"Result": "結果", |
|||
"SeeTheDocumentForMoreInformation": "查看<a href=\"{1}\">{0} 文件</a>獲得更多訊息", |
|||
"IndexPageHeroSection": "<span class=\"third-line shine2\"><strong>asp.net core的</strong></span><span class=\"first-line shine\"><strong>開源</strong></span><span class=\"second-line text-uppercase\">Web應用程式<br />框架 </span>", |
|||
"UiFramework": "UI框架", |
|||
"EmailAddress": "電子信箱地址" |
|||
} |
|||
} |
|||
@ -1,40 +0,0 @@ |
|||
# COMMON PATHS |
|||
|
|||
$rootFolder = (Get-Item -Path "./" -Verbose).FullName |
|||
|
|||
# List of solutions |
|||
|
|||
$solutionPaths = ( |
|||
"framework", |
|||
"modules/users", |
|||
"modules/permission-management", |
|||
"modules/setting-management", |
|||
"modules/feature-management", |
|||
"modules/identity", |
|||
"modules/identityserver", |
|||
"modules/tenant-management", |
|||
"modules/account", |
|||
"modules/docs", |
|||
"modules/blogging", |
|||
"modules/audit-logging", |
|||
"modules/background-jobs", |
|||
"modules/client-simulation", |
|||
"templates/module/aspnet-core", |
|||
"templates/app/aspnet-core", |
|||
"abp_io/AbpIoLocalization" |
|||
) |
|||
|
|||
# Build all solutions |
|||
|
|||
foreach ($solutionPath in $solutionPaths) { |
|||
$solutionAbsPath = (Join-Path $rootFolder $solutionPath) |
|||
Set-Location $solutionAbsPath |
|||
dotnet build --configuration Release |
|||
if (-Not $?) { |
|||
Write-Host ("Build failed for the solution: " + $solutionPath) |
|||
Set-Location $rootFolder |
|||
exit $LASTEXITCODE |
|||
} |
|||
} |
|||
|
|||
Set-Location $rootFolder |
|||
@ -1,40 +0,0 @@ |
|||
# COMMON PATHS |
|||
|
|||
$rootFolder = (Get-Item -Path "./" -Verbose).FullName |
|||
|
|||
# List of solutions |
|||
|
|||
$solutionPaths = ( |
|||
"framework", |
|||
"modules/users", |
|||
"modules/permission-management", |
|||
"modules/setting-management", |
|||
"modules/feature-management", |
|||
"modules/identity", |
|||
"modules/identityserver", |
|||
"modules/tenant-management", |
|||
"modules/account", |
|||
"modules/docs", |
|||
"modules/blogging", |
|||
"modules/audit-logging", |
|||
"modules/background-jobs", |
|||
"modules/client-simulation", |
|||
"templates/module/aspnet-core", |
|||
"templates/app/aspnet-core", |
|||
"abp_io/AbpIoLocalization" |
|||
) |
|||
|
|||
# Build all solutions |
|||
|
|||
foreach ($solutionPath in $solutionPaths) { |
|||
$solutionAbsPath = (Join-Path $rootFolder $solutionPath) |
|||
Set-Location $solutionAbsPath |
|||
dotnet build |
|||
if (-Not $?) { |
|||
Write-Host ("Build failed for the solution: " + $solutionPath) |
|||
Set-Location $rootFolder |
|||
exit $LASTEXITCODE |
|||
} |
|||
} |
|||
|
|||
Set-Location $rootFolder |
|||
@ -0,0 +1,16 @@ |
|||
. ".\common.ps1" |
|||
|
|||
# Build all solutions |
|||
|
|||
foreach ($solutionPath in $solutionPaths) { |
|||
$solutionAbsPath = (Join-Path $rootFolder $solutionPath) |
|||
Set-Location $solutionAbsPath |
|||
dotnet build --configuration Release |
|||
if (-Not $?) { |
|||
Write-Host ("Build failed for the solution: " + $solutionPath) |
|||
Set-Location $rootFolder |
|||
exit $LASTEXITCODE |
|||
} |
|||
} |
|||
|
|||
Set-Location $rootFolder |
|||
@ -0,0 +1,16 @@ |
|||
. ".\common.ps1" |
|||
|
|||
# Build all solutions |
|||
|
|||
foreach ($solutionPath in $solutionPaths) { |
|||
$solutionAbsPath = (Join-Path $rootFolder $solutionPath) |
|||
Set-Location $solutionAbsPath |
|||
dotnet build |
|||
if (-Not $?) { |
|||
Write-Host ("Build failed for the solution: " + $solutionPath) |
|||
Set-Location $rootFolder |
|||
exit $LASTEXITCODE |
|||
} |
|||
} |
|||
|
|||
Set-Location $rootFolder |
|||
@ -0,0 +1,34 @@ |
|||
# COMMON PATHS |
|||
|
|||
$rootFolder = (Get-Item -Path "./" -Verbose).FullName |
|||
|
|||
# List of solutions |
|||
|
|||
$solutionPaths = ( |
|||
"../framework", |
|||
"../modules/users", |
|||
"../modules/permission-management", |
|||
"../modules/setting-management", |
|||
"../modules/feature-management", |
|||
"../modules/identity", |
|||
"../modules/identityserver", |
|||
"../modules/tenant-management", |
|||
"../modules/account", |
|||
"../modules/docs", |
|||
"../modules/blogging", |
|||
"../modules/audit-logging", |
|||
"../modules/background-jobs", |
|||
"../modules/client-simulation", |
|||
"../templates/module/aspnet-core", |
|||
"../templates/app/aspnet-core", |
|||
"../samples/BasicAspNetCoreApplication", |
|||
"../samples/BasicConsoleApplication", |
|||
"../samples/BookStore", |
|||
"../samples/BookStore-Angular-MongoDb/aspnet-core", |
|||
"../samples/BookStore-Modular/modules/book-management", |
|||
"../samples/BookStore-Modular/application", |
|||
"../samples/DashboardDemo", |
|||
"../samples/MicroserviceDemo", |
|||
"../samples/RabbitMqEventBus", |
|||
"../abp_io/AbpIoLocalization" |
|||
) |
|||
@ -0,0 +1,16 @@ |
|||
. ".\common.ps1" |
|||
|
|||
# Test all solutions |
|||
|
|||
foreach ($solutionPath in $solutionPaths) { |
|||
$solutionAbsPath = (Join-Path $rootFolder $solutionPath) |
|||
Set-Location $solutionAbsPath |
|||
dotnet test --no-build --no-restore |
|||
if (-Not $?) { |
|||
Write-Host ("Test failed for the solution: " + $solutionPath) |
|||
Set-Location $rootFolder |
|||
exit $LASTEXITCODE |
|||
} |
|||
} |
|||
|
|||
Set-Location $rootFolder |
|||
@ -0,0 +1,9 @@ |
|||
<Project> |
|||
<ItemGroup> |
|||
<PackageReference Include="ConfigureAwait.Fody" Version="3.3.1" /> |
|||
<PackageReference Include="Fody" Version="6.0.6"> |
|||
<PrivateAssets>all</PrivateAssets> |
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> |
|||
</PackageReference> |
|||
</ItemGroup> |
|||
</Project> |
|||
@ -1,74 +1,39 @@ |
|||
## Entity Framework Core PostgreSQL integrace |
|||
# Přepnutí na EF Core PostgreSQL providera |
|||
|
|||
> Podívejte se na [Entity Framework Core integrační dokument](../Entity-Framework-Core.md) pro základy integrace EF Core. |
|||
Tento dokument vysvětluje, jak přepnout na poskytovatele databáze **PostgreSQL** pro **[spouštěcí šablonu aplikace](Startup-Templates/Application.md)**, která je dodávána s předem nakonfigurovaným SQL poskytovatelem. |
|||
|
|||
### Aktualizace projektu EntityFrameworkCore |
|||
## Výměna balíku Volo.Abp.EntityFrameworkCore.SqlServer |
|||
|
|||
- V projektu `Acme.BookStore.EntityFrameworkCore` nahraďte balík `Volo.Abp.EntityFrameworkCore.SqlServer` za `Volo.Abp.EntityFrameworkCore.PostgreSql` |
|||
- Aktualizace pro použití PostgreSQL v `BookStoreEntityFrameworkCoreModule` |
|||
- Nahraďte `AbpEntityFrameworkCoreSqlServerModule` za `AbpEntityFrameworkCorePostgreSqlModule` |
|||
- Nahraďte `options.UseSqlServer()` za `options.UsePostgreSql()` |
|||
- V jiných projektech aktualizujte PostgreSQL connection string v nezbytných `appsettings.json` souborech |
|||
- Více informací v [PostgreSQL connection strings](https://www.connectionstrings.com/postgresql/), v tomto dokumentu věnujte pozornost sekci `Npgsql` |
|||
Projekt `.EntityFrameworkCore` v řešení závisí na NuGet balíku [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer). Odstraňte tento balík a přidejte stejnou verzi balíku [Volo.Abp.EntityFrameworkCore.PostgreSql](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.PostgreSql). |
|||
|
|||
### Aktualizace projektu EntityFrameworkCore.DbMigrations |
|||
- Aktualizace pro použití PostgreSQL v `XXXMigrationsDbContextFactory` |
|||
- Nahraďte `new DbContextOptionsBuilder<XXXMigrationsDbContext>().UseSqlServer()` za `new DbContextOptionsBuilder<XXXMigrationsDbContext>().UseNpgsql()` |
|||
## Nahrazení závislosti modulu |
|||
|
|||
Najděte třídu ***YourProjectName*EntityFrameworkCoreModule** v projektu `.EntityFrameworkCore`, odstraňte `typeof(AbpEntityFrameworkCoreSqlServerModule)` z atributu `DependsOn`, přidejte `typeof(AbpEntityFrameworkCorePostgreSqlModule)` (také nahraďte `using Volo.Abp.EntityFrameworkCore.SqlServer;` za `using Volo.Abp.EntityFrameworkCore.PostgreSql;`). |
|||
|
|||
### Odstranění stávajících migrací |
|||
## UsePostgreSql() |
|||
|
|||
Smažte všechny stavající migrační soubory (včetně `DbContextModelSnapshot`) |
|||
Najděte volání `UseSqlServer()` v *YourProjectName*EntityFrameworkCoreModule.cs uvnitř projektu `.EntityFrameworkCore` a nahraďte za `UsePostgreSql()`. |
|||
|
|||
 |
|||
Najděte volání `UseSqlServer()` v *YourProjectName*MigrationsDbContextFactory.cs uvnitř projektu `.EntityFrameworkCore.DbMigrations` a nahraďte za `UseNpgsql()`. |
|||
|
|||
### Znovu vygenerujte počáteční migraci |
|||
> V závislosti na struktuře řešení můžete najít více volání `UseSqlServer()`, které je třeba změnit. |
|||
|
|||
Nastavte správný spouštěcí projekt (obvykle web projekt) |
|||
## Změna connection stringů |
|||
|
|||
 |
|||
PostgreSql connection stringy se od těch pro SQL Server liší. Je proto potřeba zkontrolovat všechny soubory `appsettings.json` v řešení a connection stringy v nich nahradit. Podívejte se na [connectionstrings.com](https://www.connectionstrings.com/postgresql/) pro více detailů o možnostech PostgreSql connection stringů. |
|||
|
|||
Otevřete **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), zvolte `.EntityFrameworkCore.DbMigrations` jako **Default project** a proveďte následující příkaz: |
|||
Typicky je potřeba změnit `appsettings.json` v projektech `.DbMigrator` a `.Web` projects, ale to záleží na vaší struktuře řešení. |
|||
|
|||
Proveďte příkaz `Add-Migration`: |
|||
```` |
|||
PM> Add-Migration Initial |
|||
```` |
|||
## Regenerace migrací |
|||
|
|||
### Aktualizace databáze |
|||
Startovací šablona používá [Entity Framework Core Code First migrace](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core migrace závisí na zvoleném DBMS poskytovateli. Tudíž změna DBMS poskytovatele způsobí selhání migrace. |
|||
* Smažte složku Migrations v projektu `.EntityFrameworkCore.DbMigrations` and znovu sestavte řešení. |
|||
* Spusťte `Add-Migration "Initial"` v Package Manager Console (je nutné zvolit `.DbMigrator` (nebo `.Web`) projekt jako startovací projekt v Solution Explorer a zvolit projekt `.EntityFrameworkCore.DbMigrations` jako výchozí v Package Manager Console). |
|||
|
|||
K vytvoření databáze máte dvě možnosti. |
|||
Tímto vytvoříte migraci databáze se všemi nakonfigurovanými databázovými objekty (tabulkami). |
|||
|
|||
#### Použití DbMigrator aplikace |
|||
Spusťte projekt `.DbMigrator` k vytvoření databáze a vložení počátečních dat. |
|||
|
|||
Řešení obsahuje konzolovou aplikaci (v tomto příkladu nazvanou `Acme.BookStore.DbMigrator`), která může vytvářet databáze, aplikovat migrace a vkládat seed data. Je užitečná jak pro vývojové, tak pro produkční prostředí. |
|||
## Spuštění aplikace |
|||
|
|||
> Projekt `.DbMigrator` má vlastní `appsettings.json`. Takže pokud jste změnili connection string uvedený výše, musíte změnit také tento. |
|||
|
|||
Klikněte pravým na projekt `.DbMigrator` a vyberte **Set as StartUp Project**: |
|||
|
|||
 |
|||
|
|||
Zmáčkněte F5 (nebo Ctrl+F5) ke spuštění aplikace. Výstup bude vypadat následovně: |
|||
|
|||
 |
|||
|
|||
#### Použití EF Core Update-Database příkazu |
|||
|
|||
Ef Core má `Update-Database` příkaz, který v případě potřeby vytvoří databázi a aplikuje čekající migrace. |
|||
|
|||
Nastavte správný spouštěcí projekt (obvykle web projekt) |
|||
|
|||
 |
|||
|
|||
Otevřete **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), vyberte projekt `.EntityFrameworkCore.DbMigrations` jako **Default Project** and spusťte následující příkaz: |
|||
|
|||
```` |
|||
PM> Update-Database |
|||
```` |
|||
|
|||
Dojde k vytvoření nové databáze na základě nakonfigurovaného connection stringu. |
|||
|
|||
 |
|||
|
|||
> Použití nástroje `.DbMigrator` je doporučený způsob, jelikož zároveň vloží seed data nutné k správnému běhu webové aplikace. |
|||
Vše je připraveno. Stačí už jen spustit aplikaci a užívat si kódování. |
|||
|
|||
|
After Width: | Height: | Size: 9.4 KiB |
@ -0,0 +1,3 @@ |
|||
## Ambient Context Pattern |
|||
|
|||
TODO |
|||
@ -1,3 +1,372 @@ |
|||
# Audit Logging |
|||
|
|||
TODO |
|||
[Wikipedia](https://en.wikipedia.org/wiki/Audit_trail): "*An audit trail (also called **audit log**) is a security-relevant chronological record, set of records, and/or destination and source of records that provide documentary evidence of the sequence of activities that have affected at any time a specific operation, procedure, or event*". |
|||
|
|||
ABP Framework provides an **extensible audit logging system** that automates the audit logging by **convention** and provides **configuration** points to control the level of the audit logs. |
|||
|
|||
An **audit log object** (see the Audit Log Object section below) is typically created & saved per web request. It includes; |
|||
|
|||
* **Request & response details** (like URL, Http method, Browser info, HTTP status code... etc.). |
|||
* **Performed actions** (controller actions and application service method calls with their parameters). |
|||
* **Entity changes** occurred in the web request. |
|||
* **Exception** information (if there was an error while executing the request). |
|||
* **Request duration** (to measure the performance of the application). |
|||
|
|||
> [Startup templates](Startup-Templates/Index.md) are configured for the audit logging system which is suitable for most of the applications. Use this document for a detailed control over the audit log system. |
|||
|
|||
### Database Provider Support |
|||
|
|||
* Fully supported by the [Entity Framework Core](Entity-Framework-Core.md) provider. |
|||
* Entity change logging is not supported by the [MongoDB](MongoDB.md) provider. Other features work as expected. |
|||
|
|||
## UseAuditing() |
|||
|
|||
`UseAuditing()` middleware should be added to the ASP.NET Core request pipeline in order to create and save the audit logs. If you've created your applications using [the startup templates](Startup-Templates/Index.md), it is already added. |
|||
|
|||
## AbpAuditingOptions |
|||
|
|||
`AbpAuditingOptions` is the main [options object](Options.md) to configure the audit log system. You can configure it in the `ConfigureServices` method of your [module](Module-Development-Basics.md): |
|||
|
|||
````csharp |
|||
Configure<AbpAuditingOptions>(options => |
|||
{ |
|||
options.IsEnabled = false; //Disables the auditing system |
|||
}); |
|||
```` |
|||
|
|||
Here, a list of the options you can configure: |
|||
|
|||
* `IsEnabled` (default: `true`): A root switch to enable or disable the auditing system. Other options is not used if this value is `false`. |
|||
* `HideErrors` (default: `true`): Audit log system hides and write regular [logs](Logging.md) if any error occurs while saving the audit log objects. If saving the audit logs is critical for your system, set this to `false` to throw exception in case of hiding the errors. |
|||
* `IsEnabledForAnonymousUsers` (default: `true`): If you want to write audit logs only for the authenticated users, set this to `false`. If you save audit logs for anonymous users, you will see `null` for `UserId` values for these users. |
|||
* `IsEnabledForGetRequests` (default: `false`): HTTP GET requests should not make any change in the database normally and audit log system doesn't save audit log objects for GET request. Set this to `true` to enable it also for the GET requests. |
|||
* `ApplicationName`: If multiple applications saving audit logs into a single database, set this property to your application name, so you can distinguish the logs of different applications. |
|||
* `IgnoredTypes`: A list of `Type`s to be ignored for audit logging. If this is an entity type, changes for this type of entities will not be saved. This list is also used while serializing the action parameters. |
|||
* `EntityHistorySelectors`: A list of selectors those are used to determine if an entity type is selected for saving the entity change. See the section below for details. |
|||
* `Contributors`: A list of `AuditLogContributor` implementations. A contributor is a way of extending the audit log system. See the "Audit Log Contributors" section below. |
|||
|
|||
### Entity History Selectors |
|||
|
|||
Saving all changes of all your entities would require a lot of database space. For this reason, **audit log system doesn't save any change for the entities unless you explicitly configure it**. |
|||
|
|||
To save all changes of all entities, simply use the `AddAllEntities()` extension method. |
|||
|
|||
````csharp |
|||
Configure<AbpAuditingOptions>(options => |
|||
{ |
|||
options.EntityHistorySelectors.AddAllEntities(); |
|||
}); |
|||
```` |
|||
|
|||
`options.EntityHistorySelectors` actually a list of type predicate. You can write a lambda expression to define your filter. |
|||
|
|||
The example selector below does the same of the `AddAllEntities()` extension method defined above: |
|||
|
|||
````csharp |
|||
Configure<AbpAuditingOptions>(options => |
|||
{ |
|||
options.EntityHistorySelectors.Add( |
|||
new NamedTypeSelector( |
|||
"MySelectorName", |
|||
type => |
|||
{ |
|||
if (typeof(IEntity).IsAssignableFrom(type)) |
|||
{ |
|||
return true; |
|||
} |
|||
else |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
) |
|||
); |
|||
}); |
|||
```` |
|||
|
|||
The condition `typeof(IEntity).IsAssignableFrom(type)` will be `true` for any class implements the `IEntity` interface (this is technically all the entities in your application). You can conditionally check and return `true` or `false` based on your preference. |
|||
|
|||
`options.EntityHistorySelectors` is a flexible and dynamic way of selecting the entities for audit logging. Another way is to use the `Audited` and `DisableAuditing` attributes per entity. |
|||
|
|||
## Enabling/Disabling Audit Logging for Services |
|||
|
|||
### Enable/Disable for Controllers & Actions |
|||
|
|||
All the controller actions are logged by default (see `IsEnabledForGetRequests` above for GET requests). |
|||
|
|||
You can use the `[DisableAuditing]` to disable it for a specific controller type: |
|||
|
|||
````csharp |
|||
[DisableAuditing] |
|||
public class HomeController : AbpController |
|||
{ |
|||
//... |
|||
} |
|||
```` |
|||
|
|||
Use `[DisableAuditing]` for any action to control it in the action level: |
|||
|
|||
````csharp |
|||
public class HomeController : AbpController |
|||
{ |
|||
[DisableAuditing] |
|||
public async Task<ActionResult> Home() |
|||
{ |
|||
//... |
|||
} |
|||
|
|||
public async Task<ActionResult> OtherActionLogged() |
|||
{ |
|||
//... |
|||
} |
|||
} |
|||
```` |
|||
|
|||
### Enable/Disable for Application Services & Methods |
|||
|
|||
[Application service](Application-Services.md) method calls also included into the audit log by default. You can use the `[DisableAuditing]` in service or method level. |
|||
|
|||
#### Enable/Disable for Other Services |
|||
|
|||
Action audit logging can be enabled for any type of class (registered to and resolved from the [dependency injection](Dependency-Injection.md)) while it is only enabled for the controllers and the application services by default. |
|||
|
|||
Use `[Audited]` and `[DisableAuditing]` for any class or method that need to be audit logged. In addition, your class can (directly or inherently) implement the `IAuditingEnabled` interface to enable the audit logging for that class by default. |
|||
|
|||
### Enable/Disable for Entities & Properties |
|||
|
|||
An entity is ignored on entity change audit logging in the following cases; |
|||
|
|||
* If you add an entity type to the `AbpAuditingOptions.IgnoredTypes` (as explained before), it is completely ignored in the audit logging system. |
|||
* If the object is not an [entity](Entities.md) (not implements `IEntity` directly or inherently - All entities implement this interface by default). |
|||
* If entity type is not public. |
|||
|
|||
Otherwise, you can use `Audited` to enable entity change audit logging for an entity: |
|||
|
|||
````csharp |
|||
[Audited] |
|||
public class MyEntity : Entity<Guid> |
|||
{ |
|||
//... |
|||
} |
|||
```` |
|||
|
|||
Or disable it for an entity: |
|||
|
|||
````csharp |
|||
[DisableAuditing] |
|||
public class MyEntity : Entity<Guid> |
|||
{ |
|||
//... |
|||
} |
|||
```` |
|||
|
|||
Disabling audit logging can be necessary only if the entity is being selected by the `AbpAuditingOptions.EntityHistorySelectors` that explained before. |
|||
|
|||
You can disable auditing only some properties of your entities for a detailed control over the audit logging: |
|||
|
|||
````csharp |
|||
[Audited] |
|||
public class MyUser : Entity<Guid> |
|||
{ |
|||
public string Name { get; set; } |
|||
|
|||
public string Email { get; set; } |
|||
|
|||
[DisableAuditing] //Ignore the Passoword on audit logging |
|||
public string Password { get; set; } |
|||
} |
|||
```` |
|||
|
|||
Audit log system will save changes for the `MyUser` entity while it ignores the `Password` property which can be dangerous to save for security purposes. |
|||
|
|||
In some cases, you may want to save a few properties but ignore all others. Writing `[DisableAuditing]` for all the other properties would be tedious. In such cases, use `[Audited]` only for the desired properties and mark the entity with the `[DisableAuditing]` attribute: |
|||
|
|||
````csharp |
|||
[DisableAuditing] |
|||
public class MyUser : Entity<Guid> |
|||
{ |
|||
[Audited] //Only log the Name change |
|||
public string Name { get; set; } |
|||
|
|||
public string Email { get; set; } |
|||
|
|||
public string Password { get; set; } |
|||
} |
|||
```` |
|||
|
|||
## IAuditingStore |
|||
|
|||
`IAuditingStore` is an interface that is used to save the audit log objects (explained below) by the ABP Framework. If you need to save the audit log objects to a custom data store, you can implement the `IAuditingStore` in your own application and replace using the [dependency injection system](Dependency-Injection.md). |
|||
|
|||
`SimpleLogAuditingStore` is used if no audit store was registered. It simply writes the audit object to the standard [logging system](Logging.md). |
|||
|
|||
[The Audit Logging Module](Modules/Audit-Logging.md) has been configured in [the startup templates](Startup-Templates/Index.md) saves audit log objects to a database (it supports multiple database providers). So, most of the times you don't care about how `IAuditingStore` was implemented and used. |
|||
|
|||
## Audit Log Object |
|||
|
|||
An **audit log object** is created for each **web request** by default. An audit log object can be represented by the following relation diagram: |
|||
|
|||
 |
|||
|
|||
* **AuditLogInfo**: The root object with the following properties: |
|||
* `ApplicationName`: When you save audit logs of different applications to the same database, this property is used to distinguish the logs of the applications. |
|||
* `UserId`: Id of the current user, if the user has logged in. |
|||
* `UserName`: User name of the current user, if the user has logged in (this value is here to not depend on the identity module/system for lookup). |
|||
* `TenantId`: Id of the current tenant, for a multi-tenant application. |
|||
* `TenantName`: Name of the current tenant, for a multi-tenant application. |
|||
* `ExecutionTime`: The time when this audit log object has been created. |
|||
* `ExecutionDuration`: Total execution duration of the request, in milliseconds. This can be used to observe the performance of the application. |
|||
* `ClientId`: Id of the current client, if the client has been authenticated. A client is generally a 3rd-party application using the system over an HTTP API. |
|||
* `ClientName`: Name of the current client, if available. |
|||
* `ClientIpAddress`: IP address of the client/user device. |
|||
* `CorrelationId`: Current [Correlation Id](CorrelationId.md). Correlation Id is used to relate the audit logs written by different applications (or microservices) in a single logical operation. |
|||
* `BrowserInfo`: Browser name/version info of the current user, if available. |
|||
* `HttpMethod`: HTTP method of the current request (GET, POST, PUT, DELETE... etc.). |
|||
* `HttpStatusCode`: HTTP response status code for this request. |
|||
* `Url`: URL of the request. |
|||
* **AuditLogActionInfo**: An audit log action is typically a controller action or an [application service](Application-Services.md) method call during the web request. One audit log may contain multiple actions. An action object has the following properties: |
|||
* `ServiceName`: Name of the executed controller/service. |
|||
* `MethodName`: Name of the executed method of the controller/service. |
|||
* `Parameters`: A JSON formatted text representing the parameters passed to the method. |
|||
* `ExecutionTime`: The time when this method was executed. |
|||
* `ExecutionDuration`: Duration of the method execution, in milliseconds. This can be used to observe the performance of the method. |
|||
* **EntityChangeInfo**: Represents a change of an entity in this web request. An audit log may contain zero or more entity changes. An entity change has the following properties: |
|||
* `ChangeTime`: The time when the entity was changed. |
|||
* `ChangeType`: An enum with the following fields: `Created` (0), `Updated` (1) and `Deleted` (2). |
|||
* `EntityId`: Id of the entity that was changed. |
|||
* `EntityTenantId`: Id of the tenant this entity belongs to. |
|||
* `EntityTypeFullName`: Type (class) name of the entity with full namespace (like *Acme.BookStore.Book* for the Book entity). |
|||
* **EntityPropertyChangeInfo**: Represents a change of a property of an entity. An entity change info (explained above) may contain one or more property change with the following properties: |
|||
* `NewValue`: New value of the property. It is `null` if the entity was deleted. |
|||
* `OriginalValue`: Old/original value before the change. It is `null` if the entity was newly created. |
|||
* `PropertyName`: The name of the property on the entity class. |
|||
* `PropertyTypeFullName`: Type (class) name of the property with full namespace. |
|||
* **Exception**: An audit log object may contain zero or more exception. In this way, you can get a report of the failed requests. |
|||
* **Comment**: An arbitrary string value to add custom messages to the audit log entry. An audit log object may contain zero or more comments. |
|||
|
|||
In addition to the standard properties explained above, `AuditLogInfo`, `AuditLogActionInfo` and `EntityChangeInfo` objects implement the `IHasExtraProperties` interface, so you can add custom properties to these objects. |
|||
|
|||
## Audit Log Contributors |
|||
|
|||
You can extend the auditing system by creating a class that is derived from the `AuditLogContributor` class which defines the `PreContribute` and the `PostContribute` methods. |
|||
|
|||
The only pre-built contributor is the `AspNetCoreAuditLogContributor` class which sets the related properties for an HTTP request. |
|||
|
|||
A contributor can set properties and collections of the `AuditLogInfo` class to add more information. |
|||
|
|||
Example: |
|||
|
|||
````csharp |
|||
public class MyAuditLogContributor : AuditLogContributor |
|||
{ |
|||
public override void PreContribute(AuditLogContributionContext context) |
|||
{ |
|||
var currentUser = context.ServiceProvider.GetRequiredService<ICurrentUser>(); |
|||
context.AuditInfo.SetProperty( |
|||
"MyCustomClaimValue", |
|||
currentUser.FindClaimValue("MyCustomClaim") |
|||
); |
|||
} |
|||
|
|||
public override void PostContribute(AuditLogContributionContext context) |
|||
{ |
|||
context.AuditInfo.Comments.Add("Some comment..."); |
|||
} |
|||
} |
|||
```` |
|||
|
|||
* `context.ServiceProvider` can be used to resolve services from the [dependency injection](Dependency-Injection.md). |
|||
* `context.AuditInfo` can be used to access to the current audit log object to manipulate it. |
|||
|
|||
After creating such a contributor, you must add it to the `AbpAuditingOptions.Contributors` list: |
|||
|
|||
````csharp |
|||
Configure<AbpAuditingOptions>(options => |
|||
{ |
|||
options.Contributors.Add(new MyAuditLogContributor()); |
|||
}); |
|||
```` |
|||
|
|||
## IAuditLogScope & IAuditingManager |
|||
|
|||
This section explains the `IAuditLogScope` & `IAuditingManager` services for advanced use cases. |
|||
|
|||
An **audit log scope** is an [ambient scope](Ambient-Context-Pattern.md) that **builds** and **saves** an audit log object (explained before). By default, an audit log scope is created for a web request by the Audit Log Middleware (see `UseAuditing()` section above). |
|||
|
|||
### Access to the Current Audit Log Scope |
|||
|
|||
Audit log contributors, was explained above, is a global way of manipulating the audit log object. It is good if you can get a value from a service. |
|||
|
|||
If you need to manipulate the audit log object in an arbitrary point of your application, you can access to the current audit log scope and get the current audit log object (independent of how the scope is managed). Example: |
|||
|
|||
````csharp |
|||
public class MyService : ITransientDependency |
|||
{ |
|||
private readonly IAuditingManager _auditingManager; |
|||
|
|||
public MyService(IAuditingManager auditingManager) |
|||
{ |
|||
_auditingManager = auditingManager; |
|||
} |
|||
|
|||
public async Task DoItAsync() |
|||
{ |
|||
var currentAuditLogScope = _auditingManager.Current; |
|||
if (currentAuditLogScope != null) |
|||
{ |
|||
currentAuditLogScope.Log.Comments.Add( |
|||
"Executed the MyService.DoItAsync method :)" |
|||
); |
|||
|
|||
currentAuditLogScope.Log.SetProperty("MyCustomProperty", 42); |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
Always check if `_auditingManager.Current` is null or not, because it is controlled in an outer scope and you can't know if an audit log scope was created before calling your method. |
|||
|
|||
### Manually Create an Audit Log Scope |
|||
|
|||
You rarely need to create a manual audit log scope, but if you need, you can create an audit log scope using the `IAuditingManager` as like in the following example: |
|||
|
|||
````csharp |
|||
public class MyService : ITransientDependency |
|||
{ |
|||
private readonly IAuditingManager _auditingManager; |
|||
|
|||
public MyService(IAuditingManager auditingManager) |
|||
{ |
|||
_auditingManager = auditingManager; |
|||
} |
|||
|
|||
public async Task DoItAsync() |
|||
{ |
|||
using (var auditingScope = _auditingManager.BeginScope()) |
|||
{ |
|||
try |
|||
{ |
|||
//Call other services... |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
//Add exceptions |
|||
_auditingManager.Current.Log.Exceptions.Add(ex); |
|||
} |
|||
finally |
|||
{ |
|||
//Always save the log |
|||
await auditingScope.SaveAsync(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
You can call other services, they may call others, they may change entities and so on. All these interactions are saved as a single audit log object in the finally block. |
|||
|
|||
## The Audit Logging Module |
|||
|
|||
The Audit Logging Module basically implements the `IAuditingStore` to save the audit log objects to a database. It supports multiple database providers. This module is added to the startup templates by default. |
|||
|
|||
See [the Audit Logging Module document](Modules/Audit-Logging.md) for more about it. |
|||
@ -1,3 +1,43 @@ |
|||
# Hangfire Background Job Manager |
|||
|
|||
TODO |
|||
[Hangfire](https://www.hangfire.io/) is an advanced background job manager. You can integrate Hangfire with the ABP Framework to use it instead of the [default background job manager](Background-Jobs.md). In this way, you can use the same background job API for Hangfire and your code will be independent of Hangfire. If you like, you can directly use Hangfire's API, too. |
|||
|
|||
> See the [background jobs document](Background-Jobs.md) to learn how to use the background job system. This document only shows how to install and configure the Hangfire integration. |
|||
|
|||
## Installation |
|||
|
|||
It is suggested to use the [ABP CLI](CLI.md) to install this package. |
|||
|
|||
### Using the ABP CLI |
|||
|
|||
Open a command line window in the folder of the project (.csproj file) and type the following command: |
|||
|
|||
````bash |
|||
abp add-package Volo.Abp.BackgroundJobs.HangFire |
|||
```` |
|||
|
|||
### Manual Installation |
|||
|
|||
If you want to manually install; |
|||
|
|||
1. Add the [Volo.Abp.BackgroundJobs.HangFire](https://www.nuget.org/packages/Volo.Abp.BackgroundJobs.HangFire) NuGet package to your project: |
|||
|
|||
```` |
|||
Install-Package Volo.Abp.BackgroundJobs.HangFire |
|||
```` |
|||
|
|||
2. Add the `AbpBackgroundJobsHangfireModule` to the dependency list of your module: |
|||
|
|||
````csharp |
|||
[DependsOn( |
|||
//...other dependencies |
|||
typeof(AbpBackgroundJobsHangfireModule) //Add the new module dependency |
|||
)] |
|||
public class YourModule : AbpModule |
|||
{ |
|||
} |
|||
```` |
|||
|
|||
## Configuration |
|||
|
|||
TODO... |
|||
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 236 KiB |
|
After Width: | Height: | Size: 2.7 MiB |
@ -0,0 +1,7 @@ |
|||
# Audit Logging Module |
|||
|
|||
The Audit Logging Module basically implements the `IAuditingStore` to save the audit log objects to a database. |
|||
|
|||
> Audit Logging module is already installed and configured for [the startup templates](../Startup-Templates/Index.md). So, most of the times you don't need to manually add this module to your application. |
|||
|
|||
See [the audit logging system](../Audit-Logging.md) document for more about the audit logging. |
|||
|
After Width: | Height: | Size: 28 KiB |
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||