从Web API获取空的500 http状态代码

时间:2013-01-10 12:54:24

标签: asp.net asp.net-mvc serialization asp.net-mvc-4 asp.net-web-api

我的模型中有一个圆形对象图,但这是不可避免的。

根据this article中提供的建议,我使用DataContractAttribute并在所有成员上设置IsReference = true。我还在我要序列化的所有属性上提供了DataMemberAttribute

为确保序列化程序不会再遇到任何问题,我只选择 not 来序列化导航属性。

但是,我的catch块中仍然遇到异常。例外的细节如下:

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

2 个答案:

答案 0 :(得分:2)

<强>解决方案

此问题已在AspNetWebStack Nightly Build中解决。

我没有跟踪哪个签到会纠正行为,因为我正在跟进多个问题。

您可以通过将http://www.myget.org/F/aspnetwebstacknightly/添加到您的程序包管理器配置,然后从此附加存储库中显式更新来更新您的解决方案以使用最新的每晚程序包。

据我所知,1/18夜间在我的解决方案中是稳定的(odata查询也会更快地返回。)

解决方法

如果您不能使用最新的aspnetwebstack版本,如果您不需要XML格式的Feed,则可能会有解决方法。

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

答案 1 :(得分:0)

我不太了解WebAPI,但您使用ProxyDataContractResolver在WCF中解决了同样的问题。希望WebAPI中有类似的钩子吗?