gpt4 book ai didi

asp.net-mvc - 使用 ASP.NET WebAPI 对 POST 请求进行 XML 架构验证

转载 作者:行者123 更新时间:2023-12-03 20:30:48 26 4
gpt4 key购买 nike

我正在尝试找到一种解决方案来验证在 POST 请求中发送的 XML 数据是否满足给定的自定义 XML 模式。

如果我使用随 ASP.NET Web API 提供的 XmlMediaTypeFormatter,据我所知,我没有可用的模式验证。例如:如果我有一个模型类型......

public class Order
{
public string Code { get; set; }
public int Quantity { get; set; }
}

...以及 ApiController 中的 POST 操作 ...
public HttpResponseMessage Post(Order order)
{
if (ModelState.IsValid)
{
// process order...
// send 200 OK response for example
}
else
// send 400 BadRequest response with ModelState errors in response body
}

...我可以发布以下“错误”的 XML 数据,但仍会得到 200 OK 响应:
User-Agent: Fiddler
Host: localhost:45678
Content-Type: application/xml; charset=utf-8

<Order> <Code>12345</Nonsense> </Order> // malformed XML

或者:
<Order> <CustomerName>12345</CustomerName> </Order>    // invalid property

或者:
<Customer> <Code>12345</Code> </Customer>    // invalid root

或者:
"Hello World"    // no XML at all

等等等等

我验证请求的唯一一点是模型绑定(bind):在请求示例 1、3 和 4 中,传递给 order 方法的 Postnull ,在示例 2 中, order.Code 属性是 null ,我可以通过测试 order == null 或通过使用 Code 属性标记 [Required] 属性。我可以在响应中使用 400 "BadRequest"Http 状态代码和响应正文中的验证消息将此验证结果发回。但是我不能确切地知道出了什么问题,也无法区分示例 1、3 和 4 中的错误 XML(没有发布 order,这是我能看到的唯一内容) - 例如。

要求 Order 必须使用特定的自定义 XML 模式发布,例如 xmlns="http://test.org/OrderSchema.xsd" ,我想验证发布的 XML 是否对此模式有效,如果不是,则在响应中发回模式验证错误。为了实现这一点,我从自定义 MediaTypeFormatter 开始:
public class MyXmlMediaTypeFormatter : MediaTypeFormatter
{
// constructor, CanReadType, CanWriteType, ...

public override Task<object> ReadFromStreamAsync(Type type, Stream stream,
HttpContentHeaders contentHeaders, IFormatterLogger formatterLogger)
{
var task = Task.Factory.StartNew(() =>
{
using (var streamReader = new StreamReader(stream))
{
XDocument document = XDocument.Load(streamReader);
// TODO: exceptions must the catched here,
// for example due to malformed XML
XmlSchemaSet schemaSet = new XmlSchemaSet();
schemaSet.Add(null, "OrderSchema.xsd");

var msgs = new List<string>();
document.Validate(schemaSet, (s, e) => msgs.Add(e.Message));
// msgs contains now the list of XML schema validation errors
// I want to send back in the response
if (msgs.Count == 0)
{
var order = ... // deserialize XML to order
return (object)order;
}
else
// WHAT NOW ?
}
});
return task;
}
}

只要一切正确,这就是有效的。

但我不知道如果 msgs.Count > 0 该怎么办。如何将此验证结果列表“传输”到 Post 操作,或者如何创建包含这些 XML 模式验证消息的 Http 响应?

此外,我不确定自定义 MediaTypeFormatter 是否是此类 XML 模式验证的最佳扩展点,以及我的方法是否正确。自定义 HttpMessageHandler/ DelegatingHandler 可能是一个更好的地方吗?或者是否有一些开箱即用的更简单的东西?

最佳答案

如果我这样做,我不会使用格式化程序。格式化程序的主要目标是将连线表示转换为 CLR 类型。在这里,您有一个 XML 文档,您想要根据一个完全不同的任务来验证模式。

我建议创建一个新的 MessageHandler 来进行验证。从 DelegatingHandler 派生,如果内容类型是 application/xml将内容加载到 XDocument 并进行验证。如果失败,则抛出 HttpResponseException。

只需将您的 MessageHandler 添加到 Configuration.MessageHandlers 集合中即可。

使用派生的 XmlMediaTypeFormatter 的问题在于,您现在正在执行嵌入在 ObjectContent 代码中的某个点,并且干净地退出可能会很棘手。此外,使 XmlMediaTypeFormatter 变得更复杂可能不是一个好主意。

我尝试创建 MessageHandler。我实际上并没有尝试运行此代码,所以买家要小心。此外,如果您避免阻止调用者,任务内容会变得非常棘手。也许有人会为我清理该代码,无论如何它就在这里。

  public class SchemaValidationMessageHandler : DelegatingHandler {

private XmlSchemaSet _schemaSet;
public SchemaValidationMessageHandler() {

_schemaSet = new XmlSchemaSet();
_schemaSet.Add(null, "OrderSchema.xsd");
}

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {

if (request.Content != null && request.Content.Headers.ContentType.MediaType == "application/xml")
{
var tcs = new TaskCompletionSource<HttpResponseMessage>();

var task = request.Content.LoadIntoBufferAsync() // I think this is needed so XmlMediaTypeFormatter will still have access to the content
.ContinueWith(t => {
request.Content.ReadAsStreamAsync()
.ContinueWith(t2 => {
var doc = XDocument.Load(t2.Result);
var msgs = new List<string>();
doc.Validate(_schemaSet, (s, e) => msgs.Add(e.Message));
if (msgs.Count > 0) {
var responseContent = new StringContent(String.Join(Environment.NewLine, msgs.ToArray()));
tcs.TrySetException(new HttpResponseException(
new HttpResponseMessage(HttpStatusCode.BadRequest) {
Content = responseContent
}));
} else {
tcs.TrySetResult(base.SendAsync(request, cancellationToken).Result);
}
});

});
return tcs.Task;
} else {
return base.SendAsync(request, cancellationToken);
}

}

关于asp.net-mvc - 使用 ASP.NET WebAPI 对 POST 请求进行 XML 架构验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11820594/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com