4

经过昨天的大量帮助,我在 asp.net4 beta 中遇到了一个已知错误 - 我升级到 VS2012 RC Express (4.5),现在我遇到了内部服务器错误,我不明白为什么。我正在创建一个 Web API:

模型

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcApplication6.Models
{
    public class tblCustomerBooking
    {
        [Key()]
        public int customer_id { get; set; }
        public string customer_name { get; set; }
        public string customer_email { get; set; }
        public virtual ICollection<tblRental> tblRentals { get; set; }
    }

    public class tblRental
    {
        [Key()]
        public int rental_id { get; set; }
        public int room_id { get; set; }
        public DateTime check_in { get; set; }
        public DateTime check_out { get; set; }
        public decimal room_cost { get; set; }
        public int customer_id { get; set; }
        [ForeignKey("customer_id")]
        public virtual tblCustomerBooking tblCustomerBooking { get; set; }
    }
}

然后我使用添加控制器向导,选择“模板:具有读/写动作的 API 控制器,使用实体框架”,选择 tblCustomerBooking 作为我的模型类,然后单击,即:

using System.Data.Entity;

namespace MvcApplication6.Models
{
    public class BookingsContext : DbContext
    {
        public BookingsContext() : base("name=BookingsContext")
        {
        }
        public DbSet<tblCustomerBooking> tblCustomerBookings { get; set; }
    }
}

Visual Studio 2012 Express 自动生成的我的控制器 (BookingsController.cs) 是:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using MvcApplication6.Models;

namespace MvcApplication6.Controllers
{
    public class BookingsController : ApiController
    {
        private BookingsContext db = new BookingsContext();

        // GET api/Bookings
        public IEnumerable<tblCustomerBooking> GettblCustomerBookings()
        {
            return db.tblCustomerBookings.AsEnumerable();
        }
    }
}

我在上面的“return db .....”处添加了一个断点,并检查了 VS 中的 Watch 部分——它清楚地显示了对象、客户以及相关的租金:

客户和租赁对象的快照

但是,如果我允许脚本继续,我只会得到一个 http500 错误(如下面的 Fiddler 所示): 显示 HTTP500 的 Fiddler 屏幕截图

是否还有更多代码可以添加到控制器中以让我查看它为什么出错?或者任何人都可以看到可能出了什么问题?VS 似乎可以检索它,如第一个屏幕截图所示,但似乎无法将其发送出去。

感谢您的任何帮助或指点,

标记

更新

嗨 - 我只是对 API 要求太多了吗?它不可能(开箱即用)简单地返回具有一对多关系的对象吗?它真的只能产生一个对象列表吗?

谢谢,马克

4

7 回答 7

2

[Update]

1, change the action code to include the navigation property data:

    // GET api/Bookings
    public IEnumerable<tblCustomerBooking> GettblCustomerBookings()
    {
        return db.tblCustomerBookings.Include("tblRentals").AsEnumerable();
    }

2, turn off proxy in data context

EF suggests to turn off proxy when serializing POCO.

If you want to support proxy, there are different ways for different serializers:

JSON.net serializer: It can support proxy by upgrading to latest version. Version 4.5.1 has a bug that can't support ignore NonserializedAttribute. It will block proxy to be serialized.

DataContractSerializer (JSON/XML): use ProxyDataContractResolver to resolve the types, here is a walkthrough.

3, enable preserving reference in model class

Both json.net and DataContract serializer support detecting circular reference and they give developer to control how to handle it.

Change the model class to following:

[JsonObject(IsReference = true)]
[DataContract(IsReference = true)]
public class tblCustomerBooking
{
    [Key()]
    public int customer_id { get; set; }
    [DataMember]
    public string customer_name { get; set; }
    [DataMember]
    public string customer_email { get; set; }
    [DataMember]
    public virtual ICollection<tblRental> tblRentals { get; set; }
}


public class tblRental
{
    [Key()]
    public int rental_id { get; set; }
    public int room_id { get; set; }
    public DateTime check_in { get; set; }
    public DateTime check_out { get; set; }
    public decimal room_cost { get; set; }
    public int customer_id { get; set; }
    [ForeignKey("customer_id")]
    public virtual tblCustomerBooking tblCustomerBooking { get; set; }
}

Note that, if the model is attributed with DataContract, you have to specify DataMember for all its members, otherwise none of them will be serialized.

于 2012-07-08T19:59:43.900 回答
2

为了解决返回带有 virtual 关键字的实体的 JSON 时出现的错误 500 问题,我执行了以下操作,

    public class BookingsController : ApiController
{
    private BookingsContext db = new BookingsContext();

    // GET api/Bookings
    public IEnumerable<tblCustomerBooking> GettblCustomerBookings()
    {
        db.Configuration.ProxyCreationEnabled = false;  
        return db.tblCustomerBookings.AsEnumerable();
    }
}

对于代理干扰的特定情况,如序列化,禁用代理创建(也禁用延迟加载)就足够了。这只会为特定的上下文实例禁用代理创建db

db.Configuration.ProxyCreationEnabled = false;

http://blogs.msdn.com/b/adonet/archive/2011/01/31/using-dbcontext-in-ef-feature-ctp5-part-6-loading-related-entities.aspx

http://blogs.msdn.com/b/adonet/archive/2011/01/27/using-dbcontext-in-ef-feature-ctp5-part-1-introduction-and-model.aspx

于 2012-07-08T23:03:03.067 回答
1

你在做什么:

db.tblCustomerBookings.Include("tblRentals").Select(i => 
    new { i.something //etc });

另外,您使用的是哪个 MediaTypeFormatter,Xml 还是 Json?错误 500 通常意味着 Formatter 阻塞。

切换到 JSON.NET 格式化程序(在 Web API RC 中最简单的方法是这样做GlobalConfiguration.Configuration.Formatters.RemoveAt(1)- 这将删除 XML 格式化程序)并查看它是否有帮助或至少给出更有意义的错误(或使用内容类型 JSON 请求您的方法)。

于 2012-06-05T14:45:12.447 回答
1

您可能希望将全局错误处理程序添加到您的项目中。它可以捕获和记录后台线程中发生的任何奇怪错误。这篇 S/O 文章讨论了一些可靠的方法。它们将在任何项目中为您节省大量时间: ASP.NET MVC Error Logging in Both Global.asax 和 Error.aspx

于 2012-06-05T12:52:17.020 回答
0

我也为将代理对象序列化为 poco 的问题而苦苦挣扎。您可以在上下文中构建一个切换 db.Configuration.ProxyCreationEnabled = false 的标志;

或者您应该设置一个视图模型并获取代理对象并将参数分配给视图模型。

public IEnumerable<tblCustomerBooking> GettblCustomerBookings()
        {
            return db.tblCustomerBookings.Select(cb=> new CustomerBookingsViewModel{id=cb.Id, et.....);
        }

或使用匿名类型:

.Select(cb=>new{id=cb.id....}
于 2012-08-06T22:43:04.523 回答
0

我猜您由于延迟加载实体而在序列化时遇到异常。

这个线程可以帮助你。

更新:

试试这是否有效,如果是,那么问题主要是我所说的

public IList<tblCustomerBooking> GettblCustomerBookings()
{
    var custBookings = db.tblCustomerBookings.Include("tblRentals").AsEnumerable();

    return custBookings
               .Select(c => new tblCustomerBooking
                            { 
                               customer_id = c.customer_id,
                               customer_name = c.customer_name,
                               customer_email = c.customer_email,
                               tblRentals = c.tblRentals
                                               .Select(r => new tblRentals
                                                      {
                                                          rental_id = r.rental_id,
                                                          // other props exclude the 
                                                          // tblCustomerBooking 
                                                      })
                            }
                      ).ToList();
}

我想如果您使用带有 web api 的JSON.NET库,您可以通过指定属性轻松控制不需要序列化的[JsonIgnore]属性,这样您就可以避免编写上述 LINQ 查询。

http://code.msdn.microsoft.com/Using-JSONNET-with-ASPNET-b2423706

http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size.aspx

于 2012-06-05T13:12:59.680 回答
0

Api Controller 是基于 Convention-Over-Configuration 的,因此您可以尝试通过以下任一方式解决:

于 2012-06-05T13:20:45.707 回答