5

私のモデルに円形のオブジェクトグラフがありますが、それは避けられません。Web APIから空の500 HTTPステータスコードを取得する

this articleに記載されているアドバイスに従って、DataContractAttributeを使用し、すべてのメンバーにIsReference = trueを設定しました。私はまた、シリアル化したいすべてのプロパティにDataMemberAttributeを提供しました。

シリアライザが問題に直面しないようにするには、でなく、を選択して、ナビゲーションプロパティをシリアル化します。

しかし、まだキャッチブロックで例外が発生しています。例外の詳細は以下のとおりです。

 _innerException: {"Type 
'System.Data.Entity.DynamicProxies.Author_615FB9F8BB22B55A7CA168DA5ED29EC6A0B59F62FD79D1346045351BE2F163A4' with data contract name 
    'Author_615FB9F8BB22B55A7CA168DA5ED29EC6A0B59F62FD79D1346045351BE2F163A4: 
http://schemas.datacontract 
    .org/2004/07/System.Data.Entity.DynamicProxies' is not expected. 
Consider using a 
    DataContractResolver or add any types not known statically to 
the list of known types - for 
    example, by using the KnownTypeAttribute attribute or by adding them 
to the list of known types 
    passed to DataContractSerializer."} 

私ができるだけにはしたくない:

1)を無効プロキシの作成。シリアライズのためだけにプロキシの作成を削除することができます。しかし、なぜ私はまだ例外が発生しているのか、それについて何ができるのかを知りたい。

2)循環参照を削除します。理由:これらの種類の参照は、Entity Frameworkで生成されるモデルでは非常に一般的です。モデルで800〜1000クラスの大きなプロジェクトをやっていたら、循環参照を取り除いて実装するのは難しいことです。

以下、この小さなスパイクソリューションのアーキテクチャ要素について説明しました。

データベーススキーマ

Id AuthorName 
------------------------------- 
1 Charles Dickens 
2 Charles Petzold 
3 Charles Darwin 
4 Charles Chaplin 
5 Leo Tolstoy 
6 Fydor Dostoevsky 
7 Ayn Rand 
8 Napolean Hill 
9 Claude M. Bristol 
10 Edward Dwight Easty 
11 O. Henry 
12 William Shakespeare 
13 Juwal Lowy 
14 Jeffrey Richter 
15 Chris Sells 
16 Don Box 
17 Steven Pinker 
18 Jim Rohn 
19 George Eliot 
20 Sathyaish Chakravarthy 



Id   Title            AuthorId 
----------- -------------------------------------------------- ----------- 
1   Nicholas Nickleby         1 


Id   BookId  Review 
----------- --------------------------------------------------------------- 
1   1   How do I know? I haven't read it. 

モデル

using System.Collections.Generic; 
using System.Runtime.Serialization; 

namespace BookReviewsModel 
{ 
    [DataContract(IsReference = true)] 
    public partial class Author 
    { 
     [DataMember] 
     public virtual int Id { get; set; } 

     [DataMember] 
     public virtual string AuthorName { get; set; } 

     public virtual ICollection<Book> Books { get; set; } 
    } 
} 


namespace BookReviewsModel 
{ 
    [DataContract(IsReference = true)] 
    public partial class Book 
    { 
     [DataMember] 
     public virtual int Id { get; set; } 

     [DataMember] 
     public virtual string Title { get; set; } 

     [DataMember] 
     public virtual int AuthorId { get; set; } 

     public virtual Author Author { get; set; } 

     public virtual ICollection<BookReview> BookReviews { get; set; } 
    } 
} 

namespace BookReviewsModel 
{ 
    [DataContract(IsReference = true)] 
    public partial class BookReview 
    { 
     [DataMember] 
     public virtual int Id { get; set; } 

     [DataMember] 
     public virtual int BookId { get; set; } 

     [DataMember] 
     [AllowHtml] 
     public virtual string Review { get; set; } 

     public virtual Book Book { get; set; } 
    } 
} 

コントローラコード

namespace BookReviews.Controllers 
{ 
    public class AuthorController : ApiController 
    { 
     [HttpGet] 
     public IEnumerable<Author> Index() 
     { 
      try 
      { 
       using (var context = new BookReviewEntities()) 
       { 
        var authors = context.Authors.ToList(); 

        var str = Serialize(new XmlMediaTypeFormatter(), authors); 

        System.Diagnostics.Debugger.Break(); 
        System.Diagnostics.Debug.Print(str); 

        return authors; 
       } 
      } 
      catch (Exception ex) 
      { 
       var responseMessage = new HttpResponseMessage 
       { 
        Content = new StringContent("Couldn't retreive the list of authors."), 
        ReasonPhrase = ex.Message.Replace('\n', ' ') 
       }; 

       throw new HttpResponseException(responseMessage); 
      } 
     } 

     string Serialize<T>(MediaTypeFormatter formatter, T value) 
     { 
      Stream stream = new MemoryStream(); 
      var content = new StreamContent(stream); 

      formatter.WriteToStreamAsync(typeof(T), value, stream, content, null).Wait(); 

      stream.Position = 0; 
      return content.ReadAsStringAsync().Result; 
     } 
    } 
} 
+0

すべてのクラスは、部分的です - それは、追加の問題を引き起こす可能性が?クラスの他の部分も属性でマークされているのか、それとも必須ではないのですか? –

+0

これは部分クラスなしで発生することが確認できますが、私のケースでは根本原因は仮想ナビゲーションプロパティ(シリアル化用にマークされていない)を使用しているようです。このためには、WCFサービスで使用できるProxyDataContractResolver + IObjectBehaviorソリューションに似た、きれいな回避策が必要です。 –

+0

あなたはこれを見てみましたか:http://stackoverflow.com/questions/11851207/prevent-property-from-being-serialized-in-web-apiまたはthis one http://stackoverflow.com/questions/1411577/ net-json-serialization-like-to-xmlignoreの間に-field-fieldを無視する –

答えて

2

ソリューション

この問題は、ビルドのAspNetWebStack夜間で解決されます。

私は複数の問題をフォローアップしているため、どのチェックインが動作を修正したかを追跡していません。

パッケージマネージャの設定にhttp://www.myget.org/F/aspnetwebstacknightly/を追加し、この追加のリポジトリから明示的に更新することで、最新の夜間パッケージを使用するようにソリューションをアップデートできます。私の知る限り

、毎晩1/18は私のソリューション内で安定している(ODATAクエリがはるかに速いだけでなく返す。)

回避策

あなたが使用できない場合最新のaspnetwebstackがビルドされている場合、XML形式のフィードを必要としないならば、潜在的な回避策があります。

http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization

この文書では、Web-APIコントローラが使用するフォーマッタを設定する方法を示し、それはまた、循環参照に対処する方法を示しており、どのようにデフォルトのXMLフォーマッタを交換/再構成します。あなたがのApplication_Start時にXMLフォーマッタを削除することができます回避策として

var xmlFormatter = config.Formatters.XmlFormatter; 
if (xmlFormatter != null) 
{ 
    config.Formatters.Remove(xmlFormatter); 
} 
0

私にはわからないWebAP私は非常にうまくいきますが、ProxyDataContractResolverを使ってWCFの同じ問題を解決します。うまくいけば、WebAPIにも同様のフックがありますか?

+0

これはApiControllerには当てはまりません。 WCFサービスと同じ方法です(テスト済みです)。 –

関連する問題