可选参数在 Swashbuckle.AspNetCore 中导致空异常
Optional parameter causes null exception in Swashbuckle.AspNetCore
我有一个 asp.net core 2.0
api 控制器操作,带有一个可选(和可为空的)参数。 Swashbuckle.AspNetCore 1.0.0
当方法签名中存在此参数时,Swagger 文档的生成失败,但如果我将其从签名中删除,则会成功。似乎可选参数是错误的原因,但我不知道为什么...
我正在使用 Swashbuckle 与 aspnet-api-versioning 的集成:
https://github.com/Microsoft/aspnet-api-versioning/wiki/Swashbuckle-Integration
控制器动作:
[HttpGet("{id}")]
public IActionResult GetPerson(int id, [FromQuery] bool? includeContactInfo = null)
{
var includeInfo = (includeContactInfo.HasValue && includeContactInfo.Value == true);
var person = _repo.GetPerson(id, includeInfo);
if (person == null)
{
return NotFound();
}
if (includeInfo)
{
// using AutoMapper to map between entity and dto
var personFullDto = Mapper.Map<PersonFullDto>(person);
return Ok(personFullDto);
}
var personBasicDto = Mapper.Map<PersonBasicDto>(person);
return Ok(personBasicDto);
}
这是我的 startup.cs
:
中的 ConfigureServices 和 Configure 方法
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore().AddVersionedApiExplorer(o => o.GroupNameFormat = "'v'VVV");
services.AddMvc();
services.AddApiVersioning(o =>
{
o.ReportApiVersions = true;
o.DefaultApiVersion = new Microsoft.AspNetCore.Mvc.ApiVersion(1, 0);
});
services.AddSwaggerGen(options =>
{
var provider = services.BuildServiceProvider().GetRequiredService<IApiVersionDescriptionProvider>();
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description));
}
options.OperationFilter<SwaggerDefaultValues>();
options.IncludeXmlComments(XmlCommentsFilePath);
});
var connectString = Startup.Configuration["connectionStrings:ContactsAppDb"];
services.AddDbContext<ContactsDbContext>(o => o.UseSqlServer(connectString));
services.AddScoped<IContactsRepository, ContactsRepository>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApiVersionDescriptionProvider provider)
{
if (env.IsEnvironment("PROD"))
{
app.UseExceptionHandler();
}
else
{
app.UseDeveloperExceptionPage();
}
app.UseStatusCodePages();
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<Entities.Person, Models.PersonBasicDto>();
cfg.CreateMap<Entities.Person, Models.PersonFullDto>();
cfg.CreateMap<Entities.ContactInfo, Models.ContactInfoDto>();
});
app.UseMvc();
app.UseSwagger();
app.UseSwaggerUI(options =>
{
// build a swagger endpoint for each discovered API version
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
}
});
}
我也在用SwaggerDefaultValues.csclass,来自
https://github.com/Microsoft/aspnet-api-versioning/wiki/Swashbuckle-Integration#aspnet-core
public class SwaggerDefaultValues : IOperationFilter
{
public void Apply( Operation operation, OperationFilterContext context )
{
foreach ( var parameter in operation.Parameters.OfType<NonBodyParameter>() )
{
var description = context.ApiDescription
.ParameterDescriptions
.First( p => p.Name == parameter.Name );
if ( parameter.Description == null )
{
parameter.Description = description.ModelMetadata.Description;
}
if ( parameter.Default == null )
{
parameter.Default = description.RouteInfo.DefaultValue;
}
parameter.Required |= !description.RouteInfo.IsOptional;
}
}
}
当我导航到 Swagger URL 时,以下代码行失败(在 SwaggerDefaultValues.cs class 中):
parameter.Default = description.RouteInfo.DefaultValue;
当我检查 description
对象的 includeContactInfo
optional/query 参数时,description.RouteInfo
为空。
错误信息:
Object reference not set to an instance of an object.
堆栈跟踪:
at ContactsApp.Services.SwaggerDefaultValues.Apply(Operation operation, OperationFilterContext context) in C:\Users\me\Documents\Visual Studio 2017\Projects\ContactsApp\ContactsApp\Services\SwaggerDefaultValues.cs:line 37
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.CreateOperation(ApiDescription apiDescription, ISchemaRegistry schemaRegistry)
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.CreatePathItem(IEnumerable`1 apiDescriptions, ISchemaRegistry schemaRegistry)
at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GetSwagger(String documentName, String host, String basePath, String[] schemes)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.<Invoke>d__6.MoveNext()
使用空条件运算符:
parameter.Default = description.RouteInfo?.DefaultValue;
我有一个 asp.net core 2.0
api 控制器操作,带有一个可选(和可为空的)参数。 Swashbuckle.AspNetCore 1.0.0
当方法签名中存在此参数时,Swagger 文档的生成失败,但如果我将其从签名中删除,则会成功。似乎可选参数是错误的原因,但我不知道为什么...
我正在使用 Swashbuckle 与 aspnet-api-versioning 的集成: https://github.com/Microsoft/aspnet-api-versioning/wiki/Swashbuckle-Integration
控制器动作:
[HttpGet("{id}")]
public IActionResult GetPerson(int id, [FromQuery] bool? includeContactInfo = null)
{
var includeInfo = (includeContactInfo.HasValue && includeContactInfo.Value == true);
var person = _repo.GetPerson(id, includeInfo);
if (person == null)
{
return NotFound();
}
if (includeInfo)
{
// using AutoMapper to map between entity and dto
var personFullDto = Mapper.Map<PersonFullDto>(person);
return Ok(personFullDto);
}
var personBasicDto = Mapper.Map<PersonBasicDto>(person);
return Ok(personBasicDto);
}
这是我的 startup.cs
:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore().AddVersionedApiExplorer(o => o.GroupNameFormat = "'v'VVV");
services.AddMvc();
services.AddApiVersioning(o =>
{
o.ReportApiVersions = true;
o.DefaultApiVersion = new Microsoft.AspNetCore.Mvc.ApiVersion(1, 0);
});
services.AddSwaggerGen(options =>
{
var provider = services.BuildServiceProvider().GetRequiredService<IApiVersionDescriptionProvider>();
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description));
}
options.OperationFilter<SwaggerDefaultValues>();
options.IncludeXmlComments(XmlCommentsFilePath);
});
var connectString = Startup.Configuration["connectionStrings:ContactsAppDb"];
services.AddDbContext<ContactsDbContext>(o => o.UseSqlServer(connectString));
services.AddScoped<IContactsRepository, ContactsRepository>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApiVersionDescriptionProvider provider)
{
if (env.IsEnvironment("PROD"))
{
app.UseExceptionHandler();
}
else
{
app.UseDeveloperExceptionPage();
}
app.UseStatusCodePages();
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<Entities.Person, Models.PersonBasicDto>();
cfg.CreateMap<Entities.Person, Models.PersonFullDto>();
cfg.CreateMap<Entities.ContactInfo, Models.ContactInfoDto>();
});
app.UseMvc();
app.UseSwagger();
app.UseSwaggerUI(options =>
{
// build a swagger endpoint for each discovered API version
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
}
});
}
我也在用SwaggerDefaultValues.csclass,来自 https://github.com/Microsoft/aspnet-api-versioning/wiki/Swashbuckle-Integration#aspnet-core
public class SwaggerDefaultValues : IOperationFilter
{
public void Apply( Operation operation, OperationFilterContext context )
{
foreach ( var parameter in operation.Parameters.OfType<NonBodyParameter>() )
{
var description = context.ApiDescription
.ParameterDescriptions
.First( p => p.Name == parameter.Name );
if ( parameter.Description == null )
{
parameter.Description = description.ModelMetadata.Description;
}
if ( parameter.Default == null )
{
parameter.Default = description.RouteInfo.DefaultValue;
}
parameter.Required |= !description.RouteInfo.IsOptional;
}
}
}
当我导航到 Swagger URL 时,以下代码行失败(在 SwaggerDefaultValues.cs class 中):
parameter.Default = description.RouteInfo.DefaultValue;
当我检查 description
对象的 includeContactInfo
optional/query 参数时,description.RouteInfo
为空。
错误信息:
Object reference not set to an instance of an object.
堆栈跟踪:
at ContactsApp.Services.SwaggerDefaultValues.Apply(Operation operation, OperationFilterContext context) in C:\Users\me\Documents\Visual Studio 2017\Projects\ContactsApp\ContactsApp\Services\SwaggerDefaultValues.cs:line 37
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.CreateOperation(ApiDescription apiDescription, ISchemaRegistry schemaRegistry)
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.CreatePathItem(IEnumerable`1 apiDescriptions, ISchemaRegistry schemaRegistry)
at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GetSwagger(String documentName, String host, String basePath, String[] schemes)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.<Invoke>d__6.MoveNext()
使用空条件运算符:
parameter.Default = description.RouteInfo?.DefaultValue;