c# - 如何从继承的 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>
解决方案
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();
推荐阅读
- c++ - 以安全的 C++ 方式获取 FILE*
- android - 在 ViewPager2(页面/片段)中未调用 onResume
- flutter - OpenContainer(动画包)中的 openBuilder 构建两次
- c++ - std::list::push_back 正在删除我的列表成员变量
- php - 在 WooCommerce 中隐藏未登录用户的特定产品变体
- stage - JAVA - JavaFX - 处理调用另一个阶段的节点(例如:一个 JButton)
- python - requests.exceptions.MissingSchema:无效的 URL '':未提供架构。也许你的意思是 http://?
- performance - 提高树“查询”的效率
- swift - 从一个 SwiftIUI 视图移动到另一个
- spring - SpringBoot oAuth2 位置标头