首页 > 解决方案 > 如何从继承的 FromBody 模型中获得正确的类型?

问题描述

正文的帖子有几种不同的 XML 传入。所有的 XMLS 几乎相同,所以我先添加一个基类,其他 XMLS 继承自基类。

这是模型:

[XmlInclude(typeof(TextMsg))]
[XmlRoot("xml")]        
public class BaseClass
{
    public string ToUserName { get; set; }
    public string FromUserName { get; set; }
    public string CreateTime { get; set; }
    public string MsgType { get; set; }            
}        
[XmlRoot("xml")]        
public class TextMsg : BaseClass
{
    public TextMsg()
    {
        MsgType = "text";
    }
    public string Content { get; set; }
    public string MsgId { get; set; }
}

有几个类也继承自基类模型,现在我在这里只展示一个。

这是方法:

[HttpPost]
[Produces("application/xml")]
public async Task<IActionResult> mp([FromBody]BaseClass XmlData)
{
    BaseClass ReturnXmlData = null;
    var a = XmlData.GetType();            
    return Ok(ReturnXmlData);
}  

远程服务器将向我的服务器发布一个包含 XML 的请求。现在传入的变量XmlData只获取基类的值和类型。

我需要获取真正的值和类型,然后通过传入的类型和值返回不同的 XML。

我该如何解决这个问题?谢谢你。


这是传入的 XML 之一,与上面的 TextMsg 模型匹配:

<xml> 
<ToUserName>123</ToUserName>
<FromUserName>456</FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType>text</MsgType>
<Content>this is a test</Content>
<MsgId>1234567890123456</MsgId>
</xml>

标签: c#asp.net-core.net-core

解决方案


XmlSerializerInputFormatter你可以根据它的源代码编写你自己的,例如:

[Obsolete]
public class XmlCreationConverter: XmlSerializerInputFormatter
{    
    public override async Task<InputFormatterResult> ReadRequestBodyAsync(
       InputFormatterContext context,
       Encoding encoding)
    {
        XElement xml = null;
        Type type = typeof(BaseClass);
        var request = context.HttpContext.Request;

        context.HttpContext.Request.EnableRewind();
        using (StreamReader reader = new StreamReader(request.Body))
        {
            reader.BaseStream.Seek(0, SeekOrigin.Begin);
            string text = reader.ReadToEnd();
            request.Body.Position = 0; // rewind
            xml = XElement.Parse(text);

            //your logic to return the right type
            if (xml.Element("MsgType").Value == "text")
            {
                type = typeof(TextMsg);
            }
            else if(...)
            {
                type = ...
            }
            else
            {
            }

            using (XmlReader xmlReader = CreateXmlReader(request.Body, encoding))
            {
                var serializer = GetCachedSerializer(type);
                var deserializedObject = serializer.Deserialize(xmlReader);
                return InputFormatterResult.Success(deserializedObject);
            }
        }
    }

}

启动.cs:

services.AddMvc(options=> options.InputFormatters.Add(new XmlCreationConverter()))
                .AddXmlSerializerFormatters()
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

行动:

[HttpPost]
[Produces("application/xml")]
public async Task<IActionResult> mp([FromBody]BaseClass XmlData)

更新: 对于 asp.net core 3.0,将代码更改为以下:

public class XmlCreationConverter : XmlSerializerInputFormatter
{
    private readonly MvcOptions _options;
    public XmlCreationConverter(MvcOptions options) : base(options)

    {
        _options = options;
    }
    public override async Task<InputFormatterResult> ReadRequestBodyAsync(
       InputFormatterContext context,
       Encoding encoding)
    {
        XElement xml = null;
        Type type = typeof(BaseClass);
        var request = context.HttpContext.Request;

        context.HttpContext.Request.EnableBuffering();

       //for model type is Baseclass
       if (context.ModelType == typeof(BaseClass))
        {
            using (StreamReader reader = new StreamReader(request.Body))
            {
                var text = await reader.ReadToEndAsync();
                request.Body.Position = 0;
                xml = XElement.Parse(text);
                if (xml.Element("MsgType").Value == "text")
                {
                    type = typeof(TextMsg);
                }

                using (XmlReader xmlReader = CreateXmlReader(request.Body, encoding))
                {
                    var serializer = GetCachedSerializer(type);
                    var deserializedObject = serializer.Deserialize(xmlReader);
                    return InputFormatterResult.Success(deserializedObject);
                }
            }
        }
        else if(context.ModelType == ...)
        else
        {
            using (StreamReader reader = new StreamReader(request.Body))
            {
                var text = await reader.ReadToEndAsync();
                request.Body.Position = 0;
                using (var xmlReader = CreateXmlReader(request.Body, encoding))
                {
                    var modelType = GetSerializableType(context.ModelType);

                    var serializer = GetCachedSerializer(modelType);

                    var deserializedObject = serializer.Deserialize(xmlReader);

                    // Unwrap only if the original type was wrapped.
                    if (type != context.ModelType)
                    {
                        if (deserializedObject is IUnwrappable unwrappable)
                        {
                            deserializedObject = unwrappable.Unwrap(declaredType: context.ModelType);
                        }
                    }

                    return InputFormatterResult.Success(deserializedObject);
                }
            }
        }

    }
}

启动.cs

services.AddMvc(options => options.InputFormatters.Add(new XmlCreationConverter(options)))
                .AddXmlSerializerFormatters();

推荐阅读