Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,12 @@ private static void AddApiExplorerServices( IApiVersioningBuilder builder )

var services = builder.Services;

// registers DefaultApiDescriptionProvider, which discovers controller-based endpoints
services.AddMvcCore().AddApiExplorer();

// registers EndpointMetadataApiDescriptionProvider, which discovers minimal API endpoints.
// both providers are required so that OpenApiDocumentService sees all endpoints.
services.AddEndpointsApiExplorer();
services.TryAddSingleton<IOptionsFactory<ApiExplorerOptions>, ApiExplorerOptionsFactory<ApiExplorerOptions>>();
services.TryAddTransient<IApiVersionDescriptionProviderFactory, ApiVersionDescriptionProviderFactory>();
services.TryAddSingleton( static sp => sp.GetRequiredService<IApiVersionDescriptionProviderFactory>().Create() );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.

namespace Asp.Versioning;

using System.Globalization;
using System.Reflection;
using static System.AttributeTargets;
using static System.Threading.Thread;

/// <summary>
/// Allows a test method to assume that it is running in a specific locale.
/// </summary>
[AttributeUsage( Class | Method, AllowMultiple = false, Inherited = true )]
internal sealed class AssumeCultureAttribute : BeforeAfterTestAttribute
{
private CultureInfo originalCulture;
private CultureInfo originalUICulture;

public AssumeCultureAttribute( string name ) => Name = name;

public string Name { get; }

public override void Before( MethodInfo methodUnderTest, IXunitTest test )
{
originalCulture = CurrentThread.CurrentCulture;
originalUICulture = CurrentThread.CurrentUICulture;

var culture = CultureInfo.CreateSpecificCulture( Name );

CurrentThread.CurrentCulture = culture;
CurrentThread.CurrentUICulture = culture;
}

public override void After( MethodInfo methodUnderTest, IXunitTest test )
{
CurrentThread.CurrentCulture = originalCulture;
CurrentThread.CurrentUICulture = originalUICulture;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"openapi": "3.1.1",
"info": {
"title": "Test API | v1",
"description": "The API was deprecated on 1/1/2026. The API was sunset on 2/10/2026.\r\n\r\n### Links\r\n\r\n- [Version Deprecation Policy](http://my.api.com/policies/versions/deprecated.html)\r\n- [Version Sunset Policy](http://my.api.com/policies/versions/sunset.html)",
"version": "1.0"
},
"servers": [
{
"url": "http://localhost/"
}
],
"paths": {
"/test/{id}": {
"get": {
"tags": [
"Test"
],
"summary": "",
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"description": "",
"required": true,
"schema": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": "integer",
"format": "int32"
}
},
{
"name": "api-version",
"in": "query",
"description": "The requested API version",
"required": true,
"schema": {
"type": "string",
"default": "1.0"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"integer",
"string"
],
"format": "int32"
}
}
}
},
"400": {
"description": "Bad Request"
}
}
}
}
},
"tags": [
{
"name": "Test"
}
],
"x-api-versioning": [
{
"title": "Version Deprecation Policy",
"type": "text/html",
"rel": "deprecation",
"url": "http://my.api.com/policies/versions/deprecated.html"
},
{
"title": "Version Sunset Policy",
"type": "text/html",
"rel": "sunset",
"url": "http://my.api.com/policies/versions/sunset.html"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
{
"openapi": "3.1.1",
"info": {
"title": "Test API | v1",
"description": "The API was deprecated on 1/1/2026. The API was sunset on 2/10/2026.\r\n\r\n### Links\r\n\r\n- [Version Deprecation Policy](http://my.api.com/policies/versions/deprecated.html)\r\n- [Version Sunset Policy](http://my.api.com/policies/versions/sunset.html)",
"version": "1.0"
},
"servers": [
{
"url": "http://localhost/"
}
],
"paths": {
"/minimal/{id}": {
"get": {
"tags": [
"Test"
],
"summary": "",
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"description": "",
"required": true,
"schema": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": "integer",
"format": "int32"
}
},
{
"name": "api-version",
"in": "query",
"description": "The requested API version",
"required": true,
"schema": {
"type": "string",
"default": "1.0"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"integer",
"string"
],
"format": "int32"
}
}
}
},
"400": {
"description": "Bad Request"
}
}
}
},
"/Test": {
"get": {
"tags": [
"Test"
],
"summary": "",
"description": "",
"parameters": [
{
"name": "id",
"in": "query",
"description": "",
"schema": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"integer",
"string"
],
"format": "int32"
}
},
{
"name": "api-version",
"in": "query",
"description": "The requested API version",
"required": true,
"schema": {
"type": "string",
"default": "1.0"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"integer",
"string"
],
"format": "int32"
}
},
"application/json": {
"schema": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"integer",
"string"
],
"format": "int32"
}
},
"text/json": {
"schema": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"integer",
"string"
],
"format": "int32"
}
}
}
}
}
}
}
},
"tags": [
{
"name": "Test"
}
],
"x-api-versioning": [
{
"title": "Version Deprecation Policy",
"type": "text/html",
"rel": "deprecation",
"url": "http://my.api.com/policies/versions/deprecated.html"
},
{
"title": "Version Sunset Policy",
"type": "text/html",
"rel": "sunset",
"url": "http://my.api.com/policies/versions/sunset.html"
}
]
}
Loading