如何绑定XML属性在MVC的Web API的操作模式?绑定、属性、模式、操作

2023-09-04 04:14:52 作者:寄云间

这可能是在测试版发布框架的错误,或者我做一些可怕的错误与我的课。

This may be a bug in the beta-release of the framework, or I'm doing something terribly wrong with my classes.

我已经有了一个基本的模式,我想通过POST接收到我的服务行动。该模型包含一些属性的XML元素和一些属性为XML属性。元素被绑定到模型成功,但属性被忽略。

I've got a basic model I'm trying to receive via a POST to an action on my service. The model contains some properties as XML elements and some properties as XML attributes. The elements are bound to the model successfully, but the attributes are ignored.

该模型的基本形式是:

[XmlRoot]
public class Entry
{
    [XmlAttribute]
    public string Label { get; set; }

    [XmlElement]
    public Link Parent { get; set; }

    [XmlElement]
    public string Data { get; set; }
}

public class Link
{
    [XmlElement]
    public string Href { get; set; }
}

这成功连载以下XML响应。

This serializes successfully to the following XML response.

<Entry Label="Test">
  <Parent Href="http://service/entries/123" />
  <Data>WibblyWobblyTimeyWimey</Data>
</Entry>

在发送一个请求到具有相同的XML服务,我可以看到,只有数据元素被成功地坚持着。

On sending a request back to the service with the same XML, I can see that only the Data element is persisted successfully.

调查到 HttpActionContext 显示, RequestKeyValueModel 属性只包含键数据和家长,并只有数据的值。

Investigation into the HttpActionContext shows that the RequestKeyValueModel property only contains keys "Data" and "Parent", and that only "Data" has a value.

我测试过反序列化的条目手动和使用一个简单的测试客户端搭载可以成功反序列化响应 System.Net.Http.HttpClient 来读取请求作为一个对象(和锻炼 MediaTypeFormatter 在这个过程中)。

I've tested deserialization of the entry manually and can successfully deserialize the response using a simple test client powered by the System.Net.Http.HttpClient to read the request as an object (and exercise the MediaTypeFormatter in the process).

有一些诀窍我已经错过了,有的设置地方,比如我已经忽略了?我相信问题出在 IActionBinder 试图从反序列化XML请求到行动上的参数绑定的值,但我没有任何更多的信息,为什么。

Is there some trick I've missed, some setting somewhere like which I've overlooked? I'm convinced the problem lies in the IActionBinder attempting to bind the values from the deserialized XML request to the arguments on the action, but I don't have any more information as to why.

推荐答案

我了解到,这是与现款车型有问题结合该框架的Beta版本实现(因为后来改进)。

I learned that this is a problem with the current model binding implemented by the Beta release of the framework (and subsequently improved since).

这篇文章提出的解决办法是禁用模式有利于一个简单的系列化的模式,这听起来更接近我其实是想结合。

This article suggested the work-around is to disable model binding in favour of a simpler "serialization" model, which sounded closer to what I actually wanted.

不幸的是,作为一个副作用,这种退出的所有的路由参数绑定过的,所以我不再得到任何参数的URL和行动不会不执行遗漏值。

Unfortunately, as a side-effect, this dropped out all of the route parameter binding too, so I was no longer getting any of the parameters from the URL and the action would not execute without the missing values.

不过,我设法解决这个问题通过引入以下特性:

However, I managed to work around that problem by introducing the following attribute:

public class AddRouteParametersAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var descriptor = actionContext.ActionDescriptor
            as ReflectedHttpActionDescriptor;
        var parameters = descriptor.MethodInfo.GetParameters();

        foreach (var key in actionContext.ActionArguments.Keys.ToList())
        {
            if (actionContext.ActionArguments[key] == null)
            {
                var parameter = parameters
                    .SingleOrDefault(param => param.Name == key);

                var valueProvider = new RouteDataValueProvider(
                    actionContext,
                    CultureInfo.InvariantCulture);

                var result = valueProvider.GetValue(key);

                if (result != null && parameter != null)
                {
                    actionContext.ActionArguments[key]
                        = result.ConvertTo(parameter.ParameterType);
                }
            }
        }

        base.OnActionExecuting(actionContext);
    }
}

这是一个有点这些混沌(因为所有的最好的解决方法应该是),但它使用现有的 RouteDataValueProvider 类阅读的正确类型的路由信息​​时的参数不填充通过正常的反序列化过程。我敢肯定有这样的情况,它不与工作,但到目前为止,它填补了我需要填补的空白,对我来说,无需下探的真正的深入框架解决了问题。

It's a bit crufty (as all the best workarounds should be), but it uses the existing RouteDataValueProvider class to read the route information in as the correct type whenever a parameter is not populated by the normal deserialization process. I'm sure there are cases that it doesn't work with, but so far it has filled the gap I needed filling and resolves the issue for me without having to plumb really deep into the framework.

我们希望,如果你有类似的问题,你可以参考这个code,直到RC,在这一点上我们放心,这些问题消失。

Hopefully, if you have a similar problem, you can refer to this code until the RC, at which point we're assured these problems go away.