【问题标题】:Swashbuckle Swagger - Pulling information from Attributes and putting it into the Schema definitionSwashbuckle Swagger - 从属性中提取信息并将其放入模式定义中
【发布时间】:2018-11-22 11:08:02
【问题描述】:

我正在尝试从 Swagger 模型的某些部分中提取 DisplayAttribute 和 DescriptionAttribute。例如,我可能有一个 Body Parameter,它具有带属性的属性,我也希望在 swagger.json 中生成并在 SwaggerUI 中可见。

到目前为止,我认为应该可行的方法是使用带有 swashbuckle 的自定义过滤器。我使用显示描述属性的 IParameterFilter 获得了概念证明,但不确定另一个过滤器是否会更好。

问题:

对于某些类型(例如列表),查找 schemaRegistry 的键会失败。

与swagger一样需要获取生成参数的key。

可能需要递归来遍历包含复杂对象的子属性。

public class SwaggerParameterFilter : IParameterFilter
{
    private SchemaRegistrySettings _settings;
    private SchemaIdManager _schemaIdManager;

    public SwaggerParameterFilter(SchemaRegistrySettings settings = null)
    {

        this._settings = settings ?? new SchemaRegistrySettings();
        this._schemaIdManager = new SchemaIdManager(this._settings.SchemaIdSelector);
    }


    public void Apply(IParameter parameter, ParameterFilterContext context)
    {
        try
        {


            if (context.ApiParameterDescription?.ModelMetadata?.Properties == null) return;
            if (parameter is BodyParameter bodyParameter)
            {
                string idFor = _schemaIdManager.IdFor(context.ApiParameterDescription.Type);
                var schemaRegistry = (SchemaRegistry)context.SchemaRegistry;
                //not perfect, crashes with some cases
                var schema = schemaRegistry.Definitions[idFor];
                //bodyParameter.Schema,  this doesn't seem right, no properties
                foreach (var modelMetadata in context.ApiParameterDescription.ModelMetadata.Properties)
                {

                    if (modelMetadata is DefaultModelMetadata defaultModelMetadata)
                    {

                        //not sure right now how to get the right key for the schema.Properties...
                        var name = defaultModelMetadata.Name;
                        name = Char.ToLowerInvariant(name[0]) + name.Substring(1);

                        if (schema.Properties.ContainsKey(name))
                        {
                            var subSchema = schema.Properties[name];
                            var attributes = defaultModelMetadata.Attributes.Attributes.Select(x => (Attribute)x);
                            var descriptionAttribute = (DescriptionAttribute)attributes.FirstOrDefault(x => x is DescriptionAttribute);
                            if (descriptionAttribute != null)
                                subSchema.Description = descriptionAttribute.Description;
                        }
                    }
                }
            }
        }
        catch (Exception e)
        {
            //eat because above is broken
        }
    }


}

编辑添加循环。

public class SwaggerParameterFilter : IParameterFilter
{
    private SchemaRegistrySettings _settings;
    private SchemaIdManager _schemaIdManager;

    public SwaggerParameterFilter(SchemaRegistrySettings settings = null)
    {

        this._settings = settings ?? new SchemaRegistrySettings();
        this._schemaIdManager = new SchemaIdManager(this._settings.SchemaIdSelector);
    }


    public void Apply(IParameter parameter, ParameterFilterContext context)
    {
        try
        {
            if (context.ApiParameterDescription?.ModelMetadata?.Properties == null) return;
            //Only BodyParameters are complex and stored in the schema
            if (parameter is BodyParameter bodyParameter)
            {
                var idFor = _schemaIdManager.IdFor(context.ApiParameterDescription.Type);
                //not perfect, crashes with some cases
                var schema = context.SchemaRegistry.Definitions[idFor];
                UpdateSchema(schema, (SchemaRegistry) context.SchemaRegistry, context.ApiParameterDescription.ModelMetadata);
            }
        }
        catch (Exception e)
        {
            //eat because above is broken
        }
    }

    private void UpdateSchema(Schema schema, SchemaRegistry schemaRegistry, ModelMetadata modelMetadata)
    {
        if (schema.Ref != null)
        {
            var schemaReference = schema.Ref.Replace("#/definitions/", "");
            UpdateSchema(schemaRegistry.Definitions[schemaReference], schemaRegistry, modelMetadata);
            return;
        }

        if (schema.Properties == null) return;
        foreach (var properties in modelMetadata.Properties)
        {

            if (properties is DefaultModelMetadata defaultModelMetadata)
            {
                //not sure right now how to get the right key for the schema.Properties...
                var name = defaultModelMetadata.Name;
                name = Char.ToLowerInvariant(name[0]) + name.Substring(1);
                if (schema.Properties.ContainsKey(name) == false) return;
                var subSchema = schema.Properties[name];
                var attributes = defaultModelMetadata.Attributes.Attributes.Select(x => (Attribute) x).ToList();
                var descriptionAttribute =
                    (DescriptionAttribute) attributes.FirstOrDefault(x => x is DescriptionAttribute);
                if (descriptionAttribute != null)
                    subSchema.Description = descriptionAttribute.Description;
                var displayAttribute = (DisplayAttribute) attributes.FirstOrDefault(x => x is DisplayAttribute);
                if (displayAttribute != null)
                    subSchema.Title = displayAttribute.Name;
                if (modelMetadata.ModelType.IsPrimitive) return;
                UpdateSchema(subSchema, schemaRegistry, defaultModelMetadata);
            }
        }
    }
}

