4

昨日多くの助けを借りた後、asp.net4ベータ版の既知のエラーに遭遇しました-VS2012 RC Express(4.5)にアップグレードしましたが、内部サーバーエラーが発生しましたが、理由がわかりません。私はWebAPIを作成しています:

モデル

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();
        }
    }
}

上記の「returndb.....」にブレークポイントを追加し、VSでウォッチパーツを確認しました。これにより、オブジェクト、顧客、および関連するレンタルが明確に表示されます。

顧客およびレンタルオブジェクトのスナップショット

ただし、スクリプトの続行を許可すると、http500エラーが発生します(以下のFiddlerを参照)。 HTTP500を示すフィドラーのスクリーンショット

エラーが発生している理由を確認するためにコントローラーに追加できるコードは他にありますか?または、誰かが何が間違っているのかを知ることができますか?最初のスクリーンショットに示されているように、VSはそれを正常に取得しているように見えますが、送信できないようです。

ヘルプやポインタをありがとう、

マーク

アップデート

こんにちは-私は単にAPIを要求しすぎていますか?1対多の関係を持つオブジェクトを単純に返すことは(箱から出して)不可能ですか?実際に単一のオブジェクトリストのみを生成できますか?

ありがとう、マーク

4

7 に答える 7

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、モデルクラスで参照を保持できるようにします

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を指定する必要があることに注意してください。指定しないと、どのメンバーもシリアル化されません。

于 2012-07-08T19:59:43.900 に答える
2

仮想キーワードを持つエンティティで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

プロジェクトにグローバルエラーハンドラーを追加することをお勧めします。バックグラウンドスレッドで発生している奇妙なエラーをトラップしてログに記録できます。このS/Oの記事では、いくつかの確かなアプローチについて説明しています。これらは、どのプロジェクトでも多くの時間を節約します: Global.asaxとError.aspxの両方でのASP.NETMVCエラーロギング

于 2012-06-05T12:52:17.020 に答える
1

あなたはやっていますか:

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

また、XmlとJsonのどちらのMediaTypeFormatterを使用していますか?エラー500は、多くの場合、フォーマッターが窒息していることを意味します。

JSON.NETフォーマッターに切り替え(Web API RCでは最も簡単な方法はGlobalConfiguration.Configuration.Formatters.RemoveAt(1)XMLフォーマッターを削除することです)、それが役立つか、少なくともより意味のあるエラーをもたらすかどうかを確認します(またはコンテンツタイプJSONでメソッドをリクエストします)。

于 2012-06-05T14:45:12.447 に答える
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は設定より規約に基づいているため、次のいずれかの方法で解決を試みることができます。

  • GET動詞と一致するように、メソッドの名前を「Get」に変更します。

  • HttpGet属性でメソッドを装飾します:[HttpGet]

  • http://mydomain.com/myapi/api/bookings/GettblCustomerBookings()で呼び出すには、Global.asaxのAPIのルートマッピングと{controller}/の後の{action}に移動します。

于 2012-06-05T13:20:45.707 に答える
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 に答える