0

我正在尝试在 .NET Core 3.1 上创建一个 WebAPI 控制器,它支持 JSON 和 XML 作为请求/响应内容类型。

控制器在接收带有“application/json”的 JSON 时工作得很好,但是当它接收带有“application/xml”的 XML 时,方法参数是使用默认值创建的,而不是在请求正文中发布的值。

示例项目 - https://github.com/rincew1nd/ASPNetCore_XMLMethods

启动中的附加 XML 序列化程序:

services.AddControllers().AddXmlSerializerFormatters();

带有方法和测试模型的控制器:

    [ApiController]
    [Route("[controller]")]
    public class TestController : ControllerBase
    {
        [HttpPost, Route("v1")]
        [Consumes("application/json", "application/xml")]
        [Produces("application/json", "application/xml")]
        public TestRequest Test([FromBody] TestRequest data)
        {
            return data;
        }
    }

    [DataContract]
    public class TestRequest
    {
        [DataMember]
        public Guid TestGuid { get; set; }
        [DataMember]
        public string TestString { get; set; }
    }

PS 项目包含用于 API 测试目的的 Swagger。

4

3 回答 3

1

您的 xml 发布请求正文使用骆驼案例,导致模型绑定为空。

添加using Swashbuckle.AspNetCore.SwaggerGen;starup.cs尝试配置如下代码:

public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers().AddXmlSerializerFormatters();

        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "Neocase <-> 1C Integration", Version = "v1" });
            c.SchemaFilter<XmlSchemaFilter>();
        });

    }
public class XmlSchemaFilter : Swashbuckle.AspNetCore.SwaggerGen.ISchemaFilter
    {
        public void Apply(OpenApiSchema model, SchemaFilterContext context)
        {
            if (model.Properties == null) return;

            foreach (var entry in model.Properties)
            {
                var name = entry.Key;
                entry.Value.Xml = new OpenApiXml
                {
                    Name = name.Substring(0, 1).ToUpper() + name.Substring(1)
                };
            }
        }
    }
于 2020-03-31T05:05:39.383 回答
0

不要使用application/xmlFromBody的属性。

当参数具有 [FromBody] 时,Web API 使用 Content-Type 标头来选择格式化程序。在此示例中,内容类型是“application/json”,请求正文是原始 JSON 字符串(不是 JSON 对象)。

使用 [FromBody]

于 2020-03-31T04:54:10.427 回答
-1

经过更多研究后,我发现 swagger 生成错误的 xml 示例,甚至没有注意到类或属性的自定义命名。

我编写了自定义模式来命名 xml 属性,因为它们是由 XML 属性命名的。我面临的唯一问题是 SchemaFilterContext 不提供 Enum 类型属性的描述。因此,要命名枚举,我将自定义属性用于招摇名称,并在具有相同名称的属性上使用 XMLElementAttribute(是的,它很垃圾但有效)。

public class XmlSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        //Try to find XmlRootAttribute on class
        var xmlroot = context.Type.GetAttributeValue((XmlRootAttribute xra) => xra);
        if (xmlroot != null)
        {
            schema.Xml = new OpenApiXml
            {
                Name = xmlroot.ElementName
            };
        }

        //Try to find XmlElementAttribute on property
        if (context.MemberInfo != null)
        {
            var xmlelement = context.MemberInfo.GetAttributeValue((XmlElementAttribute xea) => xea);
            if (xmlelement != null)
            {
                schema.Xml = new OpenApiXml
                {
                    Name = xmlelement.ElementName
                };
            }
        }

        //Try to find XmlEnumNameAttribute on enums
        if (context.Type.IsEnum)
        {
            var enumname = context.Type.GetAttributeValue((XmlEnumNameAttribute xea) => xea);
            if (enumname != null)
            {
                schema.Xml = new OpenApiXml
                {
                    Name = enumname.ElementName
                };
            }
        }
    }
}
public static class AttributeHelper
{
    public static TValue GetAttributeValue<TAttribute, TValue>(
        this Type type,
        Func<TAttribute, TValue> valueSelector)
        where TAttribute : Attribute
    {
        var att = type.GetCustomAttributes(
            typeof(TAttribute), true
        ).FirstOrDefault() as TAttribute;
        if (att != null)
        {
            return valueSelector(att);
        }
        return default(TValue);
    }
    public static TValue GetAttributeValue<TAttribute, TValue>(
        this MemberInfo mi,
        Func<TAttribute, TValue> valueSelector)
        where TAttribute : Attribute
    {
        var att = mi.GetCustomAttributes(
            typeof(TAttribute), true
        ).FirstOrDefault() as TAttribute;
        if (att != null)
        {
            return valueSelector(att);
        }
        return default(TValue);
    }
}
于 2020-03-31T16:16:11.913 回答