操作过滤器

public class SwaggerOperationFilter : IOperationFilter
{
    private SchemaRegistrySettings _settings;
    private SchemaIdManager _schemaIdManager;
    private IModelMetadataProvider _metadataProvider;

    public SwaggerOperationFilter(IModelMetadataProvider metadataProvider, SchemaRegistrySettings settings = null)
    {
        this._metadataProvider = metadataProvider;
        this._settings = settings ?? new SchemaRegistrySettings();
        this._schemaIdManager = new SchemaIdManager(this._settings.SchemaIdSelector);
    }
    public void Apply(Operation operation, OperationFilterContext context)
    {
        try
        {
            foreach (var paramDescription in context.ApiDescription.ParameterDescriptions)
            {
                if (paramDescription?.ModelMetadata?.Properties == null)
                {
                    continue;
                }

                if (paramDescription.ModelMetadata.ModelType.IsPrimitive)
                {
                    continue;
                }

                if (paramDescription.ModelMetadata.ModelType == typeof(string))
                {
                    continue;
                }
                var idFor = _schemaIdManager.IdFor(paramDescription.Type);
                var schema = context.SchemaRegistry.Definitions[idFor];
                UpdateSchema(schema, (SchemaRegistry)context.SchemaRegistry, paramDescription.ModelMetadata);
            }

        }
        catch (Exception e)
        {
            //eat because above is broken
        }
    }
    private void UpdateSchema(Schema schema, SchemaRegistry schemaRegistry, ModelMetadata modelMetadata)
    {

            if (schema.Ref != null)
            {
                var schemaReference = schema.Ref.Replace("#/definitions/", "");
                UpdateSchema(schemaRegistry.Definitions[schemaReference], schemaRegistry, modelMetadata);
                return;
            }

            if (schema.Type == "array")
            {
                if (schema.Items.Ref != null)
                {
                    var schemaReference = schema.Items.Ref.Replace("#/definitions/", "");
                    var modelTypeGenericTypeArgument = modelMetadata.ModelType.GenericTypeArguments[0];

                    modelMetadata = _metadataProvider.GetMetadataForType(modelTypeGenericTypeArgument);
                    UpdateSchema(schemaRegistry.Definitions[schemaReference], schemaRegistry, modelMetadata);

                }
                return;
            }
            if (schema.Properties == null) return;
            foreach (var properties in modelMetadata.Properties)
            {

                if (properties is DefaultModelMetadata defaultModelMetadata)
                {

                    //not sure right now how to get the right key for the schema.Properties...
                    var name = defaultModelMetadata.Name;
                    name = Char.ToLowerInvariant(name[0]) + name.Substring(1);
                    if (schema.Properties.ContainsKey(name) == false) return;
                    var subSchema = schema.Properties[name];
                    var attributes = defaultModelMetadata.Attributes.Attributes.Select(x => (Attribute)x).ToList();
                    var descriptionAttribute =
                        (DescriptionAttribute)attributes.FirstOrDefault(x => x is DescriptionAttribute);
                    if (descriptionAttribute != null)
                        subSchema.Description = descriptionAttribute.Description;
                    var displayAttribute = (DisplayAttribute)attributes.FirstOrDefault(x => x is DisplayAttribute);
                    if (displayAttribute != null)
                        subSchema.Title = displayAttribute.Name;
                    if (defaultModelMetadata.ModelType.IsPrimitive) return;
                    UpdateSchema(subSchema, schemaRegistry, defaultModelMetadata);
                }
            }
    }
}

