ASP. NET Базовый WebAPI XML десериализация аргумента метода - PullRequest
0 голосов
/ 30 марта 2020

Я пытаюсь включить контроллер WebAPI. NET Ядро 3.1 поддерживает как JSON, так и XML как тип содержимого запроса / ответа.

Контроллер отлично работает при получении JSON с "application / json", но когда он получает XML с "application / 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 Project содержит Swagger для тестирования API.

Ответы [ 3 ]

1 голос
/ 31 марта 2020

Ваше тело запроса xml post использует случаи верблюда, что приводит к привязке модели к нулю.

Добавьте 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)
                };
            }
        }
    }
0 голосов
/ 31 марта 2020

После еще одного исследования я обнаружил, что swagger генерирует неправильные xml примеры, даже не замечая пользовательского именования классов или свойств.

Я написал собственную схему для именования атрибутов xml, так как они называются XML атрибуты. Единственная проблема, с которой я столкнулся, заключается в том, что SchemaFilterContext не предоставляет описание свойств типа Enum. Поэтому для именования Enums я использую пользовательский атрибут для имени чванства и атрибут 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);
    }
}
0 голосов
/ 31 марта 2020

Не использовать атрибут FromBody для приложения / xml.

Когда параметр имеет [FromBody], веб-API использует заголовок Content-Type для выберите форматер. В этом примере тип содержимого - «application / json», а тело запроса - необработанная строка JSON (не объект JSON).

Использование [FromBody ]

...