自定义Odata格式化程序返回完整数据库而不是资源

时间:2015-06-22 17:47:33

标签: entity-framework odata asp.net-web-api asp.net-web-api2

我使用自定义格式化程序将结果直接嵌入<script>标记中。格式化程序只是添加一个变量并序列化该实体。这是我的自定义格式化程序的简化实现:

        public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
        {
            return Task.Factory.StartNew(() =>
            {
                using (StreamWriter sw = new StreamWriter(writeStream))
                {
                    var jsonOutput = JsonConvert.SerializeObject(value, Newtonsoft.Json.Formatting.Indented, new JsonSerializerSettings
                    {
                        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                    });

                    sw.Write("var values=" + jsonOutput + ";");
                }

            });
        }

如果我使用$filter$select$expand请求资源,这样可以正常工作,但如果我只查询资源本身(例如http://localhost:53662/Categories?$format=jsone)则不行。然而,格式化程序序列化整个数据库

以下是http://localhost:53662/Categories?$format=jsone的错误结果(正如您所看到的,它还会返回产品和标签,但不包含在Odata请求中):

Wrong result with full db

这是一个正确的例子,如果我添加一个Odata查询(这里是http://localhost:53662/Categories?$format=jsone&$select=Name):

Good result with select query

这是没有自定义格式化程序(http://localhost:53662/Categories)的正确结果:

Normal request also works

Web API Controller非常简单:

        [EnableQuery]
        public IQueryable<Categories> Get(ODataQueryOptions<Categories> qOptions)
        {
            IQueryable<Categories> result = db.Categories;
            return result;
        }

        [EnableQuery]
        public SingleResult<Categories> Get([FromODataUri] int key, ODataQueryOptions<Categories> qOptions)
        {
            IQueryable<Categories> result = db.Categories.Where(x => x.Id == key);
            return SingleResult.Create(result);
        }

为什么自定义格式化程序返回完整数据库而不仅仅是请求的资源?

1 个答案:

答案 0 :(得分:0)

Well, I'm using Web API with ASP.MVC 4. You're using Web API 2, but it's kind of the same problem

In case you don't need that reference depth at all: add to your reference list, contained in codefirst model, new attribute [JsonIgnore]

Example:

public class Subgroup
{
    public int SubgroupId { get; set; }
    public string SubgroupName { get; set; }
    //relations
    public int GroupId { get; set; }
    public Group Group { get; set; }
}

public class Group
{
    public int GroupId { get; set; }
    public string GroupName { get; set; }
    //relations
    [JsonIgnore]
    public virtual List<Subgroup> Subgroups { get; set; } 
}

or you can just make it private (non-virtual).

In case you want to set up return result, try to work with DataContract attribute.

But we want to have a choice. Make it configurable (with own formatters). And documentation doesn't give proper answer. JsonFormatter.SerializerSettings.MaxDepth and JsonFormatter.MaxDepth do nothing. But no harm in trying:

var jsonOutput = JsonConvert.SerializeObject(value, Newtonsoft.Json.Formatting.Indented, new JsonSerializerSettings
{
   ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
   MaxDepth = 1
});

What else can I suggest: you can write your own formatter using JavaScriptSerializer