【问题标题】:Web API silently fails for data types without a default parameterless constructor对于没有默认无参数构造函数的数据类型,Web API 静默失败
【发布时间】:2012-08-05 10:47:02
【问题描述】:

我有一个与这个 SO 问题类似的问题:Deserializing JSON to object with no default constructor in ASP.NET MVC 3 但在 MVC4 中,引用的解决方案对我不起作用。

基本上,如果我有这样的课程;

public class MyObject
{
    public string name = "foo";
    public int age = 33;
    public MyObject(string n)
    {
        name = n;
    }
}

我尝试从 Web API 方法返回它;

    // GET api/values/5
    public **MyObject** Get(int id)
    {
        return new MyObject("Getted");
    }

管道只是把我的要求扔在地板上。它静默失败并出现 500 错误。现在我可能期望它会挣扎,但我更喜欢例外。目前尚不清楚这是在哪里生成的,但我尝试在多个点(FilterProvider、ValueProvider、ModelBinder)进行拦截,但我看不到管道的哪个部分将其丢弃。

这个自定义模型绑定器不会甚至被调用;

public class MyObjectModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        return new MyObject("bound model");
    }
}

为了完整起见,这是在 global.asax.cs 中注册的;

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        // other stuff...

        ModelBinders.Binders.Add(typeof(MyObject), new MyObjectModelBinder());
    }
}

奇怪的是,如果我添加一个默认构造函数,它实际上永远不会被调用,但如果没有它,Web API 管道似乎就无法工作。

确实工作(奇怪);

public class MyObject
{
    public string name = "foo";
    public int age = 33;
    public MyObject()
    {
        throw new Exception("I am never called! But I must exist");
    }
    public MyObject(string n)
    {
        name = n;
    }
}

我正在考虑在 connect.microsoft.com 上提出有关静默失败的问题,但大概必须有解决方法。

谁能解释我做错了什么?

【问题讨论】:

  • 我刚刚尝试了自定义 MediaTypeFormatter()。它用相关的类“MyObject”调用我的 CanWriteType(),但它从不回叫我。它仍然默默地失败,在管道的其他地方有 500 个。
  • 你的Get 方法被调用了吗?当您返回 string 而不是 MyObject 时?
  • 是的。 Get() 会如你所愿地被调用。
  • 这似乎是一个普遍问题。如果在序列化过程中抛出异常,即使在调试模式下,它也会巧妙地返回 500 而没有任何进一步的描述。
  • 请求是否包含 Accept: application/json 标头?如果没有,那么响应将被格式化为 xml(默认)并且它会抛出,因为 MyObject 需要应用 DataContractDataMember 属性。

标签: c# .net asp.net-mvc-4 asp.net-web-api model-binding


【解决方案1】:

我尝试使用以下代码重现您的问题,但效果很好。你能尝试附上一个复制品吗?

class Program
{
    private const string baseAddress = "http://localhost:8080/";

    static void Main(string[] args)
    {   
        HttpSelfHostConfiguration configuration = new HttpSelfHostConfiguration(baseAddress);
        configuration.Routes.MapHttpRoute("default", "api/{controller}");
        HttpSelfHostServer server = new HttpSelfHostServer(configuration);

        try
        {
            server.OpenAsync().Wait();

            RunClient();
        }
        finally
        {
            server.CloseAsync().Wait();
        }
    }

    static void RunClient()
    {
        HttpClient client = new HttpClient();
        client.BaseAddress = new Uri(baseAddress);
        HttpResponseMessage response = client.GetAsync("api/Test?id=1").Result;
        response.EnsureSuccessStatusCode();
        Console.WriteLine(response.Content.ReadAsStringAsync().Result);
    }
}

public class MyObject
{
    public string name = "foo";
    public int age = 33;
    public MyObject(string n)
    {
        name = n;
    }
}

public class TestController : ApiController
{
    // GET api/values/5
    public MyObject Get(int id)
    {
        return new MyObject("Getted");
    }
}

你能附上一份复制品吗?

顺便说一句,您可以使用一个跟踪包来了解更多信息是哪里出了问题。

http://www.nuget.org/packages/Microsoft.AspNet.WebApi.Tracing/0.3.0-rc

您可以通过http://blogs.msdn.com/b/roncain/archive/2012/08/16/asp-net-web-api-tracing-preview.aspx了解更多关于如何使用它的信息

谢谢!

最好, 红梅

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-08
    • 1970-01-01
    • 2023-03-20
    相关资源
    最近更新 更多