【问题讨论】:

    标签: asp.net-core swashbuckle


    【解决方案1】:

    所以经过一些故障排除后,这似乎对我有用,但可能需要针对其他情况进行修改。

    public class SwashbuckleAttributeReaderDocumentFilter : IDocumentFilter
    {
        private readonly SchemaIdManager _schemaIdManager;
        private readonly IModelMetadataProvider _metadataProvider;
        private List<string> _updatedSchemeList;
        public SwashbuckleAttributeReaderDocumentFilter(IModelMetadataProvider metadataProvider, SchemaRegistrySettings settings = null)
        {
            _metadataProvider = metadataProvider;
            var registrySettings = settings ?? new SchemaRegistrySettings();
            _schemaIdManager = new SchemaIdManager(registrySettings.SchemaIdSelector);         
        }
        public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
        {   
            _updatedSchemeList = new List<string>();
            foreach (var apiDescription in context.ApiDescriptions)
            {
                foreach (var responseTypes in apiDescription.SupportedResponseTypes)
                {
                    ProcessModelMetadata(context, responseTypes.ModelMetadata);
                }
                foreach (var paramDescription in apiDescription.ParameterDescriptions)
                {
                    ProcessModelMetadata(context, paramDescription.ModelMetadata);
                }
            }
    
        }
    
        private void ProcessModelMetadata(DocumentFilterContext context, ModelMetadata currentModelMetadata)
        {
    
            if (currentModelMetadata?.Properties == null)
            {
                return;
            }
    
            if (currentModelMetadata.ModelType.IsValueType)
            {
                return;
            }
    
            if (currentModelMetadata.ModelType == typeof(string))
            {
                return;
            }
    
            if (currentModelMetadata.ModelType.IsGenericType)
            {
                foreach (var modelType in currentModelMetadata.ModelType.GenericTypeArguments)
                {
                    var modelMetadata = _metadataProvider.GetMetadataForType(modelType);
                    UpdateSchema(context.SchemaRegistry, modelMetadata);
                }
            }
            else if (currentModelMetadata.IsCollectionType)
            {
                var modelType = currentModelMetadata.ModelType.GetElementType();
                var modelMetadata = _metadataProvider.GetMetadataForType(modelType);
                UpdateSchema(context.SchemaRegistry, modelMetadata);
    
            }
            else
            {
    
                UpdateSchema(context.SchemaRegistry, currentModelMetadata);
    
            }
        }
        public static void SetSchema(Schema schema, ModelMetadata modelMetadata)
        {
            if (!(modelMetadata is DefaultModelMetadata metadata)) return;
            var attributes = GetAtributes(metadata);
            SetDescription(attributes, schema);
            SetTitle(attributes, schema);
        }
    
        private static List<Attribute> GetAtributes(DefaultModelMetadata modelMetadata)
        {
            return modelMetadata.Attributes.Attributes.Select(x => (Attribute)x).ToList();
        }
    
        private static void SetTitle(List<Attribute> attributes, Schema schema)
        {
            //LastOrDefault because we want the attribute from the dervived class.
            var displayAttribute = (DisplayNameAttribute)attributes.LastOrDefault(x => x is DisplayNameAttribute);
            if (displayAttribute != null)
                schema.Title = displayAttribute.DisplayName;
        }
    
        private static void SetDescription(List<Attribute> attributes, Schema schema)
        {
            //LastOrDefault because we want the attribute from the dervived class. not sure if this works.
            var descriptionAttribute = (DescriptionAttribute)attributes.LastOrDefault(x => x is DescriptionAttribute);
            if (descriptionAttribute != null)
                schema.Description = descriptionAttribute.Description;
        }
    
        private void UpdateSchema(ISchemaRegistry schemaRegistry, ModelMetadata modelMetadata, Schema schema = null)
        {
            if (modelMetadata.ModelType.IsValueType) return;
            if (modelMetadata.ModelType == typeof(string)) return;
            var idFor = _schemaIdManager.IdFor(modelMetadata.ModelType);
            if (_updatedSchemeList.Contains(idFor))
                return;
            if (schema == null || schema.Ref != null)
            {
                if (schemaRegistry.Definitions.ContainsKey(idFor) == false) return;
                schema = schemaRegistry.Definitions[idFor];
            }
    
            _updatedSchemeList.Add(idFor);
            SetSchema(schema, modelMetadata);
            if (schema.Type == "array")//Array Schema
            {
                var metaData = _metadataProvider.GetMetadataForType(modelMetadata.ModelType.GenericTypeArguments[0]);
                UpdateSchema(schemaRegistry, metaData);
            }
            else//object schema
            {
                if (schema.Properties == null)
                {
                    return;
                }
                foreach (var properties in modelMetadata.Properties)
                {
                    if (!(properties is DefaultModelMetadata defaultModelMetadata))
                    {
                        continue;
                    }
                    var name = ToLowerCamelCase(defaultModelMetadata.Name);
                    if (schema.Properties.ContainsKey(name) == false)
                    {
                        //when this doesn't match the json object naming.
                        return;
                    }
                    var subSchema = schema.Properties[name];
                    SetSchema(subSchema, defaultModelMetadata);
    
                    UpdateSchema(schemaRegistry, defaultModelMetadata, subSchema);
                }
            }
        }
    
        private static string ToLowerCamelCase(string inputString)
        {
            if (inputString == null) return null;
            if (inputString == string.Empty) return string.Empty;
            if (char.IsLower(inputString[0])) return inputString;
            return inputString.Substring(0, 1).ToLower() + inputString.Substring(1);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-12-07
      • 2021-02-05
      • 2015-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多