* add tests
* add standards
This commit is contained in:
Amir Sasson 2022-01-06 12:23:57 +02:00 коммит произвёл GitHub
Родитель ba8124c970
Коммит 0c37d70bcf
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
106 изменённых файлов: 1522 добавлений и 592 удалений

Просмотреть файл

@ -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

2
.gitignore поставляемый
Просмотреть файл

@ -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

2
.vscode/settings.json поставляемый
Просмотреть файл

@ -1,3 +1,3 @@
{
"cSpell.words": ["commonize"]
"cSpell.words": ["commonize", "Pageable"]
}

48
Directory.Build.props Normal file
Просмотреть файл

@ -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
Просмотреть файл

@ -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.

109
common.ruleset Normal file
Просмотреть файл

@ -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);
}

38
stylecop.json Normal file
Просмотреть файл

@ -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
}
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше