Вопрос по asp.net-mvc, asp.net – ASP.Net Web API правильно показывает в VS, но дает HTTP500

4

После большой помощи вчера я столкнулся с известной ошибкой в бета-версии asp.net4 - я обновился до VS2012 RC Express (4.5), и теперь я получаю внутреннюю ошибку сервера, и я не могу понять, почему. Я создаю веб-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; }
    }
}

Затем я использовал мастер Add Controller, выбрал «Шаблон: API-контроллер с актами чтения / записи, используя Entity Framework», выбрал tblCustomerBooking в качестве моего класса модели и щелкнул:

using System.Data.Entity;

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

Мой контроллер (BookingsController.cs), автоматически сгенерированный Visual Studio 2012 Express:

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 .....» выше и проверил часть Watch в VS - она ясно показывает объект с клиентом и связанные с ним аренды:

Однако если я разрешу продолжить выполнение сценария, я просто получу ошибку http500 (как показано в Fiddler ниже):

Есть ли еще код, который я могу добавить в контроллер, чтобы увидеть, почему он дает ошибку? Или кто-нибудь может увидеть, что может быть не так? VS, кажется, получает его нормально, как показано на первом скриншоте, но, похоже, не может отправить его.

Спасибо за любую помощь или указатели,

Отметк

Обновит

Привет, я просто слишком много спрашиваю об API? Разве невозможно (из коробки) просто вернуть объекты с отношениями один ко многим? Может ли он создать только один список объектов?

Спасибо, Марк

Ваш Ответ

7   ответов
1

вы захотите добавить глобальный обработчик ошибок в ваш проект. Он может перехватывать и регистрировать любые нечетные ошибки, возникающие в фоновых потоках. Эта статья о S / O говорит о некоторых твердых подходах. Они сэкономят вам много времени в любом проекте: ASP.NET MVC Ведение журнала ошибок в Global.asax и Error.aspx

Я использовал ELMAH в веб-формах, но до сих пор не смог заставить его работать с RC API (есть много противоречивых советов). Mark
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();
}

Думаю, если вы используете JSON.NET библиотека с веб-API, вы можете легко управлять свойствами, которые не нужно сериализовать, указав[JsonIgnore] атрибут и там вы можете избежать написания вышеупомянутого запроса LINQ.

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

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

Hi - @Mark - я попробовал эту ссылку: Strathweb.com / 2012/03 / ... - однако VS не будет компилироваться, так как не распознает (например) i.rental_id (это безопасность типов)? Mark
Я обновил ответ .. попробуй VJAI
Hi @Mark, спасибо за предложение - VS сообщает об ошибке: не удается неявно преобразовать тип 'System.Collections.Generic.List <AnonymousType # 1>' в 'System.Collections.Generic.IList <MvcApplication6.Models.tblCustomerBooking>'. Существует явное преобразование (вам не хватает приведения?) Mark
Hi @Mark - это работает, если я преобразую его в Dynamic - но все еще только возвращает информацию tblCustomerBookings - может ли ваш код быть адаптирован для добавления связанной информации tblRentals в JSON? Mark
Вам не нужно указывать «динамический», если вы указываете имя типа после «нового» ключевого слова. VJAI
0

те встроить в свой контекст флаг, который переключает 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....}
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).

Hi @Filip W - да, я сделал: Открытая динамическая GettblCustomerBookings () {return db.tblCustomerBookings.Include ("tblRentals"). Select (i => new {i.rental_id}); } - rental_id - это свойство в модели tblRentals, но VS не запускается, но выдает ошибку: «MvcApplication6.Models.tblCustomerBooking» не содержит определения для rental_id и не имеет метода расширения «rental_id», принимающего первый аргумент типа 'MvcApplication6.Models.tblCustomerBooking' может быть найден (отсутствует директива using или ссылка на сборку?) - еще раз спасибо. Mark
since tblRentals - это виртуальное свойство, вам нужно явно его загрузить, отсюда и «Включить» выше, вы делали это так? Filip W
Hi @Filip W - спасибо - да, я попробовал этот метод - но VS не будет компилироваться / запускаться, так как не распознает {i.rental_id} - просто поместил красную линию под ним, говоря, что я отсутствует директива или ссылка. В fiddler я попытался запросить как XML, так и JSON, используя: User-Agent: Fiddler Хост: localhost: 65387 Accept: application / json (и / xml для xml) - я также получил ошибку, сообщая, что GlobalConfiguration не содержит определения для ' Форматеры »- еще раз спасибо. Mark
если вы получите 'System.Collections.Generic.List <AnonymousType # 1>' для 'System.Collections.Generic.IList <MvcApplication6.Models.tblCustomerBooking>'. Существует явное преобразование (вам не хватает приведения?), Когда вам нужно «динамическое» для спасения - вместо IList <tblCustomerBooking> в качестве возвращаемого типа Filip W
try: public dynamic GettblCustomerBookings () {db.Configuration.LazyLoadingEnabled = false; return db.tblCustomerBookings.Include ("tblRentals"). Выберите (i => new {name = i.customer_id, rentals = i.tblRentals.ToArray ()}). ToList (); } Filip W
2

иртуальным ключевым словом, я сделал следующе

    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.asp

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

2

1, измените код действия, включив в него данные свойства навигации:

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

2, отключить прокси в контексте данных

EF предлагает отключить прокси при сериализации POCO.

Если вы хотите поддерживать прокси, существуют разные способы для разных сериализаторов:

JSON.net сериализатор: он может поддерживать прокси путем обновления до последней версии. В версии 4.5.1 есть ошибка, которая не поддерживает игнорирование NonserializedAttribute. Он заблокирует прокси для сериализации.

DataContractSerializer (JSON / XML): используйте ProxyDataContractResolver для разрешения типов, вотпрохождени.

3, включить сохранение ссылки в классе модели

Both json.net и сериализатор DataContract поддерживают обнаружение циклических ссылок и дают разработчикам возможность контролировать, как их обрабатывать.

Измените класс модели следующим образом:

[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; }
}

Обратите внимание, что если модель приписывается DataContract, вы должны указать DataMember для всех ее членов, иначе ни один из них не будет сериализован.

0

поэтому вы можете попытаться решить одним из следующих способов:

Переименуйте ваш метод в «Получить», чтобы он соответствовал глаголу GET

Украсьте свой метод с помощью атрибута HttpGet: [HttpGet]

Перейдите к отображению маршрута API в Global.asax и {action} после {controller} /, чтобы вызвать его с помощьюhttp: //mydomain.com/myapi/api/bookings/GettblCustomerBooking ()

Я тоже это попробовал (изменил на Get), но через Fiddler больше не получил никакой информации. Mark

Похожие вопросы