使用斜扣。ASP中的AspNetCore。NET Core webapp,我们有如下响应类型:
public class DateRange
{
[JsonConverter(typeof(IsoDateConverter))]
public DateTime StartDate {get; set;}
[JsonConverter(typeof(IsoDateConverter))]
public DateTime EndDate {get; set;}
}
使用Swashback发出swagger API JSON时,这将变成:
{ ...
"DateRange": {
"type": "object",
"properties": {
"startDate": {
"format": "date-time",
"type": "string"
},
"endDate": {
"format": "date-time",
"type": "string"
}
}
}
...
}
这里的问题是,DateTime是一种值类型,不能为null;但是发出的Swagger API JSON没有将这两个属性标记为必需的。这种行为对于所有其他值类型都是一样的:int、long、byte等,它们都被认为是可选的。
为了完成这幅图,我们将我们的Swagger API JSON提供给dtsgenerator,以生成JSON响应模式的typescript接口。e、 g.上述等级为:
export interface DateRange {
startDate?: string; // date-time
endDate?: string; // date-time
}
这显然是不正确的。在深入研究了一下这个问题后,我得出结论,dts生成器在使非必需属性在打字稿中为空方面做得是正确的。也许昂首阔步的规范需要明确支持nullable vs必需,但现在2是合并的。
我知道我可以向每个值类型属性添加[必需]
属性,但这跨越多个项目和数百个类,是冗余信息,必须维护。所有不可为空的值类型属性都不能为空,因此将它们表示为可选似乎是不正确的。
Web API、Entity Framework和Json.net都明白值类型属性不能为null
;因此在使用这些库时不需要[必需的]
属性。
我正在寻找一种方法,根据我的swagger JSON中的要求,自动标记所有不可为null的值类型,以匹配这种行为。
如果您使用的是C#8.0,并且启用了可为null的引用类型,那么答案就更容易了。假设所有不可为null的类型都是必需的,而所有其他显式定义为可为null的类型都不是必需的,那么下面的模式过滤器将起作用。
public class RequireNonNullablePropertiesSchemaFilter : ISchemaFilter
{
/// <summary>
/// Add to model.Required all properties where Nullable is false.
/// </summary>
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
var additionalRequiredProps = model.Properties
.Where(x => !x.Value.Nullable && !model.Required.Contains(x.Key))
.Select(x => x.Key);
foreach (var propKey in additionalRequiredProps)
{
model.Required.Add(propKey);
}
}
}
Apply方法将循环检查每个模型属性,以查看Nullable是否为false,并将它们添加到所需对象的列表中。从观察中可以看出,Swashbuckle在基于是否为可空类型设置可空属性方面做得很好。如果你不相信它,你总是可以用反射来产生同样的影响。
与其他模式过滤器一样,不要忘记在Startup类中添加这个过滤器以及处理可空对象的适当Swashuckle扩展。
services.AddSwaggerGen(c =>
{
/*...*/
c.SchemaFilter<RequireNonNullablePropertiesSchemaFilter>();
c.SupportNonNullableReferenceTypes(); // Sets Nullable flags appropriately.
c.UseAllOfToExtendReferenceSchemas(); // Allows $ref enums to be nullable
c.UseAllOfForInheritance(); // Allows $ref objects to be nullable
}
使用以下模式过滤器和Swashbuck 5.4.1,我能够达到与公认答案相同的效果:
public class RequireValueTypePropertiesSchemaFilter : ISchemaFilter
{
private readonly HashSet<OpenApiSchema> _valueTypes = new HashSet<OpenApiSchema>();
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
if (context.Type.IsValueType)
{
_valueTypes.Add(model);
}
if (model.Properties != null)
{
foreach (var prop in model.Properties)
{
if (_valueTypes.Contains(prop.Value))
{
model.Required.Add(prop.Key);
}
}
}
}
}
这依赖于这样一个事实,即ISchemaFilter必须应用于每个属性的简单模式,然后才能应用于包含这些属性的复杂模式——因此我们所要做的就是跟踪与ValueType相关的简单模式,如果我们稍后遇到将这些ValueType模式之一作为属性的模式,我们可以根据需要标记该属性名称。
我找到了一个解决方案:我能够实现一个虚张声势的ISchemaFilter。实施是:
/// <summary>
/// Makes all value-type properties "Required" in the schema docs, which is appropriate since they cannot be null.
/// </summary>
/// <remarks>
/// This saves effort + maintenance from having to add <c>[Required]</c> to all value type properties; Web API, EF, and Json.net already understand
/// that value type properties cannot be null.
///
/// More background on the problem solved by this type: https://stackoverflow.com/questions/46576234/swashbuckle-make-non-nullable-properties-required </remarks>
public sealed class RequireValueTypePropertiesSchemaFilter : ISchemaFilter
{
private readonly CamelCasePropertyNamesContractResolver _camelCaseContractResolver;
/// <summary>
/// Initializes a new <see cref="RequireValueTypePropertiesSchemaFilter"/>.
/// </summary>
/// <param name="camelCasePropertyNames">If <c>true</c>, property names are expected to be camel-cased in the JSON schema.</param>
/// <remarks>
/// I couldn't figure out a way to determine if the swagger generator is using <see cref="CamelCaseNamingStrategy"/> or not;
/// so <paramref name="camelCasePropertyNames"/> needs to be passed in since it can't be determined.
/// </remarks>
public RequireValueTypePropertiesSchemaFilter(bool camelCasePropertyNames)
{
_camelCaseContractResolver = camelCasePropertyNames ? new CamelCasePropertyNamesContractResolver() : null;
}
/// <summary>
/// Returns the JSON property name for <paramref name="property"/>.
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
private string PropertyName(PropertyInfo property)
{
return _camelCaseContractResolver?.GetResolvedPropertyName(property.Name) ?? property.Name;
}
/// <summary>
/// Adds non-nullable value type properties in a <see cref="Type"/> to the set of required properties for that type.
/// </summary>
/// <param name="model"></param>
/// <param name="context"></param>
public void Apply(Schema model, SchemaFilterContext context)
{
foreach (var property in context.SystemType.GetProperties())
{
string schemaPropertyName = PropertyName(property);
// This check ensures that properties that are not in the schema are not added as required.
// This includes properties marked with [IgnoreDataMember] or [JsonIgnore] (should not be present in schema or required).
if (model.Properties?.ContainsKey(schemaPropertyName) == true)
{
// Value type properties are required,
// except: Properties of type Nullable<T> are not required.
var propertyType = property.PropertyType;
if (propertyType.IsValueType
&& ! (propertyType.IsConstructedGenericType && (propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))))
{
// Properties marked with [Required] are already required (don't require it again).
if (! property.CustomAttributes.Any(attr =>
{
var t = attr.AttributeType;
return t == typeof(RequiredAttribute);
}))
{
// Make the value type property required
if (model.Required == null)
{
model.Required = new List<string>();
}
model.Required.Add(schemaPropertyName);
}
}
}
}
}
}
要使用,请在启动类中注册它:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc(c_swaggerDocumentName, new Info { Title = "Upfront API", Version = "1.0" });
c.SchemaFilter<RequireValueTypePropertiesSchemaFilter>(/*camelCasePropertyNames:*/ true);
});
这将导致上述日期范围类型变为:
{ ...
"DateRange": {
"required": [
"startDate",
"endDate"
],
"type": "object",
"properties": {
"startDate": {
"format": "date-time",
"type": "string"
},
"endDate": {
"format": "date-time",
"type": "string"
}
}
},
...
}
在昂首阔步的JSON模式中,并且:
export interface DateRange {
startDate: string; // date-time
endDate: string; // date-time
}
在dtsgenerator输出中。我希望这对其他人有帮助。
有一个错误,其中登录的用户将尝试更新他们的帐户用户名,但遇到一个错误。在我的一生中,我无法弄清楚为什么有时(可能有1/20的用户遇到这种情况)找不到当前的用户。只有登录后,用户才能访问此页面。错误有: 投掷;//未处理的“错误”事件 TypeError:无法设置null的属性“username” 错误似乎发生在这里:user.username=req.body.username;
对于通过传递到操作中的模型,我喜欢使其属性不可变
问题内容: 为什么会出现错误或未捕获的TypeError:无法将属性’innerHTML’设置为null?我以为我了解innerHTML并在以前使用过。 问题答案: 您必须将div放在脚本之前,以便在加载脚本时该div存在。
我在R中的光栅包中遇到了“writeRaster”功能问题。我正在导入我在ArcGIS中制作的光栅(TIF)(与要素光栅的距离)。 我的目标是将距离光栅重新采样到正确的分辨率和范围,然后用适当的光栅“遮罩”它,以将其裁剪到我需要的形状。当我用基本打印功能检查遮罩的结果时,一切看起来都很好,我可以看到新遮罩光栅中的每个像素都有一个距离值。 但是,当我使用writeRaster函数将此光栅写入文件时,
我实现了一个Hibernate拦截器(扩展了EmptyInterceptor)并实现了onFlushDirty方法,以便在保存对象时将该对象的属性设置为null。代码如下所示: 不幸的是,即使我取消了对象的值,记录仍然保存到数据库中。奇怪的是,当我修改该对象时,更改被保存到数据库中。 对象和属性都是实体。
我有一个看起来像这样的DTO: 当Swashuckle在OpenAPI 3规范中描述它时,这两个属性都不会出现在列表中,并且客户属性没有标记任何,但产品属性标记为。 在客户端,如果我没有将客户设置为服务器端的某个内容,则会出现deser错误: Newtonsoft. Json. JsonSerializationException:'必需属性'客户'期望一个非空值 来自服务器的JSON(顺便提一下