Родитель
ba8124c970
Коммит
0c37d70bcf
232
.editorconfig
232
.editorconfig
|
@ -1,4 +1,229 @@
|
|||
[*.cs]
|
||||
# http://EditorConfig.org
|
||||
|
||||
# This file is the top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# All Files
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = crlf
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Solution Files
|
||||
[*.sln]
|
||||
indent_style = tab
|
||||
|
||||
# XML Project Files
|
||||
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
|
||||
indent_size = 2
|
||||
|
||||
# Configuration Files
|
||||
[*.{json,xml,yml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}]
|
||||
indent_size = 2
|
||||
|
||||
# Markdown Files
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
# Web Files
|
||||
[*.{htm,html,js,ts,css,scss,less}]
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
|
||||
# Bash Files
|
||||
[*.sh]
|
||||
end_of_line = lf
|
||||
|
||||
# Dotnet Code Style Settings
|
||||
# See https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
|
||||
# See http://kent-boogaart.com/blog/editorconfig-reference-for-c-developers
|
||||
[*.{cs,csx,cake,vb}]
|
||||
dotnet_sort_system_directives_first = true:warning
|
||||
dotnet_style_coalesce_expression = true:warning
|
||||
dotnet_style_collection_initializer = true:warning
|
||||
dotnet_style_explicit_tuple_names = true:warning
|
||||
dotnet_style_null_propagation = true:warning
|
||||
dotnet_style_object_initializer = true:warning
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = false:none
|
||||
dotnet_style_predefined_type_for_member_access = false:none
|
||||
|
||||
|
||||
|
||||
# "This." and "Me." qualifiers
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
|
||||
# Naming Symbols
|
||||
# constant_fields - Define constant fields
|
||||
dotnet_naming_symbols.constant_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.constant_fields.required_modifiers = const
|
||||
# non_private_protected_readonly_fields - Define public, internal and protected readonly fields
|
||||
dotnet_naming_symbols.non_private_protected_readonly_fields.applicable_accessibilities = public, internal
|
||||
dotnet_naming_symbols.non_private_protected_readonly_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.non_private_protected_readonly_fields.required_modifiers = readonly
|
||||
# static_readonly_fields - Define static and readonly fields
|
||||
dotnet_naming_symbols.static_readonly_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.static_readonly_fields.required_modifiers = static, readonly
|
||||
# private_readonly_fields - Define private readonly fields
|
||||
dotnet_naming_symbols.private_readonly_fields.applicable_accessibilities = private
|
||||
dotnet_naming_symbols.private_readonly_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.private_readonly_fields.required_modifiers = readonly
|
||||
|
||||
# public_internal_fields - Define public and internal fields
|
||||
dotnet_naming_symbols.public_internal_fields.applicable_accessibilities = public, internal
|
||||
dotnet_naming_symbols.public_internal_fields.applicable_kinds = field
|
||||
# private_protected_fields - Define private and protected fields
|
||||
dotnet_naming_symbols.private_protected_fields.applicable_accessibilities = private, protected
|
||||
dotnet_naming_symbols.private_protected_fields.applicable_kinds = field
|
||||
# public_symbols - Define any public symbol
|
||||
dotnet_naming_symbols.public_symbols.applicable_accessibilities = public, internal, protected, protected_internal
|
||||
dotnet_naming_symbols.public_symbols.applicable_kinds = method, property, event, delegate
|
||||
# parameters - Defines any parameter
|
||||
dotnet_naming_symbols.parameters.applicable_kinds = parameter
|
||||
# non_interface_types - Defines class, struct, enum and delegate types
|
||||
dotnet_naming_symbols.non_interface_types.applicable_kinds = class, struct, enum, delegate
|
||||
# interface_types - Defines interfaces
|
||||
dotnet_naming_symbols.interface_types.applicable_kinds = interface
|
||||
|
||||
# Naming Styles
|
||||
# camel_case - Define the camelCase style
|
||||
dotnet_naming_style.camel_case.capitalization = camel_case
|
||||
# pascal_case - Define the Pascal_case style
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
# first_upper - The first character must start with an upper-case character
|
||||
dotnet_naming_style.first_upper.capitalization = first_word_upper
|
||||
# prefix_interface_interface_with_i - Interfaces must be PascalCase and the first character of an interface must be an 'I'
|
||||
dotnet_naming_style.prefix_interface_interface_with_i.capitalization = pascal_case
|
||||
dotnet_naming_style.prefix_interface_interface_with_i.required_prefix = I
|
||||
|
||||
# Naming Rules
|
||||
# Constant fields must be PascalCase
|
||||
dotnet_naming_rule.constant_fields_must_be_pascal_case.severity = warning
|
||||
dotnet_naming_rule.constant_fields_must_be_pascal_case.symbols = constant_fields
|
||||
dotnet_naming_rule.constant_fields_must_be_pascal_case.style = pascal_case
|
||||
# Public, internal and protected readonly fields must be PascalCase
|
||||
dotnet_naming_rule.non_private_protected_readonly_fields_must_be_pascal_case.severity = warning
|
||||
dotnet_naming_rule.non_private_protected_readonly_fields_must_be_pascal_case.symbols = non_private_protected_readonly_fields
|
||||
dotnet_naming_rule.non_private_protected_readonly_fields_must_be_pascal_case.style = pascal_case
|
||||
# Static readonly fields must be PascalCase
|
||||
dotnet_naming_rule.static_readonly_fields_must_be_pascal_case.severity = warning
|
||||
dotnet_naming_rule.static_readonly_fields_must_be_pascal_case.symbols = static_readonly_fields
|
||||
dotnet_naming_rule.static_readonly_fields_must_be_pascal_case.style = pascal_case
|
||||
|
||||
# Private/protected Fields should start with underscore
|
||||
dotnet_naming_rule.private_members_with_underscore.severity = warning
|
||||
dotnet_naming_rule.private_members_with_underscore.symbols = private_protected_fields
|
||||
dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore
|
||||
|
||||
dotnet_naming_style.prefix_underscore.required_prefix = _
|
||||
dotnet_naming_style.prefix_underscore.capitalization = camel_case
|
||||
|
||||
dotnet_naming_symbols.private_protected_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.private_protected_fields.applicable_accessibilities = private, protected
|
||||
dotnet_naming_symbols.private_protected_fields.required_modifiers = readonly
|
||||
|
||||
|
||||
# Public and internal fields must be PascalCase
|
||||
dotnet_naming_rule.public_internal_fields_must_be_pascal_case.severity = warning
|
||||
dotnet_naming_rule.public_internal_fields_must_be_pascal_case.symbols = public_internal_fields
|
||||
dotnet_naming_rule.public_internal_fields_must_be_pascal_case.style = pascal_case
|
||||
# Private and protected fields must be camelCase
|
||||
dotnet_naming_rule.private_protected_fields_must_be_camel_case.severity = warning
|
||||
dotnet_naming_rule.private_protected_fields_must_be_camel_case.symbols = private_protected_fields
|
||||
dotnet_naming_rule.private_protected_fields_must_be_camel_case.style = camel_case
|
||||
# Public members must be capitalized
|
||||
dotnet_naming_rule.public_members_must_be_capitalized.severity = warning
|
||||
dotnet_naming_rule.public_members_must_be_capitalized.symbols = public_symbols
|
||||
dotnet_naming_rule.public_members_must_be_capitalized.style = first_upper
|
||||
# Parameters must be camelCase
|
||||
dotnet_naming_rule.parameters_must_be_camel_case.severity = warning
|
||||
dotnet_naming_rule.parameters_must_be_camel_case.symbols = parameters
|
||||
dotnet_naming_rule.parameters_must_be_camel_case.style = camel_case
|
||||
# Class, struct, enum and delegates must be PascalCase
|
||||
dotnet_naming_rule.non_interface_types_must_be_pascal_case.severity = warning
|
||||
dotnet_naming_rule.non_interface_types_must_be_pascal_case.symbols = non_interface_types
|
||||
dotnet_naming_rule.non_interface_types_must_be_pascal_case.style = pascal_case
|
||||
# Interfaces must be PascalCase and start with an 'I'
|
||||
dotnet_naming_rule.interface_types_must_be_prefixed_with_i.severity = warning
|
||||
dotnet_naming_rule.interface_types_must_be_prefixed_with_i.symbols = interface_types
|
||||
dotnet_naming_rule.interface_types_must_be_prefixed_with_i.style = prefix_interface_interface_with_i
|
||||
|
||||
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
|
||||
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
|
||||
|
||||
# C# Code Style Settings
|
||||
# See https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
|
||||
# See http://kent-boogaart.com/blog/editorconfig-reference-for-c-developers
|
||||
[*.cs,csx,cake]
|
||||
# Indentation Options
|
||||
csharp_indent_block_contents = true:warning
|
||||
csharp_indent_braces = false:warning
|
||||
csharp_indent_case_contents = true:warning
|
||||
csharp_indent_labels = no_change:warning
|
||||
csharp_indent_switch_labels = true:warning
|
||||
# Style Options
|
||||
csharp_style_conditional_delegate_call = true:warning
|
||||
csharp_style_expression_bodied_accessors = true:warning
|
||||
csharp_style_expression_bodied_constructors = true:warning
|
||||
csharp_style_expression_bodied_indexers = true:warning
|
||||
csharp_style_expression_bodied_methods = true:warning
|
||||
csharp_style_expression_bodied_operators = true:warning
|
||||
csharp_style_expression_bodied_properties = true:warning
|
||||
csharp_style_inlined_variable_declaration = true:warning
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:warning
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
|
||||
csharp_style_throw_expression = true:warning
|
||||
csharp_style_var_elsewhere = true:warning
|
||||
csharp_style_var_for_built_in_types = true:warning
|
||||
csharp_style_var_when_type_is_apparent = true:warning
|
||||
# New Line Options
|
||||
csharp_new_line_before_catch = true:warning
|
||||
csharp_new_line_before_else = true:warning
|
||||
csharp_new_line_before_finally = true:warning
|
||||
csharp_new_line_before_members_in_anonymous_types = true:warning
|
||||
csharp_new_line_before_members_in_object_initializers = true:warning
|
||||
# BUG: Warning level cannot be set https://github.com/dotnet/roslyn/issues/18010
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_between_query_expression_clauses = true:warning
|
||||
# Spacing Options
|
||||
csharp_space_after_cast = false:warning
|
||||
csharp_space_after_colon_in_inheritance_clause = true:warning
|
||||
csharp_space_after_comma = true:warning
|
||||
csharp_space_after_dot = false:warning
|
||||
csharp_space_after_keywords_in_control_flow_statements = true:warning
|
||||
csharp_space_after_semicolon_in_for_statement = true:warning
|
||||
csharp_space_around_binary_operators = before_and_after:warning
|
||||
csharp_space_around_declaration_statements = do_not_ignore:warning
|
||||
csharp_space_before_colon_in_inheritance_clause = true:warning
|
||||
csharp_space_before_comma = false:warning
|
||||
csharp_space_before_dot = false:warning
|
||||
csharp_space_before_semicolon_in_for_statement = false:warning
|
||||
csharp_space_before_open_square_brackets = false:warning
|
||||
csharp_space_between_empty_square_brackets = false:warning
|
||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false:warning
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false:warning
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false:warning
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false:warning
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false:warning
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false:warning
|
||||
csharp_space_between_parentheses = expressions:warning
|
||||
csharp_space_between_square_brackets = false:warning
|
||||
# Wrapping Options
|
||||
csharp_preserve_single_line_blocks = true:warning
|
||||
csharp_preserve_single_line_statements = false:warning
|
||||
|
||||
#[*.{cs}]
|
||||
## Default severity for analyzer diagnostics with category 'Style' (escalated to build warnings)
|
||||
# examples:
|
||||
# dotnet_analyzer_diagnostic.category-Style.severity = suggestion
|
||||
# dotnet_analyzer_diagnostic.category-Design.severity = warning
|
||||
|
||||
[*.cs]
|
||||
|
||||
# CS1591: Missing XML comment for publicly visible type or member
|
||||
dotnet_diagnostic.CS1591.severity = none
|
||||
|
@ -7,4 +232,7 @@ dotnet_diagnostic.CS1591.severity = none
|
|||
csharp_style_expression_bodied_methods = false
|
||||
|
||||
[*.{cs,vb}]
|
||||
indent_style=space
|
||||
indent_style=space
|
||||
|
||||
# IDE0049: Use framework type
|
||||
dotnet_diagnostic.IDE0049.severity = none
|
||||
|
|
|
@ -349,3 +349,5 @@ MigrationBackup/
|
|||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
samples/**/Docs/OpenApiSpecs/**
|
||||
/samples/SimpleKindArmResourceProviderDemo/SimpleKindArmResourceProviderDemo.xml
|
||||
/samples/ArmResourceProviderDemo/ArmResourceProviderDemo.xml
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"cSpell.words": ["commonize"]
|
||||
"cSpell.words": ["commonize", "Pageable"]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
<Project>
|
||||
<!-- Can be renamed to Directory.Build.props when migrating all projects in src folder to netcore3.1 or higher -->
|
||||
<PropertyGroup>
|
||||
<Company>Microsoft</Company>
|
||||
<Copyright>@Microsoft Corporation. All right reserved</Copyright>
|
||||
<Authors>Microsoft Azure Sentinal Team</Authors>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<!-- CODE ANALYSIS -->
|
||||
<PropertyGroup>
|
||||
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Nullable>disable</Nullable>
|
||||
<CodeAnalysisRuleSet>$(SolutionDir)/common.ruleset</CodeAnalysisRuleSet>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<WarningsNotAsErrors>618,1030</WarningsNotAsErrors>
|
||||
<!-- see CS618,CS1030 -->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Label="roslyn analyzers">
|
||||
<!-- for (CAxxxx) https://github.com/dotnet/roslyn-analyzers -->
|
||||
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3">
|
||||
<!-- You do not need to manually install this NuGet package to your project if you are using .NET5 SDK or later. These analyzers are enabled by default for projects targeting .NET5 or later. -->
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2">
|
||||
<!-- more info https://github.com/dotnet/roslyn-analyzers#microsoftcodeanalysisanalyzers -->
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Label="Stylecop">
|
||||
<AdditionalFiles Include="$(SolutionDir)/stylecop.json" />
|
||||
<!-- Extra 3rd party analyzer https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/DOCUMENTATION.md can be controled on -->
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -8,10 +8,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".Solution Items", ".Solutio
|
|||
.dockerignore = .dockerignore
|
||||
.editorconfig = .editorconfig
|
||||
.gitignore = .gitignore
|
||||
common.ruleset = common.ruleset
|
||||
Directory.Build.props = Directory.Build.props
|
||||
SomeWebApp\.config\dotnet-tools.json = SomeWebApp\.config\dotnet-tools.json
|
||||
global.json = global.json
|
||||
NuGet.Config = NuGet.Config
|
||||
README.md = README.md
|
||||
stylecop.json = stylecop.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ArmResourceProviderDemo", "samples\ArmResourceProviderDemo\ArmResourceProviderDemo.csproj", "{EFB66B7C-A236-4557-8B41-2CCC34D27EA0}"
|
||||
|
@ -24,6 +27,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BasicWebAppDemo", "samples\
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleKindArmResourceProviderDemo", "samples\SimpleKindArmResourceProviderDemo\SimpleKindArmResourceProviderDemo.csproj", "{A2118CB4-45DF-47ED-B257-D2B2C4BB8E3A}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{B41E590F-8952-40FC-8625-1A4FA7F52D63}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenApiExtensions.Test", "tests\OpenApiExtensions.Test\OpenApiExtensions.Test.csproj", "{17BD1A97-D83A-4E61-9F3E-1F0C7407FF6A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -46,6 +53,10 @@ Global
|
|||
{A2118CB4-45DF-47ED-B257-D2B2C4BB8E3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A2118CB4-45DF-47ED-B257-D2B2C4BB8E3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A2118CB4-45DF-47ED-B257-D2B2C4BB8E3A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{17BD1A97-D83A-4E61-9F3E-1F0C7407FF6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{17BD1A97-D83A-4E61-9F3E-1F0C7407FF6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{17BD1A97-D83A-4E61-9F3E-1F0C7407FF6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{17BD1A97-D83A-4E61-9F3E-1F0C7407FF6A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -54,6 +65,7 @@ Global
|
|||
{EFB66B7C-A236-4557-8B41-2CCC34D27EA0} = {2EDC176C-BCDE-4759-9EDD-1B0CE23FE1FB}
|
||||
{876DEB56-964B-496B-9DAE-4E1FDA5C906F} = {2EDC176C-BCDE-4759-9EDD-1B0CE23FE1FB}
|
||||
{A2118CB4-45DF-47ED-B257-D2B2C4BB8E3A} = {2EDC176C-BCDE-4759-9EDD-1B0CE23FE1FB}
|
||||
{17BD1A97-D83A-4E61-9F3E-1F0C7407FF6A} = {B41E590F-8952-40FC-8625-1A4FA7F52D63}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {EB57A47A-27F7-48FB-843C-6DBE052B81E6}
|
||||
|
|
295
README.md
295
README.md
|
@ -1,20 +1,14 @@
|
|||
(Work In Progress)
|
||||
---------------
|
||||
Enlistment
|
||||
==========
|
||||
#### Prerequisite - Configure dotnet swagger
|
||||
From the example APP project directory
|
||||
1. Run `dotnet new tool-manifest --force` to create a tool manifest file
|
||||
2. Run `dotnet tool install --version 5.0.0 Swashbuckle.AspNetCore.Cli` to install swachbuckle cli as local tool
|
||||
OpenApiExtensions
|
||||
==================
|
||||
OpenApiExtensions Nuget Package is providing out of the box, generating rich Swagger files out of your Aspnet Api code. The Generated Swagger file is enriched by decorating your code with Attributes and comments, and therefore is able to generated a fully autorest compliant Swagger file (and request/response Example files).
|
||||
the generation process is relying on [Swashbuckle](https://github.com/domaindrivendev/Swashbuckle.AspNetCore)
|
||||
|
||||
For more info check instructions here: [Swashbuckle.AspNetCore.Cli](https://github.com/domaindrivendev/Swashbuckle.AspNetCore#using-the-tool-with-the-net-core-30-sdk-or-later)
|
||||
# Getting Started
|
||||
|
||||
#### Compile and build
|
||||
1. set a global json file
|
||||
2. compile the project by running `dotnet build`. This will build the project and generate the swagger files
|
||||
* The generated swagger files should appear under `$(ProjectDir)\Docs\OpenApiSpecs`
|
||||
|
||||
Usage
|
||||
### Target Project Prerequisites
|
||||
* "Aspnet core 3.1 or higher" for your WebApi
|
||||
|
||||
How To use
|
||||
=================
|
||||
|
||||
add this code on your startup `ConfigureServices()` method [see usage](./samples/BasicWebAppDemo/Startup.cs#L64)
|
||||
|
@ -26,9 +20,8 @@ add this code on your startup `ConfigureServices()` method [see usage](./samples
|
|||
ModelEnumsAsString = true,
|
||||
ReusableParameters = new Dictionary<string, Microsoft.OpenApi.Models.OpenApiParameter>()
|
||||
{
|
||||
{ "SubscriptionIdParameter", ArmReusableParameters.GetSubscriptionIdParameter() },
|
||||
{ "ResourceGroupNameParameter", ArmReusableParameters.GetResourceGroupNameParameter() },
|
||||
{ "ApiVersionParameter", ArmReusableParameters.GetApiVersionParameter() }
|
||||
{ "SomeReusableParam", ReusableParameters.GetSomeReusableParameter() },
|
||||
{ "ApiVersionParameter", ReusableParameters.GetApiVersionParameter() }
|
||||
},
|
||||
EnableSwaggerSecurityTokenSupport = true
|
||||
};
|
||||
|
@ -42,19 +35,253 @@ add this at the beginning of the pipeline:
|
|||
app.UseAutorestCompliantSwagger(_swaggerConfig);
|
||||
```
|
||||
|
||||
Swagger Enrichment
|
||||
=================
|
||||
part of the process is to enrich your Swagger generation with metadata from your code.
|
||||
here is a list of enrichments you should consider:
|
||||
1. [Xml documentation](https://docs.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-properties?view=vs-2019) file file on your .csproj, this would read your triple slash comment, translate it into XML file, and swashbuckle will take this file and embed the comments into the generated swagger.
|
||||
2. [Swashbuckle annotations ](https://github.com/domaindrivendev/Swashbuckle.AspNetCore#swashbuckleaspnetcoreannotations)
|
||||
4. Attributes annotations (see [attributes folder](./src/OpenApiExtensions/Attributes)), some of which:
|
||||
1. ProducesContentTypeAttribute
|
||||
2. SwaggerHideParameterAttribute
|
||||
3. CustomSwaggerSchemaInheritanceAttribute
|
||||
4. ExampleAttribute
|
||||
5. CustomSwaggerSchemaIdAttribute
|
||||
6. CustomSwaggerGenericsSchemaNameStartegyAttribute
|
||||
7. LongRunningOperationAttribute
|
||||
8. HideInDocsAttribute
|
||||
|
||||
|
||||
having these minimal Prerequisites are enough to generate a swagger file.
|
||||
when running your ArmApi on "localmode" you can now browse to
|
||||
`http://127.0.0.1:<<YOUR PORT>>/swagger/<<YOUR API VERSION>>/swagger.json`
|
||||
and get the file on your browser
|
||||
or just `http://127.0.0.1:<<YOUR PORT>>/swagger` to get the **swagger ui**.
|
||||
|
||||
## Enrichment
|
||||
### [Code Enrichment](#code-enrich)
|
||||
to be able to be fully compliant with Autorest Swagger standards, your code should be decorated with Comments and attributes.
|
||||
### Enrich by Comments:
|
||||
In order to enrich your swagger file from comments, you need to set msbuild [Xml documentation file](https://docs.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-properties?view=vs-2019).
|
||||
upon build, the complier will read all your triple slash comments and save them into a XML file, which the swagger generation process will automatically read to enrich your Classes, Operations.
|
||||
see [example](./samples/BasicWebAppDemo/WebModels/WeatherForecast.cs)
|
||||
|
||||
example:
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// Some Descriptive Summary Description (Reflected on your XML Comment -> and Swashbuckle read the XmlDocumentation file and enrich the schemas , see https://github.com/domaindrivendev/Swashbuckle.AspNetCore#include-descriptions-from-xml-comments)
|
||||
/// </summary>
|
||||
abstract public class WeatherForecast
|
||||
{
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Enrich by Attributes:
|
||||
As the Swagger Generation is based on [Swashbuckle](https://github.com/domaindrivendev/Swashbuckle.AspNetCore), you may use any of the swashbuckle annotations.
|
||||
in addition to that you may refer to full list of provided annotation (attributes) by [this repo](OpenApiExtensions\Attributes)
|
||||
|
||||
|
||||
|
||||
you might also want to run the code tour of this repo by opening [this folder](.) with VSCode, and start the code tour.
|
||||
|
||||
### [Enriching your Controllers](#Enriching-your-Controllers)
|
||||
|
||||
#### ArmApi
|
||||
```csharp
|
||||
[ApiVersion("2022-01-01-preview")]
|
||||
[Route("MyArmApiController")]
|
||||
[ApiController]
|
||||
[SwaggerApiVersionRange(fromVersion: "2022-01-01-preview")] // this tell the swagger generating to include this controller in any "2022-01-01-preview" and above (not mandatory)
|
||||
[SwaggerTag("ReadSomeResource")] // this would set up the tag for your controller
|
||||
public class MyArmApiController : ControllerBase
|
||||
{
|
||||
....
|
||||
}
|
||||
```
|
||||
#### Internal Api
|
||||
to avoid Internal Apis to be reflected in External Swagger docs use
|
||||
`[HideInDocs]` attribute to decorate either your Controllers or Actions
|
||||
```csharp
|
||||
[ApiVersion("2022-01-01-preview")]
|
||||
[Route("InternalApi")]
|
||||
[HideInDocs]
|
||||
public class MyInternalApiController : ControllerBase
|
||||
{
|
||||
....
|
||||
}
|
||||
```
|
||||
|
||||
### [Enriching your Actions](#Enriching-your-Actions)
|
||||
|
||||
in this sample we provide the [SwaggerOperation] attribute that enrich the swagger model, and Request+Response + Example Providers.
|
||||
```csharp
|
||||
|
||||
[SwaggerOperation(
|
||||
Summary = "Get MyArmResources records",
|
||||
Description = "Fetches My Arm Resources",
|
||||
OperationId = "Get",
|
||||
Tags = new[] { "MyArmResources" })]
|
||||
[SwaggerResponse(200, "MyArmResources records fetched", typeof(SomeResourceList))]
|
||||
[ResponseExample(200, typeof(GetAllMyArmResourcesResponseExample))]
|
||||
[RequestExample(typeof(GetAllMyArmResourcesAsyncRequestExample))]
|
||||
[Pageable]
|
||||
[HttpGet]
|
||||
public async Task<SomeResourceList> GetListOfResources(
|
||||
Guid subscriptionId,
|
||||
string resourceGroupName,
|
||||
string workspaceName,
|
||||
[SwaggerHideParameter][FromHeader(Name = ArmHeaderConstants.InternalWorkspaceIdHeaderName)] Guid workspaceId,
|
||||
[LogIgnore] CancellationToken cancellationToken)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
```csharp
|
||||
/// <param name="resourceId">Some Documentation to be shown on swagger</param>
|
||||
[SwaggerOperation(
|
||||
Summary = "Get MyArmResource record",
|
||||
Description = "Fetches My Arm Resource",
|
||||
OperationId = "Get",
|
||||
Tags = new[] { "MyArmResource" })]
|
||||
[SwaggerResponse(200, "MyArmResource fetched", typeof(MyArmResource))]
|
||||
[ResponseExample(200, typeof(GetMyArmResourceResponseExample))]
|
||||
[RequestExample(typeof(GetAllSomeResourceAsyncRequestExample))]
|
||||
[HttpGet("{resourceId}")]
|
||||
public async Task<MyArmResource> GetSingleResource(
|
||||
Guid subscriptionId,
|
||||
string resourceGroupName,
|
||||
string workspaceName,
|
||||
string resourceId,
|
||||
[SwaggerHideParameter][FromHeader(Name = ArmHeaderConstants.InternalWorkspaceIdHeaderName)] Guid workspaceId,
|
||||
[LogIgnore] CancellationToken cancellationToken)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
#### [Examples](#providing-example)
|
||||
by specifying above your action these attributes : `[ResponseExample]` and `[RequestExample]`, examples will be auto generated for you. [see sample](samples\BasicWebAppDemo\Controllers\WeatherForecastController.cs#57)
|
||||
|
||||
|
||||
### [Enriching your WebModels](#some-markdown-heading)
|
||||
See [samples](./samples/] projects for more info
|
||||
for Virtual inheritance in your swagger file refer [this sample](samples\ArmResourceProviderDemo)
|
||||
(virtual inheritance is when you have polymorphism on your APIs, and the classes in your swagger doesnt exist on your code)
|
||||
|
||||
### Renaming your WebModels
|
||||
sometimes you want to call your models differently on the swagger doc than your code.
|
||||
you have a few options to deal with this.
|
||||
1. Renaming your class in code to match swagger, as WebModels class renaming is not a breaking change. you can do so if you can.
|
||||
2. If you are not able to control your WebModels, in such cases when returning a generic Object, `MyObjectGenericsWrapper<T>`, you still can :
|
||||
1. Not using `MyObjectGenericsWrapper<T>` and use your own class.
|
||||
2. inherit from `MyObjectGenericsWrapper<T>` and return this inheritance from your controllers actions.
|
||||
3. Use provided Swagger Attributes to control the naming:
|
||||
here are some examples:
|
||||
* Basic constant renaming:
|
||||
```csharp
|
||||
// in this example MyBoringClassResource would be named MySwaggerAwesomeName
|
||||
[SwaggerSchemaNameStrategy("MySwaggerAwesomeName")]
|
||||
public class MyBoringClassResource
|
||||
{
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
* Naming a generic wrapper:
|
||||
```csharp
|
||||
[SwaggerSchemaNameStrategy(NamingStrategy.ApplyToParentWrapper, "MySwaggerAwesomeNameModel")]
|
||||
public class MyResourceProperties
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public class MyObjectGenericsWrapper<T> // this class when used as MyObjectGenericsWrapper<MyResourceProperties> will be named in swagger as MySwaggerAwesomeNameModel
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
```csharp
|
||||
// in this example a Generic Wrapper that holds ConcreteModel would be named according to the logic of SwaggerAwesomeClassNameProvider
|
||||
[SwaggerSchemaNameStrategy(NamingStrategy.ApplyToParentWrapper, typeof(SwaggerAwesomeClassNameProvider) )]
|
||||
public class ConcreteModel
|
||||
{
|
||||
}
|
||||
|
||||
public class SwaggerAwesomeClassNameProvider : ICustomSchemaNameProvider
|
||||
{
|
||||
public string GetCustomName(Type type)
|
||||
{
|
||||
if (typeof(MyObjectGenericsWrapper<ConcreteModel>) == type)
|
||||
{
|
||||
return "ConcreteClass";
|
||||
}
|
||||
|
||||
if (typeof(MyObjectsCollectionGenericsWrapper<ConcreteModel>) == type)
|
||||
{
|
||||
return "ConcreteClassesList";
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Add more here ..");
|
||||
}
|
||||
}
|
||||
```
|
||||
<small>Open Api Extension also provide out of the box Custom name providers such as [ArmResourceWrapperNameProvider](OpenApiExtensions\Helpers\ArmResourceWrapperNameProvider.cs)</small>
|
||||
|
||||
### Models hierarchy
|
||||
You might need to create a model hierarch in swagger that doesn't reflect your code. to do so, you can use the `CustomSwaggerSchemaInheritance` to create an object Hierarchy that doesn't reflect your code.
|
||||
see this example:
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// The Some Resource Properties model.
|
||||
/// </summary>
|
||||
[ClientFlatten]
|
||||
[CustomSwaggerSchemaInheritance(externalSchemaName: "MySwaggerOnlyBaseCLass", notInheritedPropertiesName: new[] { nameof(Properties) }, CommonObjectType.ResourceProviderCommonDefinition )]
|
||||
public class SomeResourceModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets nested level of properties which contains the resource content
|
||||
/// </summary>
|
||||
[JsonProperty("properties", Required = Required.Always)]
|
||||
public MyResourceProperties Properties { get; set; }
|
||||
}
|
||||
```
|
||||
will result this Definition in swagger:
|
||||
```json
|
||||
"definitions": {
|
||||
"SomeResourceModel": {
|
||||
"description": "The Some Resource Properties model.",
|
||||
"required": [
|
||||
"properties"
|
||||
],
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "../../../common/2.0/types.json#/definitions/MySwaggerOnlyBaseClass"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"properties": {
|
||||
"description": "Gets or sets nested level of properties which contains the resource content",
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MyResourceProperties"
|
||||
}
|
||||
],
|
||||
"x-ms-client-flatten": true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
### [Inheritance and Polymorphism](#Inheritance-and-Polymorphism)
|
||||
Polymorphic in this context means, that your request or response is/contains a base (or abstract) class.
|
||||
this can lead to some challenges. in order to overcome it, OpenApiExtension has some out of the box solutions.
|
||||
for starters you need to register your polymorphic class in the SwaggerConfig:
|
||||
* in case of "Virtual Inheritance" - means the inherited classes are not in your code, please refer (to sample)[ArmResourceProviderDemo](samples\ArmResourceProviderDemo).
|
||||
* in other case you need to provide the `Discriminator` see [reference here](samples\BasicWebAppDemo\WebModels\WeatherForecast.cs)
|
||||
|
||||
|
||||
|
||||
### [Api version](#api-version)
|
||||
Api version is supported out of box by reading the `[ApiVersion]` attributes on your Controllers.
|
||||
to support also the "Api Version Fallback" you may Provide the `[SwaggerApiVersionRangeAttribute]` as well, to specify ranges version of that your api supports.
|
||||
|
||||
## [Creating Swagger files for your entire Repo by Script](#gen-script)
|
||||
### intro
|
||||
Since your code now contains everything that is needed to generate a well defined Swagger file, you can leverage an automation script that will:
|
||||
1. generate your swagger file
|
||||
2. "prettify" it so it would be valid for linters
|
||||
3. Generate Autorest csharp SDK so you can observe it.
|
||||
4. Validate that the swagger file is compliant
|
||||
|
||||
### Implement
|
||||
In order to support automate the process of generating and validating your swagger outcome, you need to set up 2 things:
|
||||
1. **Setup the script configuration section**.
|
||||
2. a WebHost function that hosts the app, and the cli tool can call it to run the swagger pipeline. see [this](https://github.com/domaindrivendev/Swashbuckle.AspNetCore#use-the-cli-tool-with-a-custom-host-configuration) example for more info.
|
|
@ -0,0 +1,109 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RuleSet Name="solution rule set" Description="set of top level rules" ToolsVersion="16.0">
|
||||
<Rules AnalyzerId="Microsoft.CodeAnalysis.CSharp" RuleNamespace="Microsoft.CodeAnalysis.CSharp">
|
||||
<Rule Id="CS1062" Action="None" />
|
||||
<Rule Id="CS1591" Action="None" />
|
||||
</Rules>
|
||||
<Rules AnalyzerId="Microsoft.CodeAnalysis.CSharp.CodeStyle" RuleNamespace="Microsoft.CodeAnalysis.CSharp.CodeStyle">
|
||||
<Rule Id="IDE0060" Action="None" />
|
||||
<Rule Id="IDE0028" Action="Info" />
|
||||
<Rule Id="IDE0079" Action="None" />
|
||||
<Rule Id="IDE1006" Action="None" />
|
||||
</Rules>
|
||||
<Rules AnalyzerId="Microsoft.CodeAnalysis.CSharp.Features" RuleNamespace="Microsoft.CodeAnalysis.CSharp.Features">
|
||||
<Rule Id="IDE0049" Action="None" />
|
||||
<Rule Id="IDE0060" Action="None" />
|
||||
</Rules>
|
||||
<Rules AnalyzerId="Microsoft.CodeAnalysis.CSharp.NetAnalyzers" RuleNamespace="Microsoft.CodeAnalysis.CSharp.NetAnalyzers">
|
||||
<Rule Id="CA1001" Action="None" />
|
||||
</Rules>
|
||||
<Rules AnalyzerId="Microsoft.CodeAnalysis.NetAnalyzers" RuleNamespace="Microsoft.CodeAnalysis.NetAnalyzers">
|
||||
<Rule Id="CA2229" Action="None" />
|
||||
<Rule Id="CA2007" Action="None" />
|
||||
<Rule Id="CA1002" Action="None" />
|
||||
<Rule Id="CA1031" Action="None" />
|
||||
<Rule Id="CA1032" Action="None" />
|
||||
<Rule Id="CA1014" Action="None" />
|
||||
<Rule Id="CA1050" Action="None" />
|
||||
<Rule Id="CA1051" Action="None" />
|
||||
<Rule Id="CA1052" Action="None" />
|
||||
<Rule Id="CA1054" Action="None" />
|
||||
<Rule Id="CA1056" Action="Info" />
|
||||
<Rule Id="CA1062" Action="None" />
|
||||
<Rule Id="CA1304" Action="None" />
|
||||
<Rule Id="CA1305" Action="None" />
|
||||
<Rule Id="CA1307" Action="None" />
|
||||
<Rule Id="CA1309" Action="None" />
|
||||
<Rule Id="CA1310" Action="None" />
|
||||
<Rule Id="CA1707" Action="None" />
|
||||
<Rule Id="CA1806" Action="None" />
|
||||
<Rule Id="CA1819" Action="None" />
|
||||
<Rule Id="CA1822" Action="None" />
|
||||
<Rule Id="CA2227" Action="None" />
|
||||
<Rule Id="CA2237" Action="None" />
|
||||
<Rule Id="CA1716" Action="None" />
|
||||
<Rule Id="CA1801" Action="None" />
|
||||
<Rule Id="CA1806" Action="None" />
|
||||
<Rule Id="CA1810" Action="None" />
|
||||
<Rule Id="CA1812" Action="None" />
|
||||
<Rule Id="CA1822" Action="None" />
|
||||
<Rule Id="CA1813" Action="None" />
|
||||
<Rule Id="CA1819" Action="None" />
|
||||
<Rule Id="CA2007" Action="None" />
|
||||
<Rule Id="CA2016" Action="None" />
|
||||
<Rule Id="CA2201" Action="None" />
|
||||
<Rule Id="CA2229" Action="None" />
|
||||
<Rule Id="CA5394" Action="None" />
|
||||
</Rules>
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
|
||||
<Rule Id="SA0001" Action="Info" />
|
||||
<Rule Id="SA1005" Action="None" />
|
||||
<Rule Id="SA1008" Action="Info" />
|
||||
<Rule Id="SA1009" Action="Info" />
|
||||
<Rule Id="SA1012" Action="Info" />
|
||||
<Rule Id="SA1013" Action="Info" />
|
||||
<Rule Id="SA1101" Action="None" />
|
||||
<Rule Id="SA1108" Action="Info" />
|
||||
<Rule Id="SA1111" Action="None" />
|
||||
<Rule Id="SA1118" Action="None" />
|
||||
<Rule Id="SA1121" Action="None" />
|
||||
<Rule Id="SA1124" Action="Info" />
|
||||
<Rule Id="SA1127" Action="Info" />
|
||||
<Rule Id="SA1128" Action="Info" />
|
||||
<Rule Id="SA1129" Action="None" />
|
||||
<Rule Id="SA1131" Action="Info" />
|
||||
<Rule Id="SA1201" Action="None" />
|
||||
<Rule Id="SA1202" Action="Warning" />
|
||||
<Rule Id="SA1203" Action="Info" />
|
||||
<Rule Id="SA1204" Action="Info" />
|
||||
<Rule Id="SA1208" Action="None" />
|
||||
<Rule Id="SA1303" Action="None" />
|
||||
<Rule Id="SA1309" Action="None" />
|
||||
<Rule Id="SA1310" Action="None" />
|
||||
<Rule Id="SA1313" Action="None" />
|
||||
<Rule Id="SA1400" Action="None" />
|
||||
<Rule Id="SA1401" Action="Info" />
|
||||
<Rule Id="SA1402" Action="Info" />
|
||||
<Rule Id="SA1413" Action="None" />
|
||||
<Rule Id="SA1500" Action="None" />
|
||||
<Rule Id="SA1501" Action="None" />
|
||||
<Rule Id="SA1502" Action="None" />
|
||||
<Rule Id="SA1503" Action="Info" />
|
||||
<Rule Id="SA1512" Action="Info" />
|
||||
<Rule Id="SA1513" Action="None" />
|
||||
<Rule Id="SA1515" Action="None" />
|
||||
<Rule Id="SA1516" Action="None" />
|
||||
<Rule Id="SA1600" Action="Info" />
|
||||
<Rule Id="SA1611" Action="Info" />
|
||||
<Rule Id="SA1612" Action="Info" />
|
||||
<Rule Id="SA1614" Action="Info" />
|
||||
<Rule Id="SA1615" Action="Info" />
|
||||
<Rule Id="SA1616" Action="Info" />
|
||||
<Rule Id="SA1623" Action="None" />
|
||||
<Rule Id="SA1627" Action="Info" />
|
||||
<Rule Id="SA1629" Action="None" />
|
||||
<Rule Id="SA1633" Action="None" />
|
||||
<Rule Id="SA1642" Action="None" />
|
||||
<Rule Id="SA1649" Action="Info" />
|
||||
</Rules>
|
||||
</RuleSet>
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"sdk": {
|
||||
"version": "3.1.101",
|
||||
"rollForward": "latestPatch"
|
||||
}
|
||||
"sdk": {
|
||||
"version": "3.1.101",
|
||||
"rollForward": "latestPatch"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
|
@ -6,7 +6,6 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DocumentationFile>ArmResourceProviderDemo.xml</DocumentationFile>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
using ArmResourceProviderDemo.WebModels;
|
||||
using ArmResourceProviderDemo.WebModels.Speed;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace ArmResourceProviderDemo.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class SpeedController : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public ResourceProxy<SpeedProperties> Get()
|
||||
{
|
||||
return new ResourceProxy<SpeedProperties> { };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
using ArmResourceProviderDemo.WebModels.Traffic;
|
||||
using System.Collections.Generic;
|
||||
using ArmResourceProviderDemo.WebModels.Traffic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ArmResourceProviderDemo.Controllers
|
||||
{
|
||||
|
@ -9,7 +9,7 @@ namespace ArmResourceProviderDemo.Controllers
|
|||
[Route("[controller]")]
|
||||
public class TrafficController : ControllerBase
|
||||
{
|
||||
private static readonly Dictionary<string, TrafficResource> _db = new Dictionary<string, TrafficResource>();
|
||||
private static readonly Dictionary<string, TrafficResource> Db = new Dictionary<string, TrafficResource>();
|
||||
private readonly ILogger<TrafficController> _logger;
|
||||
|
||||
public TrafficController(ILogger<TrafficController> logger)
|
||||
|
@ -20,14 +20,14 @@ namespace ArmResourceProviderDemo.Controllers
|
|||
[HttpGet]
|
||||
public IEnumerable<TrafficResource> Get()
|
||||
{
|
||||
return _db.Values;
|
||||
return Db.Values;
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
public IActionResult Put(TrafficResource traffic)
|
||||
public TrafficResource Put(TrafficResource traffic)
|
||||
{
|
||||
_db[traffic.Id] = traffic;
|
||||
return Ok();
|
||||
Db[traffic.Id] = traffic;
|
||||
return traffic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
using ArmResourceProviderDemo.WebModels;
|
||||
using System.Collections.Generic;
|
||||
using ArmResourceProviderDemo.WebModels.Wind;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ArmResourceProviderDemo.Controllers
|
||||
{
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ArmResourceProviderDemo
|
||||
{
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
"commandLineArgs": "--internal-swagger",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger/v1/swagger.json",
|
||||
"applicationUrl": "http://localhost:8010",
|
||||
"applicationUrl": "http://127.0.0.1:8010",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ArmResourceProviderDemo.WebModels;
|
||||
using ArmResourceProviderDemo.WebModels.Traffic;
|
||||
using ArmResourceProviderDemo.WebModels.Wind;
|
||||
|
@ -8,16 +11,15 @@ using Microsoft.Extensions.Configuration;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using ActualParameterName = System.String;
|
||||
using ParameterName = System.String;
|
||||
|
||||
namespace ArmResourceProviderDemo
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
private readonly SwaggerConfig _swaggerConfig;
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
public Startup(IConfiguration configuration)
|
||||
|
@ -26,27 +28,27 @@ namespace ArmResourceProviderDemo
|
|||
|
||||
var genarateInternalSwagger = Environment.GetCommandLineArgs().Contains("--internal-swagger");
|
||||
var genarateExternalSwagger = !genarateInternalSwagger;
|
||||
var OdataReusableParameters = new List<string>() { "$filter", "$orderBy", "$skipToken", "$top" };
|
||||
_swaggerConfig = new SwaggerConfig
|
||||
{
|
||||
PolymorphicSchemaModels = new List<Type> { typeof(TrafficResource), typeof(WindResource) },
|
||||
ModelEnumsAsString = true,
|
||||
GlobalCommonReusableParameters = new Dictionary<string, Microsoft.OpenApi.Models.OpenApiParameter>()
|
||||
{
|
||||
{ "SomeGlobalParam", new OpenApiParameter {
|
||||
Description = "SomGlobalParam Description",
|
||||
Name = "testParamName",
|
||||
In = ParameterLocation.Path,
|
||||
Required = true,
|
||||
Schema = new OpenApiSchema()
|
||||
{
|
||||
Type = "string",
|
||||
MinLength = 1,
|
||||
},
|
||||
}
|
||||
{ "SomeGlobalParam", new OpenApiParameter {
|
||||
Description = "SomGlobalParam Description",
|
||||
Name = "testParamName",
|
||||
In = ParameterLocation.Path,
|
||||
Required = true,
|
||||
Schema = new OpenApiSchema()
|
||||
{
|
||||
Type = "string",
|
||||
MinLength = 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
ResourceProviderReusableParameters = OdataReusableParameters.Concat(new List<string> { "WorkspaceName" }).ToList(),
|
||||
ResourceProviderReusableParameters = new List<KeyValuePair<ParameterName, ActualParameterName>> {
|
||||
new KeyValuePair<ParameterName, ActualParameterName>("WorkspaceName", "WorkspaceName") },
|
||||
HideParametersEnabled = genarateExternalSwagger,
|
||||
GenerateExternalSwagger = genarateExternalSwagger,
|
||||
SupportedApiVersions = new[] { "v1" },
|
||||
|
@ -58,7 +60,6 @@ namespace ArmResourceProviderDemo
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
|
@ -67,18 +68,17 @@ namespace ArmResourceProviderDemo
|
|||
c.SerializerSettings.Converters.Add(new ResourceJsonConverter<TrafficResource, TrafficBaseProperties>(
|
||||
new Dictionary<string, Type>
|
||||
{
|
||||
{ "Israel", typeof(TrafficIsraelProperties)},
|
||||
{ "India", typeof(TrafficIndiaProperties)}
|
||||
{ "Israel", typeof(TrafficIsraelProperties) },
|
||||
{ "India", typeof(TrafficIndiaProperties) }
|
||||
}));
|
||||
c.SerializerSettings.Converters.Add(new ResourceJsonConverter<WindResource, WindBaseProperties>(
|
||||
new Dictionary<string, Type>
|
||||
{
|
||||
{ "IsraelWindKind", typeof(WindIsraelProperties)},
|
||||
{ "IndiaWindKind", typeof(WindIndiaProperties)}
|
||||
{ "IsraelWindKind", typeof(WindIsraelProperties) },
|
||||
{ "IndiaWindKind", typeof(WindIndiaProperties) }
|
||||
}));
|
||||
});
|
||||
services.AddAutorestCompliantSwagger(_swaggerConfig);
|
||||
|
||||
services.AddArmCompliantSwagger(_swaggerConfig);
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
@ -92,7 +92,7 @@ namespace ArmResourceProviderDemo
|
|||
app.UseSwagger(options =>
|
||||
{
|
||||
options.RouteTemplate = "swagger/{documentName}/swagger.json";
|
||||
// Change generated swagger version to 2.0
|
||||
// Change generated swagger version to 2.0
|
||||
options.SerializeAsV2 = true;
|
||||
});
|
||||
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ArmResourceProviderDemo.WebModels
|
||||
namespace ArmResourceProviderDemo.WebModels
|
||||
{
|
||||
public class Resource
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Etag { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ArmResourceProviderDemo.WebModels
|
||||
{
|
||||
|
@ -9,6 +9,7 @@ namespace ArmResourceProviderDemo.WebModels
|
|||
{
|
||||
TPropertiesBase Properties { get; set; }
|
||||
}
|
||||
|
||||
public class ResourceJsonConverter<TContainer, TPropertiesBase> : JsonConverter
|
||||
where TContainer : IPropertiesHolder<TPropertiesBase>
|
||||
where TPropertiesBase : class
|
||||
|
@ -19,6 +20,7 @@ namespace ArmResourceProviderDemo.WebModels
|
|||
{
|
||||
_kindToTypeMapping = kindToTypeMapping;
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType) => objectType == typeof(TContainer);
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
|
@ -37,6 +39,7 @@ namespace ArmResourceProviderDemo.WebModels
|
|||
|
||||
throw new JsonSerializationException($"Could not find the concrete type of {typeof(TPropertiesBase).Name} with kind: [{resouceKindString}]");
|
||||
}
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
public class ResourceProxy<TProps> : Resource
|
||||
{
|
||||
public string Kind { get; set; }
|
||||
|
||||
public TProps Properties { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
|
||||
namespace ArmResourceProviderDemo.WebModels.Speed
|
||||
{
|
||||
[SwaggerSchemaNameStrategy(NamingStrategy.ApplyToParentWrapper, "SpeedWrapper")]
|
||||
[SwaggerSchemaNameStrategy("SpeedCustomName")]
|
||||
|
||||
public class SpeedProperties
|
||||
{
|
||||
public int Speed { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,21 +1,13 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ArmResourceProviderDemo.WebModels.Traffic
|
||||
namespace ArmResourceProviderDemo.WebModels.Traffic
|
||||
{
|
||||
public class TrafficBaseProperties
|
||||
{
|
||||
|
||||
public int BaseProperty { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class TrafficIsraelProperties : TrafficBaseProperties
|
||||
{
|
||||
public int IsraelProperty { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class TrafficIndiaProperties : TrafficBaseProperties
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
|
||||
namespace ArmResourceProviderDemo.WebModels.Traffic
|
||||
{
|
||||
|
@ -12,8 +12,8 @@ namespace ArmResourceProviderDemo.WebModels.Traffic
|
|||
Type concreteTemplateType = typeof(VirtualInheritecePropertiesWrapperTemplate<>);
|
||||
Type israelTrafficConcreteType = concreteTemplateType.MakeGenericType(typeof(TrafficIsraelProperties));
|
||||
Type indiaTrafficConcreteType = concreteTemplateType.MakeGenericType(typeof(TrafficIndiaProperties));
|
||||
kindToInheritedMap["Israel"] = new VirtuallyInheritedObjectProperties(israelTrafficConcreteType);
|
||||
kindToInheritedMap["India"] = new VirtuallyInheritedObjectProperties(indiaTrafficConcreteType);
|
||||
kindToInheritedMap[TrafficKind.Israel.ToString()] = new VirtuallyInheritedObjectProperties(israelTrafficConcreteType);
|
||||
kindToInheritedMap[TrafficKind.India.ToString()] = new VirtuallyInheritedObjectProperties(indiaTrafficConcreteType);
|
||||
|
||||
return kindToInheritedMap;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
//using System.Text.Json.Serialization;
|
||||
|
||||
namespace ArmResourceProviderDemo.WebModels.Traffic
|
||||
{
|
||||
|
@ -6,5 +7,13 @@ namespace ArmResourceProviderDemo.WebModels.Traffic
|
|||
[SwaggerVirtualInheritances(typeof(TrafficKindsVirtualInheritanceProvider), nameof(TrafficResource))]
|
||||
public class TrafficResource : ResourceProxy<TrafficBaseProperties>, IPropertiesHolder<TrafficBaseProperties>
|
||||
{
|
||||
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||
public new TrafficKind Kind { get; set; }
|
||||
}
|
||||
|
||||
public enum TrafficKind
|
||||
{
|
||||
India,
|
||||
Israel
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
public int BaseProperty { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class WindIsraelProperties : WindBaseProperties
|
||||
{
|
||||
public int IsraelProperty { get; set; }
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
|
||||
namespace ArmResourceProviderDemo.WebModels.Wind
|
||||
{
|
||||
|
@ -14,14 +13,12 @@ namespace ArmResourceProviderDemo.WebModels.Wind
|
|||
inheritesClassName: "WindIsrael",
|
||||
childClassName: nameof(WindIsraelProperties),
|
||||
innerPropertyClassType: typeof(WindIsraelProperties),
|
||||
inheritesClassDescription: "Wind Israel description"
|
||||
);
|
||||
inheritesClassDescription: "Wind Israel description");
|
||||
kindToInheritedMap["IndiaWindKind"] = new VirtuallyInheritedObjectProperties(
|
||||
inheritesClassName: "WindIndia",
|
||||
childClassName: nameof(WindIndiaProperties),
|
||||
innerPropertyClassType: typeof(WindIndiaProperties),
|
||||
inheritesClassDescription: "Wind India description"
|
||||
);
|
||||
inheritesClassDescription: "Wind India description");
|
||||
|
||||
return kindToInheritedMap;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
|
||||
namespace ArmResourceProviderDemo.WebModels.Wind
|
||||
{
|
||||
//[JsonConverter(typeof(TrafficJsonConverter))]
|
||||
[SwaggerVirtualInheritances(typeof(WindKindsVirtualInheritanceProvider), nameof(WindResource))]
|
||||
public class WindResource : ResourceProxy<WindBaseProperties>, IPropertiesHolder<WindBaseProperties>
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
|
@ -6,8 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DocumentationFile>BasicWebAppDemo.xml</DocumentationFile>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<DocumentationFile>BasicWebAppDemo.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
<member name="T:BasicWebAppDemo.V1.WeatherForecastNetanya">
|
||||
<summary>
|
||||
Som description!
|
||||
</summary>
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:BasicWebAppDemo.V2.WeatherForecast.Properties">
|
||||
<summary>
|
||||
|
@ -48,7 +48,7 @@
|
|||
<member name="T:BasicWebAppDemo.V2.WeatherForecastNetanya">
|
||||
<summary>
|
||||
Som description!
|
||||
</summary>
|
||||
</summary>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
|
|
|
@ -3,9 +3,13 @@ namespace BasicWebAppDemo.Controllers
|
|||
public class ODataQueryResponse
|
||||
{
|
||||
public int Val { get; set; }
|
||||
|
||||
public string TestStr { get; set; }
|
||||
|
||||
public string Filter { get; set; }
|
||||
|
||||
public string OrderBy { get; set; }
|
||||
|
||||
public string SkipToken { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BasicWebAppDemo.WebModels.Examples;
|
||||
using BasicWebAppDemo.V1;
|
||||
using BasicWebAppDemo.WebModels.Examples;
|
||||
using Microsoft.AspNet.OData.Query;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace BasicWebAppDemo.Controllers
|
||||
{
|
||||
|
@ -15,29 +15,28 @@ namespace BasicWebAppDemo.Controllers
|
|||
[ApiController]
|
||||
[Route("WeatherForecast")]
|
||||
[ApiVersion("2021-09-01-preview")]
|
||||
[ApiVersionRange(fromVersion: "2021-09-01-preview", toVersion: "2022-01-01-preview")]
|
||||
[SwaggerApiVersionRange(fromVersion: "2021-09-01-preview", toVersion: "2022-01-01-preview")]
|
||||
public class WeatherForecastController : ControllerBase
|
||||
{
|
||||
public static IEnumerable<WeatherForecast> Db;
|
||||
private static readonly string[] Summaries = new[]
|
||||
{
|
||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
private readonly ILogger<WeatherForecastController> _logger;
|
||||
public static IEnumerable<WeatherForecast> _db;
|
||||
|
||||
public WeatherForecastController(ILogger<WeatherForecastController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
var rng = new Random();
|
||||
_db = Enumerable.Range(1, 5).Select(index => new WeatherForecastNetanya
|
||||
Db = Enumerable.Range(1, 5).Select(index => new WeatherForecastNetanya
|
||||
{
|
||||
Date = DateTime.Now.AddDays(index),
|
||||
TemperatureC = rng.Next(-20, 55),
|
||||
Summary = Summaries[rng.Next(Summaries.Length)]
|
||||
});
|
||||
_db.ToList().AddRange(
|
||||
|
||||
Db.ToList().AddRange(
|
||||
Enumerable.Range(1, 5).Select(index => new WeatherForecastEilat
|
||||
{
|
||||
Date = DateTime.Now.AddDays(index),
|
||||
|
@ -54,13 +53,13 @@ namespace BasicWebAppDemo.Controllers
|
|||
Tags = new[] { "forecast" })]
|
||||
[SwaggerResponse(200, "The WeatherForecast was fetched", typeof(IEnumerable<WeatherForecast>))]
|
||||
[SwaggerResponse(400, "invalid request")]
|
||||
//[SwaggerResponseExample(200, typeof(StringResponseExample))]
|
||||
[ResponseExample(200, typeof(ArrayWeatherForecastExample))]
|
||||
[RequestExample(typeof(GetWeatherForecastRequestExample))]
|
||||
[Example("myfolder", "sometitle")]
|
||||
[HttpGet]
|
||||
public IEnumerable<WeatherForecast> GetWeather([FromQuery, SwaggerParameter("WeatherForecast Id", Required = true)] string id)
|
||||
{
|
||||
return _db;
|
||||
return Db;
|
||||
}
|
||||
|
||||
[SwaggerOperation(
|
||||
|
@ -70,7 +69,7 @@ namespace BasicWebAppDemo.Controllers
|
|||
Tags = new[] { "forecast" })]
|
||||
[SwaggerResponse(200, "The WeatherForecast was fetched", typeof(WeatherForecast))]
|
||||
[SwaggerResponse(400, "invalid request")]
|
||||
//[SwaggerResponseExample(200, typeof(StringResponseExample))]
|
||||
//[SwaggerResponseExample(200, typeof(StringResponseExample))]
|
||||
[ResponseExample(200, typeof(WeatherForecastExample))]
|
||||
[HttpPost]
|
||||
public string PostWeather(WeatherForecast weather)
|
||||
|
@ -93,13 +92,13 @@ namespace BasicWebAppDemo.Controllers
|
|||
Tags = new[] { "forecast" })]
|
||||
[SwaggerResponse(200, "The WeatherForecast was fetched", typeof(WeatherForecast))]
|
||||
[SwaggerResponse(400, "invalid request")]
|
||||
//[SwaggerResponseExample(200, typeof(StringResponseExample))]
|
||||
//[SwaggerResponseExample(200, typeof(StringResponseExample))]
|
||||
[ResponseExample(200, typeof(WeatherForecastExample))]
|
||||
[RequestExample(typeof(GetWeatherForecastRequestExample))]
|
||||
[HttpGet("{geo}")]
|
||||
public WeatherForecast GetSpecificWeather(string someParam, string geo, [FromQuery, SwaggerParameter("WeatherForecast Id", Required = true)] string id)
|
||||
{
|
||||
return _db.First();
|
||||
return Db.First();
|
||||
}
|
||||
|
||||
[HideInDocs]
|
||||
|
@ -114,7 +113,7 @@ namespace BasicWebAppDemo.Controllers
|
|||
[HttpGet("InternalApi")]
|
||||
public IEnumerable<WeatherForecast> InternalApi([FromQuery, SwaggerParameter("WeatherForecast Id", Required = true)] string id)
|
||||
{
|
||||
return _db;
|
||||
return Db;
|
||||
}
|
||||
|
||||
[HttpGet("test1/{val}")]
|
||||
|
@ -122,6 +121,5 @@ namespace BasicWebAppDemo.Controllers
|
|||
{
|
||||
return new ODataQueryResponse { Val = val, TestStr = testStr, Filter = options.Filter.RawValue, OrderBy = options.OrderBy.RawValue, SkipToken = options.SkipToken.RawValue };
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BasicWebAppDemo.WebModels.Examples;
|
||||
using BasicWebAppDemo.V2;
|
||||
using BasicWebAppDemo.WebModels.Examples;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace BasicWebAppDemo.Controllers
|
||||
{
|
||||
|
@ -14,29 +14,28 @@ namespace BasicWebAppDemo.Controllers
|
|||
[ApiController]
|
||||
[Route("WeatherForecast")]
|
||||
[ApiVersion("2022-01-01-preview")]
|
||||
[ApiVersionRange(fromVersion: "2022-01-01-preview")]
|
||||
[SwaggerApiVersionRange(fromVersion: "2022-01-01-preview")]
|
||||
public class WeatherForecastV2Controller : ControllerBase
|
||||
{
|
||||
public static IEnumerable<WeatherForecast> Db;
|
||||
private static readonly string[] Summaries = new[]
|
||||
{
|
||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
private readonly ILogger<WeatherForecastV2Controller> _logger;
|
||||
public static IEnumerable<WeatherForecast> _db;
|
||||
|
||||
public WeatherForecastV2Controller(ILogger<WeatherForecastV2Controller> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
var rng = new Random();
|
||||
_db = Enumerable.Range(1, 5).Select(index => new WeatherForecastNetanya
|
||||
Db = Enumerable.Range(1, 5).Select(index => new WeatherForecastNetanya
|
||||
{
|
||||
Date = DateTime.Now.AddDays(index),
|
||||
TemperatureC = rng.Next(-20, 55),
|
||||
Summary = Summaries[rng.Next(Summaries.Length)]
|
||||
});
|
||||
_db.ToList().AddRange(
|
||||
|
||||
Db.ToList().AddRange(
|
||||
Enumerable.Range(1, 5).Select(index => new WeatherForecastEilat
|
||||
{
|
||||
Date = DateTime.Now.AddDays(index),
|
||||
|
@ -59,7 +58,7 @@ namespace BasicWebAppDemo.Controllers
|
|||
[HttpGet]
|
||||
public IEnumerable<WeatherForecast> GetWeather([FromQuery, SwaggerParameter("WeatherForecast Id", Required = true)] string id)
|
||||
{
|
||||
return _db;
|
||||
return Db;
|
||||
}
|
||||
|
||||
[SwaggerOperation(
|
||||
|
@ -69,7 +68,6 @@ namespace BasicWebAppDemo.Controllers
|
|||
Tags = new[] { "forecast" })]
|
||||
[SwaggerResponse(200, "The WeatherForecast was fetched", typeof(WeatherForecast))]
|
||||
[SwaggerResponse(400, "invalid request")]
|
||||
//[SwaggerResponseExample(200, typeof(StringResponseExample))]
|
||||
[ResponseExample(200, typeof(WeatherForecastExample))]
|
||||
[HttpPost]
|
||||
public string PostWeather(V2.WeatherForecast weather)
|
||||
|
@ -77,7 +75,6 @@ namespace BasicWebAppDemo.Controllers
|
|||
return weather.GetType().FullName;
|
||||
}
|
||||
|
||||
|
||||
[SwaggerOperation(
|
||||
Summary = "Get a weather forecast",
|
||||
Description = "fetches from Db",
|
||||
|
@ -85,13 +82,12 @@ namespace BasicWebAppDemo.Controllers
|
|||
Tags = new[] { "forecast" })]
|
||||
[SwaggerResponse(200, "The WeatherForecast was fetched", typeof(WeatherForecast))]
|
||||
[SwaggerResponse(400, "invalid request")]
|
||||
//[SwaggerResponseExample(200, typeof(StringResponseExample))]
|
||||
[ResponseExample(200, typeof(WeatherForecastExample))]
|
||||
[RequestExample(typeof(GetWeatherForecastRequestExample))]
|
||||
[HttpGet("{geo}")]
|
||||
public WeatherForecast GetSpecificWeather(string geo, [FromQuery, SwaggerParameter("WeatherForecast Id", Required = true)] string id)
|
||||
{
|
||||
return _db.First();
|
||||
return Db.First();
|
||||
}
|
||||
|
||||
[HideInDocs]
|
||||
|
@ -106,7 +102,7 @@ namespace BasicWebAppDemo.Controllers
|
|||
[HttpGet("InternalApi")]
|
||||
public IEnumerable<WeatherForecast> InternalApi([FromQuery, SwaggerParameter("WeatherForecast Id", Required = true)] string id)
|
||||
{
|
||||
return _db;
|
||||
return Db;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNet.OData.Extensions;
|
||||
using Microsoft.AspNet.OData.Formatter;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Microsoft.AspNet.OData.Query;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Azure.OpenApiExtensions.Options;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using ActualParameterName = System.String;
|
||||
using ParameterName = System.String;
|
||||
|
||||
namespace BasicWebAppDemo
|
||||
{
|
||||
|
@ -29,7 +30,13 @@ namespace BasicWebAppDemo
|
|||
|
||||
var genarateInternalSwagger = Environment.GetCommandLineArgs().Contains("--internal-swagger");
|
||||
var genarateExternalSwagger = !genarateInternalSwagger;
|
||||
var OdataReusableParameters = new List<string>() { "$filter", "$orderBy", "$skipToken", "$top" };
|
||||
var odataReusableParameters = new List<KeyValuePair<ParameterName, ActualParameterName>>() {
|
||||
new KeyValuePair<ParameterName, ParameterName>("$filter", "ODataFilter"),
|
||||
new KeyValuePair<ParameterName, ParameterName>("$orderBy", "ODataOrderBy"),
|
||||
new KeyValuePair<ParameterName, ParameterName>("$skipToken", "ODataSkipToken"),
|
||||
new KeyValuePair<ParameterName, ParameterName>("$top", "ODataTop"),
|
||||
new KeyValuePair<ParameterName, ParameterName>("$skip", "ODataSkip"),
|
||||
};
|
||||
_swaggerConfig = new SwaggerConfig
|
||||
{
|
||||
PolymorphicSchemaModels = new List<Type> { typeof(V1.WeatherForecast), typeof(V2.WeatherForecast) },
|
||||
|
@ -47,9 +54,12 @@ namespace BasicWebAppDemo
|
|||
MinLength = 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ResourceProviderReusableParameters = OdataReusableParameters.Concat(new List<string> { "WorkspaceName" }).ToList(),
|
||||
ResourceProviderReusableParameters = odataReusableParameters.Concat(
|
||||
new List<KeyValuePair<ParameterName, ActualParameterName>> {
|
||||
new KeyValuePair<ParameterName, ActualParameterName>("WorkspaceName", "WorkspaceName") })
|
||||
.ToList(),
|
||||
HideParametersEnabled = genarateExternalSwagger,
|
||||
GenerateExternalSwagger = genarateExternalSwagger,
|
||||
SupportedApiVersions = new[] { "2021-09-01-preview", "2022-01-01-preview", "2021-10-01" },
|
||||
|
@ -69,7 +79,7 @@ namespace BasicWebAppDemo
|
|||
{
|
||||
// Specify the default API Version as 1.0
|
||||
config.DefaultApiVersion = ApiVersion.Parse("2021-09-01-preview");
|
||||
// If the client hasn't specified the API version in the request, use the default API version number
|
||||
// If the client hasn't specified the API version in the request, use the default API version number
|
||||
config.AssumeDefaultVersionWhenUnspecified = true;
|
||||
// Advertise the API versions supported for the particular endpoint
|
||||
config.ReportApiVersions = true;
|
||||
|
@ -90,11 +100,10 @@ namespace BasicWebAppDemo
|
|||
{
|
||||
inputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/prs.odatatestxx-odata"));
|
||||
}
|
||||
|
||||
})
|
||||
.AddNewtonsoftJson();
|
||||
|
||||
services.AddAutorestCompliantSwagger(_swaggerConfig);
|
||||
services.AddArmCompliantSwagger(_swaggerConfig);
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
@ -106,7 +115,6 @@ namespace BasicWebAppDemo
|
|||
}
|
||||
app.UseApiVersioning();
|
||||
|
||||
|
||||
app.UseSwagger(options =>
|
||||
{
|
||||
options.RouteTemplate = "swagger/{documentName}/swagger.json";
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
public class SomeObj
|
||||
{
|
||||
public int MyProperty { get; set; }
|
||||
|
||||
public string MyPropertyStr { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
using BasicWebAppDemo.V1;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using BasicWebAppDemo.V1;
|
||||
using BasicWebAppDemo.WebModels.Common;
|
||||
using Microsoft.Azure.OpenApiExtensions.Helpers;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace BasicWebAppDemo.WebModels.Examples
|
||||
{
|
||||
|
@ -21,10 +21,8 @@ namespace BasicWebAppDemo.WebModels.Examples
|
|||
Summary = "Some summary1",
|
||||
Properties = new SomeObj { MyProperty = 1, MyPropertyStr = "str" }
|
||||
})
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class WeatherForecastExample : BaseExamplesProvider<WeatherForecastNetanya>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
using JsonSubTypes;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
using BasicWebAppDemo.WebModels.Common;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using BasicWebAppDemo.WebModels.Common;
|
||||
using JsonSubTypes;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace BasicWebAppDemo.V1
|
||||
{
|
||||
|
@ -13,22 +13,21 @@ namespace BasicWebAppDemo.V1
|
|||
/// Some Descriptive Summary Description (Reflected on your XML Comment -> and Swashbuckle read the XmlDocumentation file and enrich the schamas , see https://github.com/domaindrivendev/Swashbuckle.AspNetCore#include-descriptions-from-xml-comments)
|
||||
/// </summary>
|
||||
[AzureResource]
|
||||
[SwaggerSchema(Required = new[] { "TemperatureC" })]
|
||||
[SwaggerSchema(Required = new[] { "TemperatureC" })]
|
||||
[JsonConverter(typeof(JsonSubtypes), "kind")]
|
||||
[JsonSubtypes.KnownSubType(typeof(WeatherForecastNetanya), GeoJsonObjectKind.Netanya)]
|
||||
[JsonSubtypes.KnownSubType(typeof(WeatherForecastEilat), GeoJsonObjectKind.Eilat)]
|
||||
[ClientFlatten]
|
||||
abstract public class WeatherForecast
|
||||
public abstract class WeatherForecast
|
||||
{
|
||||
|
||||
[Required]
|
||||
[JsonProperty(PropertyName = "kind")]
|
||||
abstract public GeoJsonObjectKind Kind { get; set; }
|
||||
public abstract GeoJsonObjectKind Kind { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get or sets DateTime (this is internal comment and not be shown on swagger, as we use here SwaggerSchema that overrides it )
|
||||
/// </summary>
|
||||
[SwaggerSchema(Description = "External swagger description" )]
|
||||
[SwaggerSchema(Description = "External swagger description")]
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
[SwaggerSchema("The WeatherForecast Temperature Celsius", ReadOnly = true)]
|
||||
|
@ -46,10 +45,9 @@ namespace BasicWebAppDemo.V1
|
|||
public SomeObj Properties { get; set; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Som description!
|
||||
/// </summary>
|
||||
/// </summary>
|
||||
[SubTypeOf(typeof(WeatherForecast))]
|
||||
public class WeatherForecastNetanya : WeatherForecast
|
||||
{
|
||||
|
@ -57,9 +55,11 @@ namespace BasicWebAppDemo.V1
|
|||
{
|
||||
Kind = GeoJsonObjectKind.Netanya;
|
||||
}
|
||||
[Mutability(Mutability = MutabilityTypes.read)]
|
||||
|
||||
[Mutability(Mutability = MutabilityTypes.Read)]
|
||||
[ReadOnly(true)]
|
||||
public int SomeV1NetanyaProp { get; set; }
|
||||
|
||||
public override GeoJsonObjectKind Kind { get; set; }
|
||||
}
|
||||
|
||||
|
@ -70,8 +70,10 @@ namespace BasicWebAppDemo.V1
|
|||
{
|
||||
Kind = GeoJsonObjectKind.Eilat;
|
||||
}
|
||||
|
||||
[ReadOnly(true)]
|
||||
public int SomeV1EilatProp { get; set; }
|
||||
|
||||
public override GeoJsonObjectKind Kind { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
using JsonSubTypes;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
using BasicWebAppDemo.WebModels.Common;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using BasicWebAppDemo.WebModels.Common;
|
||||
using JsonSubTypes;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace BasicWebAppDemo.V2
|
||||
{
|
||||
|
@ -14,12 +14,12 @@ namespace BasicWebAppDemo.V2
|
|||
[JsonSubtypes.KnownSubType(typeof(WeatherForecastNetanya), GeoJsonObjectKind.Netanya)]
|
||||
[JsonSubtypes.KnownSubType(typeof(WeatherForecastEilat), GeoJsonObjectKind.Eilat)]
|
||||
[ClientFlatten]
|
||||
abstract public class WeatherForecast
|
||||
public abstract class WeatherForecast
|
||||
{
|
||||
|
||||
[Required]
|
||||
[JsonProperty(PropertyName = "kind")]
|
||||
abstract public GeoJsonObjectKind Kind { get; set; }
|
||||
public abstract GeoJsonObjectKind Kind { get; set; }
|
||||
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
[SwaggerSchema("The WeatherForecast Temperature Celsius", ReadOnly = true)]
|
||||
|
@ -41,11 +41,9 @@ namespace BasicWebAppDemo.V2
|
|||
public string Version { get; set; } = "2";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Som description!
|
||||
/// </summary>
|
||||
/// </summary>
|
||||
[SubTypeOf(typeof(WeatherForecast))]
|
||||
public class WeatherForecastNetanya : WeatherForecast
|
||||
{
|
||||
|
@ -53,9 +51,11 @@ namespace BasicWebAppDemo.V2
|
|||
{
|
||||
Kind = GeoJsonObjectKind.Netanya;
|
||||
}
|
||||
[Mutability(Mutability = MutabilityTypes.read)]
|
||||
|
||||
[Mutability(Mutability = MutabilityTypes.Read)]
|
||||
[ReadOnly(true)]
|
||||
public int SomeV2NetanyaProp { get; set; }
|
||||
|
||||
public override GeoJsonObjectKind Kind { get; set; }
|
||||
}
|
||||
|
||||
|
@ -66,8 +66,10 @@ namespace BasicWebAppDemo.V2
|
|||
{
|
||||
Kind = GeoJsonObjectKind.Eilat;
|
||||
}
|
||||
|
||||
[ReadOnly(true)]
|
||||
public int SomeV2EilatProp { get; set; }
|
||||
|
||||
public override GeoJsonObjectKind Kind { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
using SimpleKindArmResourceProviderDemo.WebModels;
|
||||
using SimpleKindArmResourceProviderDemo.WebModels.Traffic;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using SimpleKindArmResourceProviderDemo.WebModels.Traffic;
|
||||
|
||||
namespace SimpleKindArmResourceProviderDemo.Controllers
|
||||
{
|
||||
|
@ -13,7 +9,7 @@ namespace SimpleKindArmResourceProviderDemo.Controllers
|
|||
[Route("[controller]")]
|
||||
public class TrafficController : ControllerBase
|
||||
{
|
||||
private static readonly Dictionary<string, TrafficResource> _db = new Dictionary<string, TrafficResource>();
|
||||
private static readonly Dictionary<string, TrafficResource> Db = new Dictionary<string, TrafficResource>();
|
||||
private readonly ILogger<TrafficController> _logger;
|
||||
|
||||
public TrafficController(ILogger<TrafficController> logger)
|
||||
|
@ -24,13 +20,13 @@ namespace SimpleKindArmResourceProviderDemo.Controllers
|
|||
[HttpGet]
|
||||
public IEnumerable<TrafficResource> Get()
|
||||
{
|
||||
return _db.Values;
|
||||
return Db.Values;
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
public IActionResult Put(TrafficResource traffic)
|
||||
{
|
||||
_db[traffic.Id] = traffic;
|
||||
Db[traffic.Id] = traffic;
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
using SimpleKindArmResourceProviderDemo.WebModels;
|
||||
using SimpleKindArmResourceProviderDemo.WebModels.Wind;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using SimpleKindArmResourceProviderDemo.WebModels.Wind;
|
||||
|
||||
namespace SimpleKindArmResourceProviderDemo.Controllers
|
||||
{
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
|
||||
namespace SimpleKindArmResourceProviderDemo
|
||||
{
|
||||
public class Program
|
||||
|
|
|
@ -6,9 +6,12 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DocumentationFile>SimpleKindArmResourceProviderDemo.xml</DocumentationFile>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!--<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />-->
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\OpenApiExtensions\OpenApiExtensions.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using SimpleKindArmResourceProviderDemo.WebModels;
|
||||
using SimpleKindArmResourceProviderDemo.WebModels.Traffic;
|
||||
using SimpleKindArmResourceProviderDemo.WebModels.Wind;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Azure.OpenApiExtensions.Options;
|
||||
|
@ -8,16 +8,17 @@ using Microsoft.Extensions.Configuration;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using SimpleKindArmResourceProviderDemo.WebModels.Traffic;
|
||||
using SimpleKindArmResourceProviderDemo.WebModels.Wind;
|
||||
using ActualParameterName = System.String;
|
||||
using ParameterName = System.String;
|
||||
|
||||
namespace SimpleKindArmResourceProviderDemo
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
private readonly SwaggerConfig _swaggerConfig;
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
public Startup(IConfiguration configuration)
|
||||
|
@ -26,7 +27,7 @@ namespace SimpleKindArmResourceProviderDemo
|
|||
|
||||
var genarateInternalSwagger = Environment.GetCommandLineArgs().Contains("--internal-swagger");
|
||||
var genarateExternalSwagger = !genarateInternalSwagger;
|
||||
var OdataReusableParameters = new List<string>() { "$filter", "$orderBy", "$skipToken", "$top" };
|
||||
|
||||
_swaggerConfig = new SwaggerConfig
|
||||
{
|
||||
PolymorphicSchemaModels = new List<Type> { typeof(TrafficResource), typeof(WindResource) },
|
||||
|
@ -44,9 +45,10 @@ namespace SimpleKindArmResourceProviderDemo
|
|||
MinLength = 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ResourceProviderReusableParameters = OdataReusableParameters.Concat(new List<string> { "WorkspaceName" }).ToList(),
|
||||
ResourceProviderReusableParameters = new List<KeyValuePair<ParameterName, ActualParameterName>> {
|
||||
new KeyValuePair<ParameterName, ActualParameterName>("WorkspaceName", "WorkspaceName") },
|
||||
HideParametersEnabled = genarateExternalSwagger,
|
||||
GenerateExternalSwagger = genarateExternalSwagger,
|
||||
SupportedApiVersions = new[] { "v1" },
|
||||
|
@ -58,15 +60,13 @@ namespace SimpleKindArmResourceProviderDemo
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddControllers().AddNewtonsoftJson(c =>
|
||||
{
|
||||
});
|
||||
services.AddAutorestCompliantSwagger(_swaggerConfig);
|
||||
|
||||
services.AddArmCompliantSwagger(_swaggerConfig);
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
@ -77,7 +77,22 @@ namespace SimpleKindArmResourceProviderDemo
|
|||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.UseAutorestCompliantSwagger(_swaggerConfig);
|
||||
app.UseSwagger(options =>
|
||||
{
|
||||
options.RouteTemplate = "swagger/{documentName}/swagger.json";
|
||||
// Change generated swagger version to 2.0
|
||||
options.SerializeAsV2 = true;
|
||||
});
|
||||
|
||||
app.UseSwaggerUI(option =>
|
||||
{
|
||||
IEnumerable<string> actualDocumentsToGenerate = _swaggerConfig.SupportedApiVersions;
|
||||
if (actualDocumentsToGenerate == null || !actualDocumentsToGenerate.Any())
|
||||
{
|
||||
actualDocumentsToGenerate = new[] { _swaggerConfig.DefaultApiVersion };
|
||||
}
|
||||
actualDocumentsToGenerate.ToList().ForEach(v => option.SwaggerEndpoint($"/swagger/{v}/swagger.json", v));
|
||||
});
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SimpleKindArmResourceProviderDemo.WebModels
|
||||
namespace SimpleKindArmResourceProviderDemo.WebModels
|
||||
{
|
||||
public class Resource
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Etag { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace SimpleKindArmResourceProviderDemo.WebModels
|
||||
{
|
||||
|
@ -9,6 +9,7 @@ namespace SimpleKindArmResourceProviderDemo.WebModels
|
|||
{
|
||||
TPropertiesBase Properties { get; set; }
|
||||
}
|
||||
|
||||
public class ResourceJsonConverter<TContainer, TPropertiesBase> : JsonConverter
|
||||
where TContainer : IPropertiesHolder<TPropertiesBase>
|
||||
where TPropertiesBase : class
|
||||
|
@ -19,6 +20,7 @@ namespace SimpleKindArmResourceProviderDemo.WebModels
|
|||
{
|
||||
_kindToTypeMapping = kindToTypeMapping;
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType) => objectType == typeof(TContainer);
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
|
@ -37,6 +39,7 @@ namespace SimpleKindArmResourceProviderDemo.WebModels
|
|||
|
||||
throw new JsonSerializationException($"Could not find the concrete type of {typeof(TPropertiesBase).Name} with kind: [{resouceKindString}]");
|
||||
}
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
public class ResourceProxy<TProps> : Resource
|
||||
{
|
||||
public string Kind { get; set; }
|
||||
|
||||
public TProps Properties { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,17 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SimpleKindArmResourceProviderDemo.WebModels.Traffic
|
||||
namespace SimpleKindArmResourceProviderDemo.WebModels.Traffic
|
||||
{
|
||||
public class TrafficBaseProperties
|
||||
{
|
||||
|
||||
public int BaseProperty { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class TrafficEnglandProperties : TrafficBaseProperties
|
||||
{
|
||||
public int EnglandProperty { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class TrafficUsaProperties : TrafficBaseProperties
|
||||
{
|
||||
public int UsaProperty { get; set; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Helpers;
|
||||
using SimpleKindArmResourceProviderDemo.WebModels.Wind;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using Microsoft.Azure.OpenApiExtensions.Helpers;
|
||||
|
||||
namespace SimpleKindArmResourceProviderDemo.WebModels.Traffic
|
||||
{
|
||||
|
@ -12,26 +7,28 @@ namespace SimpleKindArmResourceProviderDemo.WebModels.Traffic
|
|||
{
|
||||
protected override string GetChildSwaggerDisplayName(CountryKind kindValue)
|
||||
{
|
||||
|
||||
return $"{kindValue.ToString().ToUpper()}WindProperties";
|
||||
return $"{kindValue.ToString().ToUpper()}TrafficProperties";
|
||||
}
|
||||
|
||||
protected override string GetDescription(CountryKind kindValue)
|
||||
{
|
||||
return $"kind:{kindValue} description";
|
||||
|
||||
return $"kind:{kindValue} description";
|
||||
}
|
||||
|
||||
protected override string GetParentSwaggerDisplayName(CountryKind kindValue)
|
||||
{
|
||||
return $"{kindValue.ToString().ToUpper()}Wind";
|
||||
return $"{kindValue.ToString().ToUpper()}Traffic";
|
||||
}
|
||||
|
||||
protected override Type GetPropertiesClass(CountryKind kindValue)
|
||||
{
|
||||
TextInfo info = CultureInfo.CurrentCulture.TextInfo;
|
||||
return this.GetType().Assembly.GetType($"SimpleKindArmResourceProviderDemo.WebModels.Wind.Wind{info.ToTitleCase(kindValue.ToString())}Properties");
|
||||
string propertiesClassName = $"SimpleKindArmResourceProviderDemo.WebModels.Traffic.Traffic{ToCamelCase(kindValue)}Properties";
|
||||
return GetType().Assembly.GetType(propertiesClassName);
|
||||
}
|
||||
|
||||
private string ToCamelCase(CountryKind kindValue)
|
||||
{
|
||||
return string.Concat(kindValue.ToString()[0].ToString().ToUpper(), kindValue.ToString().ToLower().AsSpan(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using Microsoft.Azure.OpenApiExtensions.Helpers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SimpleKindArmResourceProviderDemo.WebModels.Traffic
|
||||
{
|
||||
|
@ -7,17 +8,16 @@ namespace SimpleKindArmResourceProviderDemo.WebModels.Traffic
|
|||
public class TrafficResource
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public CountryKind kind { get; set; }
|
||||
|
||||
public TrafficBaseProperties properties { get; set; }
|
||||
[JsonProperty("kind")]
|
||||
public CountryKind Kind { get; set; }
|
||||
|
||||
public TrafficBaseProperties Properties { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public enum CountryKind
|
||||
{
|
||||
USA,
|
||||
ENGLAND
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
public int BaseProperty { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class WindIsraelProperties : WindBaseProperties
|
||||
{
|
||||
public int IsraelProperty { get; set; }
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Helpers;
|
||||
using SimpleKindArmResourceProviderDemo.WebModels.Traffic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.OpenApiExtensions.Helpers;
|
||||
using SimpleKindArmResourceProviderDemo.WebModels.Traffic;
|
||||
|
||||
namespace SimpleKindArmResourceProviderDemo.WebModels.Wind
|
||||
{
|
||||
|
@ -18,18 +15,18 @@ namespace SimpleKindArmResourceProviderDemo.WebModels.Wind
|
|||
{
|
||||
switch (kindValue)
|
||||
{
|
||||
case CountryKind.USA:
|
||||
{
|
||||
case CountryKind.USA:
|
||||
{
|
||||
return "Kind for United States of America";
|
||||
}
|
||||
}
|
||||
case CountryKind.ENGLAND:
|
||||
{
|
||||
return "Kind for Great Britan";
|
||||
}
|
||||
{
|
||||
return "Kind for Great Britan";
|
||||
}
|
||||
default:
|
||||
{
|
||||
return $"Other kind:{kindValue}";
|
||||
}
|
||||
{
|
||||
return $"Other kind:{kindValue}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,17 +40,17 @@ namespace SimpleKindArmResourceProviderDemo.WebModels.Wind
|
|||
switch (kindValue)
|
||||
{
|
||||
case CountryKind.USA:
|
||||
{
|
||||
{
|
||||
return typeof(TrafficUsaProperties);
|
||||
}
|
||||
case CountryKind.ENGLAND:
|
||||
{
|
||||
return typeof(TrafficEnglandProperties) ;
|
||||
}
|
||||
{
|
||||
return typeof(TrafficEnglandProperties);
|
||||
}
|
||||
default:
|
||||
{
|
||||
return typeof(TrafficBaseProperties);
|
||||
}
|
||||
{
|
||||
return typeof(TrafficBaseProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ using Microsoft.Azure.OpenApiExtensions.Helpers;
|
|||
using SimpleKindArmResourceProviderDemo.WebModels.Traffic;
|
||||
|
||||
namespace SimpleKindArmResourceProviderDemo.WebModels.Wind
|
||||
{
|
||||
{
|
||||
[SwaggerVirtualInheritances(typeof(SimpleKindVirtualInheritanceProvider<CountryKind>), typeof(WindDetailedItemProvider), typeof(CountryKind), "kind")]
|
||||
public class WindResource : ResourceProxy<WindBaseProperties>, IPropertiesHolder<WindBaseProperties>
|
||||
{
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<!-- NuGet package properties -->
|
||||
<Company>Microsoft</Company>
|
||||
<Authors>Microsoft Azure Sentinal Team</Authors>
|
||||
<Version>2.0.0</Version>
|
||||
<Copyright>Copyright (c) Microsoft Corporation</Copyright>
|
||||
<OutputType>Library</OutputType>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -12,7 +12,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can be string of format with the following Directives: {GenericType}
|
||||
/// Can be string of format with the following Directives: {GenericType}
|
||||
/// </summary>
|
||||
/// <example>List of {GenericType} models</example>
|
||||
public string DescriptionFormat { get; }
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
{
|
||||
ExternalSchemaName = externalSchemaName;
|
||||
DefinitionLevel = definitionLevel;
|
||||
NotInheritedPropertiesName = notInheritedPropertiesName;
|
||||
NotInheritedPropertiesName = notInheritedPropertiesName;
|
||||
}
|
||||
|
||||
public string ExternalSchemaName { get; private set; }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
||||
{
|
||||
|
@ -11,8 +11,9 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
public class ExampleAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ExamplesAttribute"/> class.
|
||||
/// Initializes a new instance of the.
|
||||
/// </summary>
|
||||
/// <param name="folder"></param>
|
||||
/// <param name="title">OperationId Eg: DerivedModels_Get.</param>
|
||||
public ExampleAttribute(string folder, string title)
|
||||
{
|
||||
|
@ -21,8 +22,8 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
throw new ArgumentNullException(nameof(title));
|
||||
}
|
||||
|
||||
this.Title = title;
|
||||
this.FilePath = $"{folder}/" + title;
|
||||
Title = title;
|
||||
FilePath = $"{folder}/" + title;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// A marker attribute which can be applied to an API or controller to hide from docs.
|
||||
/// A marker attribute which can be applied to an API or controller to hide from docs.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
|
||||
public class HideInDocsAttribute : Attribute
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
throw new ArgumentNullException(nameof(parameterNames));
|
||||
}
|
||||
|
||||
this.ParameterNames = new HashSet<string>(parameterNames);
|
||||
ParameterNames = new HashSet<string>(parameterNames);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
||||
{
|
||||
|
@ -11,17 +11,17 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
/// <summary>
|
||||
/// Indicates that the value of the property can be read.
|
||||
/// </summary>
|
||||
read = 0x0,
|
||||
Read = 0x0,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the value of the property can be set while creating/initializing/constructing the object.
|
||||
/// </summary>
|
||||
create = 0x1,
|
||||
Create = 0x1,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that value of the property can be updated anytime(even after the object is created).
|
||||
/// </summary>
|
||||
update = 0x2,
|
||||
Update = 0x2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -40,6 +40,6 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
/// <summary>
|
||||
/// Gets or sets mutablility of a field Eg: [Mutable(Mutability = MutabilityTypes.create | MutabilityTypes.read)].
|
||||
/// </summary>
|
||||
public MutabilityTypes Mutability { get; set; } = MutabilityTypes.create | MutabilityTypes.read | MutabilityTypes.update;
|
||||
public MutabilityTypes Mutability { get; set; } = MutabilityTypes.Create | MutabilityTypes.Read | MutabilityTypes.Update;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,12 +16,12 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
/// <param name="statusCode">HTTP status codes of response.</param>
|
||||
public ProducesContentTypeAttribute(string contentType, int statusCode)
|
||||
{
|
||||
this.ContentType = contentType;
|
||||
ContentType = contentType;
|
||||
|
||||
// Validate input content type.
|
||||
MediaTypeHeaderValue.Parse(contentType);
|
||||
|
||||
this.StatusCode = statusCode;
|
||||
StatusCode = statusCode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
||||
|
||||
{
|
||||
/// <summary>
|
||||
/// Model properties marked with this attribute can only be part of response objects and should never be set in request.
|
||||
|
@ -14,7 +13,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
/// <param name="isReadOnlyProperty">true to show that the property this attribute is bound to is read-only.</param>
|
||||
public ReadOnlyPropertyAttribute(bool isReadOnlyProperty)
|
||||
{
|
||||
this.IsReadOnlyProperty = isReadOnlyProperty;
|
||||
IsReadOnlyProperty = isReadOnlyProperty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Helpers;
|
||||
using Microsoft.Azure.OpenApiExtensions.Helpers;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
||||
|
@ -6,8 +6,13 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||
public class ResponseExampleAttribute : Attribute
|
||||
{
|
||||
|
||||
public ResponseExampleAttribute(int httpCode, Type exampleTypeProvider)
|
||||
/// <summary>
|
||||
/// Init new class that implements ExampleTypeProvider, to provide example for a controller's response
|
||||
/// </summary>
|
||||
/// <param name="httpCode"></param>
|
||||
/// <param name="exampleTypeProvider">The type of ExampleTypeProvider to initiate</param>
|
||||
/// <param name="exampleName">Optional. For support multiple examples by example name in single ExampleTypeProvider</param>
|
||||
public ResponseExampleAttribute(int httpCode, Type exampleTypeProvider, string exampleName = null)
|
||||
{
|
||||
HttpCode = httpCode;
|
||||
ExampleTypeProvider = exampleTypeProvider ?? throw new ArgumentNullException(nameof(exampleTypeProvider));
|
||||
|
@ -16,7 +21,15 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
{
|
||||
throw new InvalidOperationException($"Example object {exampleTypeProvider.Name} must implement the interface {nameof(IExamplesProvider)}");
|
||||
}
|
||||
ExampleProviderInstance = (IExamplesProvider)Activator.CreateInstance(exampleTypeProvider);
|
||||
|
||||
if (exampleName == null)
|
||||
{
|
||||
ExampleProviderInstance = (IExamplesProvider)Activator.CreateInstance(exampleTypeProvider);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExampleProviderInstance = (IExamplesProvider)Activator.CreateInstance(exampleTypeProvider, exampleName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -34,8 +47,12 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||||
public class RequestExampleAttribute : Attribute
|
||||
{
|
||||
|
||||
public RequestExampleAttribute(Type exampleTypeProvider)
|
||||
/// <summary>
|
||||
/// Init new class that implements ExampleTypeProvider, to provide example for a controller's request
|
||||
/// </summary>
|
||||
/// <param name="exampleTypeProvider">The type of ExampleTypeProvider to initiate</param>
|
||||
/// <param name="exampleName">Optional. For support multiple examples by example name in single ExampleTypeProvider</param>
|
||||
public RequestExampleAttribute(Type exampleTypeProvider, string exampleName = null)
|
||||
{
|
||||
ExampleTypeProvider = exampleTypeProvider ?? throw new ArgumentNullException(nameof(exampleTypeProvider));
|
||||
|
||||
|
@ -43,7 +60,15 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
{
|
||||
throw new InvalidOperationException($"Example object {exampleTypeProvider.Name} must implement the interface {nameof(IExamplesProvider)}");
|
||||
}
|
||||
ExampleProviderInstance = (IExamplesProvider)Activator.CreateInstance(exampleTypeProvider);
|
||||
|
||||
if (exampleName == null)
|
||||
{
|
||||
ExampleProviderInstance = (IExamplesProvider)Activator.CreateInstance(exampleTypeProvider);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExampleProviderInstance = (IExamplesProvider)Activator.CreateInstance(exampleTypeProvider, exampleName);
|
||||
}
|
||||
}
|
||||
|
||||
public Type ExampleTypeProvider { get; }
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
/// <param name="parent"></param>
|
||||
public SubTypeOfAttribute(Type parent)
|
||||
{
|
||||
this.Parent = parent;
|
||||
Parent = parent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
|
||||
public class SwaggerApiVersionRangeAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Range of supported versions
|
||||
/// </summary>
|
||||
/// <param name="fromVersion">inclusive</param>
|
||||
/// <param name="toVersion">non inclusive</param>
|
||||
public SwaggerApiVersionRangeAttribute(string fromVersion, string toVersion = null)
|
||||
{
|
||||
if (fromVersion is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(fromVersion));
|
||||
}
|
||||
FromVersion = ApiVersion.Parse(fromVersion);
|
||||
if (toVersion != null)
|
||||
{
|
||||
ToVersion = ApiVersion.Parse(toVersion);
|
||||
}
|
||||
}
|
||||
|
||||
public ApiVersion FromVersion { get; }
|
||||
public ApiVersion ToVersion { get; }
|
||||
}
|
||||
}
|
|
@ -3,8 +3,8 @@
|
|||
namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// enable hiding parameters from swagger docs
|
||||
/// </summary>
|
||||
/// enable hiding parameters from swagger docs
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
|
||||
public class SwaggerHideParameterAttribute : Attribute
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Helpers;
|
||||
using Microsoft.Azure.OpenApiExtensions.Helpers;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
||||
|
@ -10,7 +10,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
ApplyToParentWrapper,
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum, AllowMultiple = false)]
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum, AllowMultiple = true, Inherited = true)]
|
||||
public class SwaggerSchemaNameStrategyAttribute : Attribute
|
||||
{
|
||||
public SwaggerSchemaNameStrategyAttribute(NamingStrategy namingStrategy, Type customNameProvider = null)
|
||||
|
@ -42,11 +42,11 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
|
||||
public class ConstNameProvider : ICustomSchemaNameProvider
|
||||
{
|
||||
public string _name;
|
||||
public string Name { get; }
|
||||
public ConstNameProvider(string name)
|
||||
{
|
||||
_name = name;
|
||||
Name = name;
|
||||
}
|
||||
public string GetCustomName(Type type) => _name;
|
||||
public string GetCustomName(Type type) => Name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
{
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
|
||||
public class SwaggerTypeAttribute : Attribute
|
||||
{
|
||||
{
|
||||
public SwaggerTypeAttribute(string typeName)
|
||||
{
|
||||
{
|
||||
TypeName = typeName;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Helpers;
|
||||
using Microsoft.Azure.OpenApiExtensions.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||
public class SwaggerVirtualInheritancesAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="VirtualInheritancesProviderType">Type of Provider for inheritance. Must Implement IVirtualInheritancesProvider</param>
|
||||
/// <param name="InheritedFromName">Name of the parent object</param>
|
||||
/// <param name="Discriminator">Field of the parent object that discrimante between different values. Default is "kind"</param>
|
||||
|
@ -26,14 +22,11 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
throw new ArgumentException($"argument must be assignable from {nameof(IVirtualInheritancesProvider)}, and must own a valid {nameof(IVirtualInheritancesProvider.GetVirtualInheritances)} method", nameof(VirtualInheritancesProviderType));
|
||||
}
|
||||
|
||||
this.VirtualInheritancesProvider = (IVirtualInheritancesProvider)Activator.CreateInstance(VirtualInheritancesProviderType);
|
||||
VirtualInheritancesProvider = (IVirtualInheritancesProvider)Activator.CreateInstance(VirtualInheritancesProviderType);
|
||||
this.InheritedFromName = InheritedFromName;
|
||||
this.Discriminator = Discriminator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="simpleKindVirtualInheritanceProvider">Type of Provider for inheritance. Must Implement SimpleKindVirtualInheritanceProvider</param>
|
||||
/// <param name="virtuallyInheritedItemDetails">Type for an object that provide the child attributes per each discrimantor</param>
|
||||
/// <param name="enumType">Enum represent the discrimantor. simpleKindVirtualInheritanceProvider and virtuallyInheritedItemDetails get the enumType as generics</param>
|
||||
|
@ -45,20 +38,19 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
throw new ArgumentNullException(nameof(enumType));
|
||||
}
|
||||
|
||||
ValidationUtils.ValidateIsAssignableToGenericType(typeof(SimpleKindVirtualInheritanceProvider<>),enumType, simpleKindVirtualInheritanceProvider);
|
||||
ValidationUtils.ValidateIsAssignableToGenericType(typeof(SimpleKindVirtualInheritanceProvider<>), enumType, simpleKindVirtualInheritanceProvider);
|
||||
|
||||
ValidationUtils.ValidateIsAssignableToGenericType(typeof(IVirtuallyInheritedItemDetails<>), enumType, virtuallyInheritedItemDetails);
|
||||
|
||||
ValidationUtils.ValidateIsAssignableToGenericType(typeof(IVirtuallyInheritedItemDetails<>), enumType, virtuallyInheritedItemDetails);
|
||||
|
||||
var virtuallyInheritedItemDetailsInstance = Activator.CreateInstance(virtuallyInheritedItemDetails);
|
||||
//var bla = new SimpleKindVirtualInheritanceProvider<CountryKind>(typeof(CountryKind), new WindDetailedItemProvider());
|
||||
this.VirtualInheritancesProvider = (IVirtualInheritancesProvider)Activator.CreateInstance(simpleKindVirtualInheritanceProvider,enumType, virtuallyInheritedItemDetailsInstance);
|
||||
VirtualInheritancesProvider = (IVirtualInheritancesProvider)Activator.CreateInstance(simpleKindVirtualInheritanceProvider, enumType, virtuallyInheritedItemDetailsInstance);
|
||||
this.Discriminator = Discriminator;
|
||||
}
|
||||
|
||||
public IVirtualInheritancesProvider VirtualInheritancesProvider { get; }
|
||||
public string InheritedFromName { get; }
|
||||
public string Discriminator { get; }
|
||||
|
||||
}
|
||||
|
||||
public interface IVirtualInheritancesProvider
|
||||
|
@ -101,7 +93,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Attributes
|
|||
[SwaggerSchemaNameStrategyAttribute(NamingStrategy.Custom, typeof(GenericArgumentPropertiesSuffixRemover))]
|
||||
public class VirtualInheritecePropertiesWrapperTemplate<TPropsType>
|
||||
{
|
||||
public TPropsType properties { get; set; }
|
||||
public TPropsType Properties { get; set; }
|
||||
}
|
||||
|
||||
public class GenericArgumentPropertiesSuffixRemover : ICustomSchemaNameProvider
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Options;
|
||||
using Microsoft.Azure.OpenApiExtensions.Options;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
@ -16,6 +16,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
{
|
||||
_config = config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies filter.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -18,7 +18,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
/// <summary>
|
||||
/// Adds x-ms-examples extention to every opertaion. Must run after SetOperationIdFilter.
|
||||
/// By default, it will add ./examples/{RelativePath}/{opetationId}.json to all the operations.
|
||||
/// Additional examples can be added using <see cref="ExamplesAttribute"/>.
|
||||
/// Additional examples can be added using <see cref="ExampleAttribute"/>.
|
||||
/// Eg: <code>
|
||||
/// "x-ms-examples": {
|
||||
/// "DerivedModels_ListBySubscription": {
|
||||
|
@ -29,7 +29,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
/// <see href="https://github.com/Azure/autorest/tree/master/docs/extensions#x-ms-examples">x-ms-examples.</see>
|
||||
public class ExampleFilter : IDocumentFilter
|
||||
{
|
||||
private SwaggerConfig _config;
|
||||
private readonly SwaggerConfig _config;
|
||||
public const string ExamplesFolderPath = "./examples/";
|
||||
|
||||
public ExampleFilter(SwaggerConfig config)
|
||||
|
@ -41,7 +41,8 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
/// Applies filter.
|
||||
/// </summary>
|
||||
/// <param name="operation">OpenApiOperation.</param>
|
||||
/// <param name="context">DocumentFilterContext.</param>
|
||||
/// <param name="apiDescription"></param>
|
||||
/// <param name="info"></param>
|
||||
public void ApplyWithVersion(OpenApiOperation operation, ApiDescription apiDescription, OpenApiInfo info)
|
||||
{
|
||||
if (_config.GenerateExternalSwagger)
|
||||
|
@ -91,9 +92,9 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
if (requestExampleAttributes.Any())
|
||||
{
|
||||
var requestExample = requestExampleAttributes.First().ExampleProviderInstance.GetExample();
|
||||
if ((requestExample as BasicAsiRequestExample) != null && ((BasicAsiRequestExample)requestExample).ApiVersion == null)
|
||||
if ((requestExample as IApiVersionableRequestExample) != null && ((IApiVersionableRequestExample)requestExample).ApiVersion == null)
|
||||
{
|
||||
((BasicAsiRequestExample)requestExample).ApiVersion = docName;
|
||||
((IApiVersionableRequestExample)requestExample).ApiVersion = docName;
|
||||
}
|
||||
exampleObj.Parameters = requestExample;
|
||||
}
|
||||
|
@ -122,7 +123,6 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
ApplyWithVersion(operation, apiDescription, swaggerDoc.Info);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class SwaggerOperationExample
|
||||
|
@ -131,11 +131,9 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
{
|
||||
Parameters = new object();
|
||||
Responses = new Dictionary<string, object>();
|
||||
|
||||
}
|
||||
public object Parameters { get; set; }
|
||||
public Dictionary<string, object> Responses { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
|
@ -9,15 +9,15 @@ using Swashbuckle.AspNetCore.SwaggerGen;
|
|||
namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
||||
{
|
||||
/// <summary>
|
||||
/// A conditional operation filter to hide an API paramater .
|
||||
/// A conditional operation filter to hide an API paramater .
|
||||
/// </summary>
|
||||
public class HideParamInDocsFilter : IOperationFilter
|
||||
{
|
||||
private readonly SwaggerConfig _config;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HideInDocsFilter"/> class.
|
||||
/// </summary>
|
||||
/// Initializes a new instance of the <see cref="HideParamInDocsFilter"/> class.
|
||||
/// </summary>
|
||||
public HideParamInDocsFilter(SwaggerConfig config)
|
||||
{
|
||||
_config = config;
|
||||
|
@ -40,9 +40,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
var p = operation.Parameters.FirstOrDefault(p => p.Name?.ToLower() == name.ToLower());
|
||||
operation.Parameters.Remove(p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using Microsoft.Azure.OpenApiExtensions.Helpers;
|
||||
using Microsoft.OpenApi.Any;
|
||||
|
@ -28,7 +27,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters
|
|||
/// <inheritdoc/>
|
||||
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
|
||||
{
|
||||
foreach (Type abstractType in this.baseTypes)
|
||||
foreach (Type abstractType in baseTypes)
|
||||
{
|
||||
RegisterSubClasses(swaggerDoc, context.SchemaRepository, context.SchemaGenerator, abstractType);
|
||||
}
|
||||
|
@ -75,7 +74,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters
|
|||
else
|
||||
{
|
||||
// abstract schema not in this document
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
// set up a discriminator property (it must be required)
|
||||
|
@ -88,7 +87,6 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters
|
|||
throw new Exception("Missing property in " + abstractType.Name + " matching discriminator name");
|
||||
}
|
||||
|
||||
|
||||
// generate and register schema for all of the derived classes
|
||||
foreach (var derivedType in derivedTypes)
|
||||
{
|
||||
|
@ -113,7 +111,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters
|
|||
{
|
||||
if (inheritedKvp.Value.InnerPropertyClassType != null)
|
||||
{
|
||||
AmirGenerateInheritanceParent(schemaRegistry, schemaGenerator, swaggerVirtualInheritanceAttribute, inheritedKvp);
|
||||
GenerateInheritanceParent(schemaRegistry, schemaGenerator, swaggerVirtualInheritanceAttribute, inheritedKvp);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -127,39 +125,12 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters
|
|||
}
|
||||
|
||||
private void GenerateInheritanceParent(SchemaRepository schemaRegistry, ISchemaGenerator schemaGenerator, SwaggerVirtualInheritancesAttribute swaggerVirtualInheritanceAttribute, KeyValuePair<string, VirtuallyInheritedObjectProperties> derivedType)
|
||||
{
|
||||
schemaGenerator.GenerateSchema(derivedType.Value.InheritesClassType, schemaRegistry);
|
||||
|
||||
schemaRegistry.TryGetIdFor(derivedType.Value.InheritesClassType, out string id);
|
||||
OpenApiSchema derivedSchema = schemaRegistry.Schemas[id];
|
||||
var newSchemaName = derivedType.Value.InheritesClassName;
|
||||
if (!schemaRegistry.Schemas.ContainsKey(newSchemaName))
|
||||
{
|
||||
schemaRegistry.GetOrAdd(GetTempTypeToBind(derivedType.Value.InheritesClassName), newSchemaName, () =>
|
||||
{
|
||||
string discriminatorValue = derivedType.Key.ToString();
|
||||
OpenApiSchema newSchema = new OpenApiSchema();
|
||||
newSchema.Description = derivedType.Value.InheritesClassDescription?.Length > 0 ? derivedType.Value.InheritesClassDescription : null;
|
||||
|
||||
newSchema.AllOf = new List<OpenApiSchema> { new OpenApiSchema { Reference = new OpenApiReference { ExternalResource = $"#/definitions/{swaggerVirtualInheritanceAttribute.InheritedFromName}" } } };
|
||||
newSchema.Properties.Add("properties", BuildInnerProperty(derivedType, newSchemaName));
|
||||
|
||||
//newSchema.AdditionalPropertiesAllowed = true;
|
||||
//newSchema.AdditionalProperties = BuildPropertiesProperty(derivedType, newSchemaName);
|
||||
newSchema.Extensions.Add("x-ms-discriminator-value", new OpenApiString(discriminatorValue));
|
||||
newSchema.Type = "object";
|
||||
return newSchema;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void AmirGenerateInheritanceParent(SchemaRepository schemaRegistry, ISchemaGenerator schemaGenerator, SwaggerVirtualInheritancesAttribute swaggerVirtualInheritanceAttribute, KeyValuePair<string, VirtuallyInheritedObjectProperties> derivedType)
|
||||
{
|
||||
var inheritanceProperties = derivedType.Value;
|
||||
var newSchemaName = inheritanceProperties.InheritesClassName;
|
||||
if (!schemaRegistry.Schemas.ContainsKey(newSchemaName))
|
||||
{
|
||||
schemaRegistry.GetOrAdd(GetTempTypeToBindAmir(inheritanceProperties.InnerPropertyClassType), newSchemaName, () =>
|
||||
schemaRegistry.GetOrAdd(GetTempTypeToBind(inheritanceProperties.InnerPropertyClassType), newSchemaName, () =>
|
||||
{
|
||||
string discriminatorValue = derivedType.Key.ToString();
|
||||
OpenApiSchema newSchema = new OpenApiSchema();
|
||||
|
@ -187,20 +158,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters
|
|||
return property;
|
||||
}
|
||||
|
||||
private static Type GetTempTypeToBind(string id)
|
||||
{
|
||||
AssemblyName aName = new AssemblyName("DynamicAssemblyExample");
|
||||
AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);
|
||||
ModuleBuilder mb = ab.DefineDynamicModule("mocktypes");
|
||||
|
||||
// For a single-module assembly, the module name is usually
|
||||
// the assembly name plus an extension.*/
|
||||
TypeBuilder tb = mb.DefineType(
|
||||
$"MyDynamicType{id}",
|
||||
TypeAttributes.Public);
|
||||
return tb.CreateType();
|
||||
}
|
||||
private static Type GetTempTypeToBindAmir(Type type)
|
||||
private static Type GetTempTypeToBind(Type type)
|
||||
{
|
||||
Type concreteTemplateType = typeof(DummyTemplate<>);
|
||||
Type uniqueType = concreteTemplateType.MakeGenericType(type);
|
||||
|
@ -211,5 +169,4 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters
|
|||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -35,9 +35,9 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
/// <param name="context">DocumentFilterContext.</param>
|
||||
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
|
||||
{
|
||||
if (swaggerDoc != null && this.parameters != null && this.parameters.Count > 0)
|
||||
if (swaggerDoc != null && parameters != null && parameters.Count > 0)
|
||||
{
|
||||
swaggerDoc.Components.Parameters = CreateReusableParameters(this.parameters);
|
||||
swaggerDoc.Components.Parameters = CreateReusableParameters(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Options;
|
||||
using Microsoft.Azure.OpenApiExtensions.Options;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Interfaces;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
@ -21,7 +21,6 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UpdateCommonRefsDocumentFilter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="apiConfig">API config.</param>
|
||||
/// <param name="swaggerConfig">Swagger config.</param>
|
||||
public UpdateCommonRefsDocumentFilter(SwaggerConfig swaggerConfig)
|
||||
{
|
||||
|
@ -51,7 +50,6 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
list.ForEach(prop => prop.Value.Type = "object");
|
||||
}
|
||||
|
||||
|
||||
var fixingActions = new List<Action>();
|
||||
|
||||
foreach (var schema in swaggerDoc.Components.Schemas)
|
||||
|
@ -60,14 +58,17 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
fixingActions.AddRange(commonizePropertiesFixingActions);
|
||||
|
||||
// Commonize Schemas to RP ReusableParameters
|
||||
if (_config.ResourceProviderReusableParameters.Contains(schema.Key))
|
||||
var rpResusableParam = _config.ResourceProviderReusableParameters.FirstOrDefault(param => param.Key.Equals(schema.Key, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (rpResusableParam.Key != null)
|
||||
{
|
||||
// the name of the Reusable parameter can be different than the one in the common file
|
||||
var nameOfResusableParameter = rpResusableParam.Value;
|
||||
// setting external references to common definitions
|
||||
fixingActions.Add(() =>
|
||||
{
|
||||
var refSchema = new OpenApiSchema
|
||||
{
|
||||
Reference = new OpenApiReference { ExternalResource = $"{_config.RPCommonFilePath}{ParametersPrefix}{schema.Key}" },
|
||||
Reference = new OpenApiReference { ExternalResource = $"{_config.RPCommonFilePath}{ParametersPrefix}{nameOfResusableParameter}" },
|
||||
Description = schema.Value.Description
|
||||
};
|
||||
swaggerDoc.Components.Schemas.Remove(schema.Key);
|
||||
|
@ -106,8 +107,10 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
// if one of the properties is a reference to a common defination, clean it up and leave only the reference+description
|
||||
// used to commonize enums
|
||||
var id = prop.Value.Reference?.Id ?? prop.Value.AllOf?.FirstOrDefault()?.Reference?.Id;
|
||||
|
||||
var rpResusableParam = _config.ResourceProviderReusableParameters.FirstOrDefault(param => param.Key.Equals(id, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (id != null &&
|
||||
(_config.ResourceProviderReusableParameters.Contains(id) ||
|
||||
(rpResusableParam.Key != null ||
|
||||
_config.VersionCommonReusableDefinitions.ContainsKey(id)))
|
||||
{
|
||||
//commonize property of schema
|
||||
|
@ -121,7 +124,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
{
|
||||
Extensions = new Dictionary<string, IOpenApiExtension>
|
||||
{
|
||||
{ "$ref" , new OpenApiString(referenceLink) } // adding ref as extension cause according to JSON standards $ref shouldne have any other properties
|
||||
{ "$ref", new OpenApiString(referenceLink) } // adding ref as extension cause according to JSON standards $ref shouldne have any other properties
|
||||
},
|
||||
Description = prop.Value.Description,
|
||||
ReadOnly = prop.Value.ReadOnly,
|
||||
|
@ -132,7 +135,6 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
schema.Value.Properties.Remove(prop.Key);
|
||||
schema.Value.Properties.Add(prop.Key, refSchema);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
return fixingActions;
|
||||
|
@ -152,13 +154,14 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
}
|
||||
|
||||
// commonize parameters to resource provider common
|
||||
foreach (var resuseParam in _config.ResourceProviderReusableParameters)
|
||||
foreach (var resuseParamKeyValue in _config.ResourceProviderReusableParameters)
|
||||
{
|
||||
var reuseParamName = resuseParam;
|
||||
var reuseParamName = resuseParamKeyValue.Key;
|
||||
var commonParamName = resuseParamKeyValue.Value;
|
||||
var opParam = op.Value.Parameters.FirstOrDefault(p => reuseParamName.Equals(p.Name, StringComparison.OrdinalIgnoreCase) || p.Reference?.Id == reuseParamName);
|
||||
if (opParam != null)
|
||||
{
|
||||
opParam.Reference = new OpenApiReference { ExternalResource = $"{_config.RPCommonFilePath}{ParametersPrefix}{reuseParamName}" };
|
||||
opParam.Reference = new OpenApiReference { ExternalResource = $"{_config.RPCommonFilePath}{ParametersPrefix}{commonParamName}" };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,24 +176,23 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters
|
|||
opParam.Reference = new OpenApiReference { ExternalResource = $"{_config.VersionCommonFolderPath}{reuseParamFileName}.json{ParametersPrefix}{reuseParamName}" };
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void RemoveReusedEntitiesFromDocument(OpenApiDocument swaggerDoc)
|
||||
{
|
||||
foreach (var resuseParam in _config.GlobalCommonReusableParameters)
|
||||
foreach (var reuseParam in _config.GlobalCommonReusableParameters)
|
||||
{
|
||||
swaggerDoc.Components.Parameters.Remove(resuseParam.Key);
|
||||
swaggerDoc.Components.Parameters.Remove(reuseParam.Key);
|
||||
}
|
||||
|
||||
foreach (var resuseParam in _config.ResourceProviderReusableParameters)
|
||||
foreach (var reuseParam in _config.ResourceProviderReusableParameters.Select(kvp => kvp.Key))
|
||||
{
|
||||
swaggerDoc.Components.Parameters.Remove(resuseParam);
|
||||
swaggerDoc.Components.Parameters.Remove(reuseParam);
|
||||
}
|
||||
|
||||
foreach (var resuseParam in _config.VersionCommonReusableDefinitions)
|
||||
foreach (var reuseParam in _config.VersionCommonReusableDefinitions)
|
||||
{
|
||||
swaggerDoc.Components.Schemas.Remove(resuseParam.Key);
|
||||
swaggerDoc.Components.Schemas.Remove(reuseParam.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
Required = true,
|
||||
Schema = new OpenApiSchema
|
||||
{
|
||||
Type = "string",
|
||||
Type = "string",
|
||||
MinLength = 1
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Net.Mime;
|
||||
using Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters;
|
||||
using Microsoft.Azure.OpenApiExtensions.Options;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
@ -8,7 +7,7 @@ using Swashbuckle.AspNetCore.SwaggerGen;
|
|||
namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
||||
{
|
||||
/// <summary>
|
||||
/// adds default response to each Operation
|
||||
/// adds default response to each Operation
|
||||
/// </summary>
|
||||
public class DefaultResponseOperationFilter : IOperationFilter
|
||||
{
|
||||
|
@ -51,7 +50,6 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
|
||||
operation.Responses.TryAdd("default", defaultErrorResponse);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using Microsoft.OpenApi.Any;
|
||||
|
@ -18,7 +18,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
// and need not be exposed in OpenApi spec. Some other parameters which can be always ignored can be added here.
|
||||
private static readonly HashSet<string> IgnoredParameters = new HashSet<string> { "x-ms-client-tenant-id" };
|
||||
|
||||
private readonly IDictionary<string, OpenApiParameter> parameters;
|
||||
private readonly IDictionary<string, OpenApiParameter> _parameters;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FormatParametersFilter"/> class.
|
||||
|
@ -33,7 +33,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
/// <param name="parameters">List of reusable parameters.</param>
|
||||
public FormatParametersFilter(IDictionary<string, OpenApiParameter> parameters)
|
||||
{
|
||||
this.parameters = parameters;
|
||||
this._parameters = parameters;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -43,7 +43,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
/// <param name="context">DocumentFilterContext.</param>
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||
{
|
||||
var referencesByName = this.GetParameterReferenceByName();
|
||||
var referencesByName = GetParameterReferenceByName();
|
||||
|
||||
var ignoredParamAttrs = context?.ApiDescription.CustomAttributes().OfType<IgnoredParametersAttribute>().FirstOrDefault();
|
||||
IList<OpenApiParameter> newParameters = new List<OpenApiParameter>();
|
||||
|
@ -74,7 +74,6 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
newParameters.Add(referencesByName[(bodyParamName as OpenApiString).Value]);
|
||||
operation.RequestBody = null;
|
||||
}
|
||||
|
||||
}
|
||||
operation.Parameters = newParameters;
|
||||
}
|
||||
|
@ -88,7 +87,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
{
|
||||
var parameterReferences = new Dictionary<string, OpenApiParameter>();
|
||||
|
||||
foreach (KeyValuePair<string, OpenApiParameter> keyValuePair in this.parameters)
|
||||
foreach (KeyValuePair<string, OpenApiParameter> keyValuePair in _parameters)
|
||||
{
|
||||
parameterReferences.Add(
|
||||
keyValuePair.Value.Name,
|
||||
|
|
|
@ -36,7 +36,6 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
|
||||
// A 'POST' operation with x-ms-long-running-operation extension must have a valid terminal success status code 200 or 201 or 204.
|
||||
// API that responds only 202 cannot marked as `x-ms-long-running-operation`. Make sure API responds 202 also responds 200 and/or 201 and/or 204.
|
||||
var longRunningOperationAttributes = context.ApiDescription.CustomAttributes().OfType<LongRunningOperationAttribute>();
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
//});
|
||||
// $count - not supported yet leave as comment
|
||||
//operation.Parameters.Add(new OpenApiParameter
|
||||
//{
|
||||
//{
|
||||
// Name = "$count",
|
||||
// Description = "Return the total count.",
|
||||
// Required = false,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
@ -16,16 +16,6 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
public class RemoveDuplicateApiVersionParameterFilter : IOperationFilter
|
||||
{
|
||||
const string HttpHeaderNamesApiVersion = "api-version";
|
||||
//private readonly IApiConfig config;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RemoveDuplicateApiVersionParameterFilter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="config">API config.</param>
|
||||
public RemoveDuplicateApiVersionParameterFilter(/*IApiConfig config*/)
|
||||
{
|
||||
// this.config = config;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||
|
@ -70,7 +60,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
// while populate for local testing.
|
||||
// first element only
|
||||
else if (
|
||||
//!this.config.IsSwaggerSpecGenerationInProgress &&
|
||||
//!this.config.IsSwaggerSpecGenerationInProgress &&
|
||||
parameter.Schema.Default == null)
|
||||
{
|
||||
parameter.Schema.Default = new OpenApiString(description.DefaultValue.ToString());
|
||||
|
|
|
@ -7,8 +7,8 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
/// <summary>
|
||||
/// Solve known issues with Swashbuckle 5
|
||||
/// For more details:
|
||||
/// https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1488 ,
|
||||
/// https://github.com/Azure/autorest/issues/3417
|
||||
/// https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1488 ,
|
||||
/// https://github.com/Azure/autorest/issues/3417
|
||||
/// </summary>
|
||||
public class ReverseAllOfPropertiesFilter : ISchemaFilter
|
||||
{
|
||||
|
|
|
@ -38,10 +38,10 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
// TODO throw a exception.
|
||||
var mediaType = operation.RequestBody.Content[MediaTypeNames.Application.Json];
|
||||
|
||||
// removing default contentType "Application-Json"
|
||||
// removing default contentType "Application-Json"
|
||||
// if we are adding other contentTypes via attribute in the operation.
|
||||
operation.RequestBody.Content.Remove(MediaTypeNames.Application.Json);
|
||||
|
||||
|
||||
foreach (var contentType in consumesAttr.ContentTypes)
|
||||
{
|
||||
operation.RequestBody.Content.Add(contentType, mediaType);
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
/// <param name="operation">OpenApiOperation.</param>
|
||||
/// <param name="context">DocumentFilterContext.</param>
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||
{
|
||||
{
|
||||
// Remove all mime types from response except application/json
|
||||
foreach (var response in operation.Responses.Values)
|
||||
{
|
||||
|
@ -38,7 +38,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
var producesAttrs = context.ApiDescription.CustomAttributes().OfType<ProducesContentTypeAttribute>();
|
||||
if (producesAttrs.Any())
|
||||
{
|
||||
// removing default contentType "Application-Json"
|
||||
// removing default contentType "Application-Json"
|
||||
// if we are adding other contentTypes via attribute in the operation.
|
||||
foreach (var response in operation.Responses.Values)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
@ -11,11 +11,9 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters
|
|||
/// </summary>
|
||||
public class SwaggerDefaultValuesFilter : IOperationFilter
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SwaggerDefaultValuesFilter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="config">API config.</param>
|
||||
public SwaggerDefaultValuesFilter()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.SchemaFilters
|
|||
var xMsEnumExtensionObject = new OpenApiObject
|
||||
{
|
||||
["name"] = new OpenApiString(type.Name),
|
||||
["modelAsString"] = new OpenApiBoolean(this.modelAsString),
|
||||
["modelAsString"] = new OpenApiBoolean(modelAsString),
|
||||
};
|
||||
|
||||
schema.Format = null;
|
||||
|
@ -70,7 +70,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.SchemaFilters
|
|||
var val = new OpenApiObject();
|
||||
val.Add("value", new OpenApiString(label));
|
||||
values.Add(val);
|
||||
}
|
||||
}
|
||||
xMsEnumExtensionObject.Add("values", values);
|
||||
schema.Example = schema.Enum.First();
|
||||
}
|
||||
|
|
|
@ -31,7 +31,16 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.SchemaFilters
|
|||
|
||||
foreach (var schemaProperty in schema.Properties)
|
||||
{
|
||||
var property = context.Type.GetProperty(schemaProperty.Key, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
|
||||
PropertyInfo property;
|
||||
try
|
||||
{
|
||||
property = context.Type.GetProperty(schemaProperty.Key, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
|
||||
}
|
||||
catch (System.Reflection.AmbiguousMatchException)
|
||||
{
|
||||
// we do this to support overrides on inhrited (properties with new keyword)
|
||||
property = context.Type.GetProperty(schemaProperty.Key, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
|
||||
}
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.SchemaFilters
|
|||
_config = config;
|
||||
}
|
||||
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
|
||||
{
|
||||
{
|
||||
var attr = context.Type.GetCustomAttribute<CustomSwaggerSchemaInheritanceAttribute>();
|
||||
if (attr != null && schema.Properties.Any())
|
||||
{
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.SchemaFilters
|
|||
if (attr != null && !string.IsNullOrEmpty(attr.DescriptionFormat))
|
||||
{
|
||||
var humanizedCamelCase = string.Empty;
|
||||
if (context.Type.GenericTypeArguments!= null && context.Type.GenericTypeArguments.Any() )
|
||||
if (context.Type.GenericTypeArguments != null && context.Type.GenericTypeArguments.Any())
|
||||
{
|
||||
humanizedCamelCase = Regex.Replace(context.Type.GenericTypeArguments.First().Name, "([A-Z])", " $1").Trim();
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.SchemaFilters
|
|||
{
|
||||
if (property.Value.AllOf != null && property.Value.AllOf.Count == 1)
|
||||
{
|
||||
if (this.IsReferenceToPolymorphicType(property.Value.AllOf[0]))
|
||||
if (IsReferenceToPolymorphicType(property.Value.AllOf[0]))
|
||||
{
|
||||
property.Value.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = property.Value.AllOf[0].Reference.Id };
|
||||
property.Value.AllOf = null;
|
||||
|
@ -44,7 +44,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Filters.SchemaFilters
|
|||
{
|
||||
if (schema.Reference != null)
|
||||
{
|
||||
foreach (var baseType in this.baseTypes)
|
||||
foreach (var baseType in baseTypes)
|
||||
{
|
||||
if (baseType.Name.Equals(schema.Reference.Id, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Helpers
|
||||
|
@ -6,9 +6,9 @@ namespace Microsoft.Azure.OpenApiExtensions.Helpers
|
|||
public class ArmResourceWrapperNameProvider : ICustomSchemaNameProvider
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// Get Custom Name
|
||||
/// </summary>
|
||||
/// <param name="modelType">Type Must be generic and have a single generic Arg</param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public string GetCustomName(Type type)
|
||||
{
|
||||
|
|
|
@ -6,7 +6,6 @@ namespace Microsoft.Azure.OpenApiExtensions.Helpers
|
|||
{
|
||||
public BasicAsiRequestExample()
|
||||
{
|
||||
|
||||
}
|
||||
public BasicAsiRequestExample(string apiVersion)
|
||||
{
|
||||
|
@ -15,9 +14,9 @@ namespace Microsoft.Azure.OpenApiExtensions.Helpers
|
|||
[JsonProperty("api-version")]
|
||||
[System.Text.Json.Serialization.JsonPropertyName("api-version")]
|
||||
public string ApiVersion { get; set; }
|
||||
public string subscriptionId { get; set; } = "d0cfe6b2-9ac0-4464-9919-dccaee2e48c0";
|
||||
public string resourceGroupName { get; set; } = "myRg";
|
||||
public string workspaceName { get; set; } = "myWorkspace";
|
||||
public string operationalInsightsResourceProvider { get; set; } = "Microsoft.OperationalInsights";
|
||||
public string SubscriptionId { get; set; } = "d0cfe6b2-9ac0-4464-9919-dccaee2e48c0";
|
||||
public string ResourceGroupName { get; set; } = "myRg";
|
||||
public string WorkspaceName { get; set; } = "myWorkspace";
|
||||
public string OperationalInsightsResourceProvider { get; set; } = "Microsoft.OperationalInsights";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
namespace Microsoft.Azure.OpenApiExtensions.Helpers
|
||||
{
|
||||
public interface IApiVersionableRequestExample
|
||||
{
|
||||
public string ApiVersion { get; set; }
|
||||
}
|
||||
}
|
|
@ -5,11 +5,11 @@
|
|||
object GetExample();
|
||||
}
|
||||
|
||||
public abstract class BodyExamplesProvider : IExamplesProvider
|
||||
public abstract class BodyExamplesProvider : IExamplesProvider
|
||||
{
|
||||
public object GetExample()
|
||||
{
|
||||
return new { body = this.GetBodyExample() };
|
||||
return new { body = GetBodyExample() };
|
||||
}
|
||||
|
||||
protected abstract object GetBodyExample();
|
||||
|
@ -32,6 +32,5 @@
|
|||
{
|
||||
public TInnerBodyValue Value { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Helpers
|
||||
{
|
||||
public interface IVirtuallyInheritedItemDetails<T> where T : Enum
|
||||
{
|
||||
{
|
||||
VirtuallyInheritedObjectProperties Provide(T kindName);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ using Swashbuckle.AspNetCore.SwaggerGen;
|
|||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Helpers
|
||||
{
|
||||
|
||||
public static class SchemaRepositoryExtensions
|
||||
{
|
||||
public static OpenApiSchema GetOrAdd(this SchemaRepository repo, Type type, string schemaId, Func<OpenApiSchema> factoryMethod)
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Helpers
|
||||
{
|
||||
public class SimpleKindVirtualInheritanceProvider<T> : IVirtualInheritancesProvider where T : Enum
|
||||
{
|
||||
|
||||
private IVirtuallyInheritedItemDetails<T> _virtuallyInheritedItemDetails;
|
||||
private Type _kindEnum;
|
||||
|
||||
|
@ -20,9 +18,9 @@ namespace Microsoft.Azure.OpenApiExtensions.Helpers
|
|||
public Dictionary<string, VirtuallyInheritedObjectProperties> GetVirtualInheritances(string documentVersion)
|
||||
{
|
||||
var kindToInheritedMap = new Dictionary<string, VirtuallyInheritedObjectProperties>();
|
||||
foreach (T connectorKind in Enum.GetValues(this._kindEnum))
|
||||
foreach (T connectorKind in Enum.GetValues(_kindEnum))
|
||||
{
|
||||
kindToInheritedMap[connectorKind.ToString()] = this._virtuallyInheritedItemDetails.Provide(connectorKind);
|
||||
kindToInheritedMap[connectorKind.ToString()] = _virtuallyInheritedItemDetails.Provide(connectorKind);
|
||||
}
|
||||
|
||||
return kindToInheritedMap;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Helpers
|
||||
|
@ -33,20 +32,17 @@ namespace Microsoft.Azure.OpenApiExtensions.Helpers
|
|||
|
||||
private static bool IsGenericTypeMatch(Type genericType, Type candidateType)
|
||||
{
|
||||
|
||||
if (candidateType.IsGenericType && candidateType.GetTypeInfo().GenericTypeArguments[0].FullName.Equals(genericType.FullName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (candidateType.BaseType == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsGenericTypeMatch(genericType,candidateType.BaseType);
|
||||
|
||||
|
||||
return IsGenericTypeMatch(genericType, candidateType.BaseType);
|
||||
}
|
||||
|
||||
private static bool IsAssignableToGenericType(Type givenType, Type genericType)
|
||||
|
|
|
@ -3,17 +3,20 @@
|
|||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<RootNamespace>Microsoft.Azure.OpenApiExtensions</RootNamespace>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
|
||||
<!-- NuGet package properties -->
|
||||
<AssemblyName>Microsoft.Azure.OpenApiExtensions</AssemblyName>
|
||||
<PackageId>Microsoft.Azure.OpenApiExtensions</PackageId>
|
||||
<Version>1.3.2</Version>
|
||||
<Authors>romeambawolves@microsoft.com</Authors>
|
||||
<Description>Microsoft.Azure.OpenApiExtensions</Description>
|
||||
<Title>Microsoft.Azure.OpenApiExtensions</Title>
|
||||
<Title>Microsoft.Azure.OpenApiExtensions</Title>
|
||||
<Copyright>Copyright (c) Microsoft Corporation</Copyright>
|
||||
<OutputType>Library</OutputType>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -14,9 +14,6 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
/// Initializes a new instance of the <see cref="Configuration"/> class.
|
||||
/// </summary>
|
||||
/// <param name="info">Document info section details.</param>
|
||||
/// <param name="xmlCommentsFileNames">Xml comment file name.</param>
|
||||
/// <param name="reusableParameters">Resuable parameters.</param>
|
||||
/// <param name="polymorphicTypes">List of polymorphic types.</param>
|
||||
public Configuration(OpenApiDocumentInfo info)
|
||||
{
|
||||
if (info == null)
|
||||
|
@ -24,9 +21,9 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
throw new ArgumentNullException(nameof(info), "Can not be null.");
|
||||
}
|
||||
|
||||
this._info = info;
|
||||
_info = info;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// OpenAPI document info section properties.
|
||||
/// </summary>
|
||||
|
@ -38,7 +35,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
/// <returns>Api version.</returns>
|
||||
public string GetVersion()
|
||||
{
|
||||
return this._info.Version;
|
||||
return _info.Version;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -49,14 +46,14 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
{
|
||||
return new OpenApiInfo
|
||||
{
|
||||
Title = this._info.Title,
|
||||
Version = this._info.Version,
|
||||
Description = this._info.Description,
|
||||
Title = _info.Title,
|
||||
Version = _info.Version,
|
||||
Description = _info.Description,
|
||||
Extensions =
|
||||
{
|
||||
["x-ms-code-generation-settings"] = new OpenApiObject
|
||||
{
|
||||
["name"] = new OpenApiString(this._info.ClientName),
|
||||
["name"] = new OpenApiString(_info.ClientName),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Options
|
||||
|
||||
{
|
||||
/// <summary>
|
||||
/// Corresponds to openAPI document info section.
|
||||
|
@ -37,10 +36,10 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
throw new ArgumentNullException(nameof(clientName), "Can not be null or empty.");
|
||||
}
|
||||
|
||||
this.Title = title;
|
||||
this.Description = description;
|
||||
this.Version = version;
|
||||
this.ClientName = clientName;
|
||||
Title = title;
|
||||
Description = description;
|
||||
Version = version;
|
||||
ClientName = clientName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Microsoft.Azure.OpenApiExtensions.Filters;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Microsoft.Azure.OpenApiExtensions.Attributes;
|
||||
using Microsoft.Azure.OpenApiExtensions.Filters;
|
||||
using Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters;
|
||||
using Microsoft.Azure.OpenApiExtensions.Filters.OperationFilters;
|
||||
using Microsoft.Azure.OpenApiExtensions.Filters.SchemaFilters;
|
||||
using Microsoft.Azure.OpenApiExtensions.Filters.DocumentFilters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Options
|
||||
{
|
||||
public static class OpenApiOptionsExtension
|
||||
{
|
||||
public static IServiceCollection AddAutorestCompliantSwagger(this IServiceCollection services, SwaggerConfig config)
|
||||
public static IServiceCollection AddArmCompliantSwagger(this IServiceCollection services, SwaggerConfig config)
|
||||
{
|
||||
config.EnsureValidity();
|
||||
|
||||
|
@ -58,7 +58,10 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
{
|
||||
// c.UseInlineDefinitionsForEnums(); // we prefer commonize enums
|
||||
}
|
||||
//c.UseAllOfToExtendReferenceSchemas(); // we prefer $ref over AllOf (and set up description ourselves)
|
||||
if (config.UseAllOfToExtendReferenceSchemas)
|
||||
{
|
||||
c.UseAllOfToExtendReferenceSchemas(); // we prefer $ref over AllOf (and set up description ourselves)
|
||||
}
|
||||
c.DocInclusionPredicate((docName, apiDesc) => DocumentApiInclusion(config, docName, apiDesc));
|
||||
|
||||
if (config.GenerateExternalSwagger)
|
||||
|
@ -112,7 +115,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
// Adds "readOnly": true to the property marked by Microsoft.Azure.Global.Services.Common.Service.OpenApi.ValidationAttribute.ReadOnlyPropertyAttribute
|
||||
c.SchemaFilter<AddReadOnlyPropertyFilter>();
|
||||
|
||||
////Handle bug that Swashbuckle has: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1488 , https://github.com/Azure/autorest/issues/3417
|
||||
////Handle bug that Swashbuckle has: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1488 , https://github.com/Azure/autorest/issues/3417
|
||||
//c.SchemaFilter<ReverseAllOfPropertiesFilter>();
|
||||
// Operation level filters
|
||||
// Set Description field using the XMLDoc summary if absent and clear summary. By
|
||||
|
@ -138,7 +141,6 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
// Removes parameters that shouldn't be on swagger (if process specifies--externalswagger-gen in command line)
|
||||
c.OperationFilter<HideParamInDocsFilter>(config);
|
||||
|
||||
|
||||
// This is applied if swagger is generated using open api 3.0 spec, helps to fix bug in autorest tool.
|
||||
// No impact for swagger generated using 2.0 spec.
|
||||
c.OperationFilter<ArrayInQueryParametersFilter>();
|
||||
|
@ -154,7 +156,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
{
|
||||
c.SchemaFilter<CustomSchemaInheritanceFilter>(config);
|
||||
|
||||
// This is used to add x-ms-examples field to each operation. We use our own filter in order to allow for customizing the destination path.
|
||||
// This is used to add x-ms-examples field to each operation. We use our own filter in order to allow for customizing the destination path.
|
||||
c.DocumentFilter<ExampleFilter>(config);
|
||||
|
||||
c.DocumentFilter<UpdateCommonRefsDocumentFilter>(config);
|
||||
|
@ -168,7 +170,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
return services;
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseAutorestCompliantSwagger(this IApplicationBuilder app, SwaggerConfig swaggerConfig, bool useSwaggerUI = true)
|
||||
public static IApplicationBuilder UseArmCompliantSwagger(this IApplicationBuilder app, SwaggerConfig swaggerConfig, bool useSwaggerUI = true)
|
||||
{
|
||||
app.UseSwagger(options =>
|
||||
{
|
||||
|
@ -191,6 +193,36 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
return app;
|
||||
}
|
||||
|
||||
internal static string DefaultSchemaIdSelector(Type modelType)
|
||||
{
|
||||
// check if generic paramater has custom naming
|
||||
if (modelType.IsConstructedGenericType)
|
||||
{
|
||||
var firstGenericArgType = modelType.GetGenericArguments()[0];
|
||||
var applyToParentGenericParamNaming = firstGenericArgType.GetCustomAttributes<SwaggerSchemaNameStrategyAttribute>().SingleOrDefault(at => at.NamingStrategy == NamingStrategy.ApplyToParentWrapper);
|
||||
if (applyToParentGenericParamNaming != null)
|
||||
{
|
||||
return applyToParentGenericParamNaming.CustomNameProvider.GetCustomName(modelType);
|
||||
}
|
||||
}
|
||||
|
||||
var customNamingAttribute = modelType.GetCustomAttributes<SwaggerSchemaNameStrategyAttribute>().SingleOrDefault(at => at.NamingStrategy == NamingStrategy.Custom);
|
||||
if (customNamingAttribute != null)
|
||||
{
|
||||
return customNamingAttribute.CustomNameProvider.GetCustomName(modelType);
|
||||
}
|
||||
|
||||
if (!modelType.IsConstructedGenericType)
|
||||
{
|
||||
return modelType.Name;
|
||||
}
|
||||
|
||||
var prefix = modelType.GetGenericArguments()
|
||||
.Select(genericArg => DefaultSchemaIdSelector(genericArg))
|
||||
.Aggregate((previous, current) => previous + current);
|
||||
|
||||
return prefix + modelType.Name.Split('`').First();
|
||||
}
|
||||
|
||||
private static bool DocumentApiInclusion(SwaggerConfig config, string docName, ApiDescription apiDesc)
|
||||
{
|
||||
|
@ -213,13 +245,13 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
|
||||
if ((supportedApiVersions == null || !supportedApiVersions.Any()) && !config.GenerateExternalSwagger)
|
||||
{
|
||||
// all in same version..
|
||||
// all in same version..
|
||||
return true;
|
||||
}
|
||||
// this filters apiEndpoints per api-version
|
||||
var metadata = apiDesc.ActionDescriptor.EndpointMetadata;
|
||||
var apiVersionAttributes = metadata.Where(x => x.GetType() == typeof(ApiVersionAttribute)).Cast<ApiVersionAttribute>();
|
||||
var apiVersionRangeAttributes = metadata.Where(x => x.GetType() == typeof(ApiVersionRangeAttribute)).Cast<ApiVersionRangeAttribute>();
|
||||
var apiVersionRangeAttributes = metadata.Where(x => x.GetType() == typeof(SwaggerApiVersionRangeAttribute)).Cast<SwaggerApiVersionRangeAttribute>();
|
||||
|
||||
var endpointMappedApiVersionsAttributes = metadata.Where(x => x.GetType() == typeof(MapToApiVersionAttribute)).Cast<MapToApiVersionAttribute>();
|
||||
if (!apiVersionAttributes.Any() &&
|
||||
|
@ -247,38 +279,6 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
}
|
||||
return apiVersions.Any(v => v == docName);
|
||||
}
|
||||
|
||||
internal static string DefaultSchemaIdSelector(Type modelType)
|
||||
{
|
||||
var customNaming = modelType.GetCustomAttribute<SwaggerSchemaNameStrategyAttribute>();
|
||||
|
||||
// check if generic paramater has custom naming
|
||||
if (modelType.IsConstructedGenericType)
|
||||
{
|
||||
var firstGenericArgType = modelType.GetGenericArguments()[0];
|
||||
var customGenericParamNaming = firstGenericArgType.GetCustomAttribute<SwaggerSchemaNameStrategyAttribute>();
|
||||
if (customGenericParamNaming != null && customGenericParamNaming.NamingStrategy == NamingStrategy.ApplyToParentWrapper)
|
||||
{
|
||||
return customGenericParamNaming.CustomNameProvider.GetCustomName(modelType);
|
||||
}
|
||||
}
|
||||
|
||||
if (customNaming != null && customNaming.NamingStrategy == NamingStrategy.Custom)
|
||||
{
|
||||
return customNaming.CustomNameProvider.GetCustomName(modelType);
|
||||
}
|
||||
|
||||
if (!modelType.IsConstructedGenericType)
|
||||
{
|
||||
return modelType.Name;
|
||||
}
|
||||
|
||||
var prefix = modelType.GetGenericArguments()
|
||||
.Select(genericArg => DefaultSchemaIdSelector(genericArg))
|
||||
.Aggregate((previous, current) => previous + current);
|
||||
|
||||
return prefix + modelType.Name.Split('`').First();
|
||||
}
|
||||
}
|
||||
|
||||
public class OpenApiOptions
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
using FileNameWithoutExtension = System.String;
|
||||
using ParemeterName = System.String;
|
||||
using TypeName = System.String;
|
||||
|
||||
#pragma warning disable CS1711 // XML comment has a typeparam tag, but there is no type parameter by that name
|
||||
|
||||
namespace Microsoft.Azure.OpenApiExtensions.Options
|
||||
{
|
||||
public class SwaggerConfig
|
||||
|
@ -14,44 +16,48 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
/// Gets Or Sets list of base/abstract types, the Swagger will use register all derived classes as Swagger definitions
|
||||
/// make sure to decorate your base classes with JsonConverterAttribute with a valid discriminator (https://manuc66.github.io/JsonSubTypes/)
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public List<Type> PolymorphicSchemaModels { get; set; } = new List<Type>();
|
||||
public bool ModelEnumsAsString { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// As Siblings of $ref are forbidden, we can use "AllOf" that permits siblings such as description, required, and other
|
||||
/// see https://swagger.io/docs/specification/data-models/oneof-anyof-allof-not/#allof
|
||||
/// default is "false", so $ref is prefered than AllOf
|
||||
/// </summary>
|
||||
public bool UseAllOfToExtendReferenceSchemas { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates shared Definitions for commonly used endpoint parameters (operations parameters) within the swagger document
|
||||
/// </summary>
|
||||
/// <typeparam name="string"></typeparam>
|
||||
/// <typeparam name="TypeName"></typeparam>
|
||||
/// <typeparam name="OpenApiParameter"></typeparam>
|
||||
/// <returns></returns>
|
||||
public Dictionary<TypeName, OpenApiParameter> DocumentLevelReusableParameters { get; set; } = new Dictionary<TypeName, OpenApiParameter>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets Or Sets the global parameters, from the Azure spec common library <see cref="https://github.com/Azure/azure-rest-api-specs/tree/main/specification/common-types/resource-management"/>
|
||||
/// Gets Or Sets the global parameters, from the Azure spec common library "https://github.com/Azure/azure-rest-api-specs/tree/main/specification/common-types/resource-management" />
|
||||
/// </summary>
|
||||
/// <typeparam name="string">the name of the parameter</typeparam>
|
||||
/// <typeparam name="TypeName">the name of the parameter</typeparam>
|
||||
/// <typeparam name="OpenApiParameter">the open Api parameter</typeparam>
|
||||
/// <returns></returns>
|
||||
public Dictionary<TypeName, OpenApiParameter> GlobalCommonReusableParameters { get; set; } = new Dictionary<TypeName, OpenApiParameter>();
|
||||
|
||||
/// <summary>
|
||||
/// Version Level Common Definitions
|
||||
/// Version Level Common Definitions
|
||||
/// </summary>
|
||||
/// <typeparam name="string">the Definition (schema) name</typeparam>
|
||||
/// <typeparam name="string">the file name where the Definition exists (the file should under the version folder on Common folder)</typeparam>
|
||||
/// <typeparam name="TypeName">the Definition (schema) name</typeparam>
|
||||
/// <typeparam name="FileNameWithoutExtension">the file name where the Definition exists (the file should under the version folder on Common folder)</typeparam>
|
||||
/// <returns></returns>
|
||||
public Dictionary<TypeName, FileNameWithoutExtension> VersionCommonReusableDefinitions { get; set; } = new Dictionary<TypeName, FileNameWithoutExtension>();
|
||||
|
||||
/// <summary>
|
||||
/// Resource Provider Common Definitions (refer Common folder under your resource provider <see cref="https://github.com/Azure/azure-rest-api-specs/tree/main/specification/securityinsights/resource-manager/common"/> )
|
||||
/// Resource Provider Common Definitions (refer Common folder under your resource provider https://github.com/Azure/azure-rest-api-specs/tree/main/specification/securityinsights/resource-manager/common/> )
|
||||
/// </summary>
|
||||
/// <typeparam name="string">the Definition (schema) name </typeparam>
|
||||
/// <returns></returns>
|
||||
public List<TypeName> ResourceProviderReusableParameters { get; set; } = new List<TypeName>();
|
||||
public List<KeyValuePair<ParemeterName, FileNameWithoutExtension>> ResourceProviderReusableParameters { get; set; } = new List<KeyValuePair<ParemeterName, FileNameWithoutExtension>>();
|
||||
|
||||
/// <summary>
|
||||
/// Read all XML Documentation files available under the running assembly folder
|
||||
// see https://riptutorial.com/csharp/example/5498/generating-xml-from-documentation-comments#:~:text=To%20generate%20an%20XML%20documentation%20file%20from%20documentation,-%3E%20Output%2C%20check%20the%20XML%20documentation%20file%20checkbox%3A"
|
||||
/// Read all XML Documentation files available under the running assembly folder see https://riptutorial.com/csharp/example/5498/generating-xml-from-documentation-comments#:~:text=To%20generate%20an%20XML%20documentation%20file%20from%20documentation,-%3E%20Output%2C%20check%20the%20XML%20documentation%20file%20checkbox%3A"
|
||||
/// </summary>
|
||||
public bool UseXmlCommentFiles { get; set; } = true;
|
||||
|
||||
|
@ -64,10 +70,9 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
/// <summary>
|
||||
/// This on conjunction with attributes such : SwaggerHideParameterAttribute will hide your Path Parameters from the swagger (consider using with GenerateExternalSwagger=true)
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public bool HideParametersEnabled { get; set; }
|
||||
public IEnumerable<string> SupportedApiVersions { get; set; }
|
||||
|
||||
public IEnumerable<string> SupportedApiVersions { get; set; }
|
||||
|
||||
/// <see cref="OpenApiDocumentInfo.Title"/>
|
||||
public string Title { get; set; }
|
||||
|
||||
|
@ -99,7 +104,7 @@ namespace Microsoft.Azure.OpenApiExtensions.Options
|
|||
{
|
||||
return (GlobalCommonReusableParameters ?? new Dictionary<TypeName, OpenApiParameter>())
|
||||
.Union(
|
||||
(DocumentLevelReusableParameters ?? new Dictionary<TypeName, OpenApiParameter>()))
|
||||
DocumentLevelReusableParameters ?? new Dictionary<TypeName, OpenApiParameter>())
|
||||
.ToDictionary(k => k.Key, v => v.Value);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
|
||||
"settings": {
|
||||
"documentationRules": {
|
||||
"companyName": "Microsoft Corporation",
|
||||
"copyrightText": "Copyright (c) {companyName}. All rights reserved.\r\n",
|
||||
"xmlHeader": false,
|
||||
"fileNamingConvention": "stylecop",
|
||||
"documentInterfaces": true,
|
||||
"documentExposedElements": false,
|
||||
"documentPrivateElements": false,
|
||||
"documentInternalElements": false,
|
||||
"documentPrivateFields": false
|
||||
},
|
||||
"layoutRules": {
|
||||
"newlineAtEndOfFile": "allow"
|
||||
},
|
||||
"indentation": {
|
||||
"useTabs": false,
|
||||
"indentationSize": 4,
|
||||
"tabSize": 4
|
||||
},
|
||||
"orderingRules": {
|
||||
"elementOrder": [
|
||||
"kind",
|
||||
"constant",
|
||||
"accessibility",
|
||||
"static",
|
||||
"readonly"
|
||||
],
|
||||
"systemUsingDirectivesFirst": true,
|
||||
"usingDirectivesPlacement": "outsideNamespace"
|
||||
},
|
||||
"namingRules": {
|
||||
"allowCommonHungarianPrefixes": true
|
||||
}
|
||||
}
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче