Microsoft.AspNet.OData 5.7.0(OData v.4)多级$ expand不起作用

时间:2015-08-26 13:53:35

标签: c# asp.net-web-api2 odata

修改

我现在只剩下一个错误:

{
  "error":{
    "code":"","message":"An error has occurred.","innererror":{
      "message":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; odata.metadata=minimal'.","type":"System.InvalidOperationException","stacktrace":"","internalexception":{
        "message":"Object reference not set to an instance of an object.","type":"System.NullReferenceException","stacktrace":"   at NHibernate.Linq.Visitors.ExpressionKeyVisitor.VisitConstantExpression(ConstantExpression expression)\r\n   at NHibernate.Linq.Visitors.ExpressionKeyVisitor.VisitBinaryExpression(BinaryExpression expression)\r\n   at NHibernate.Linq.Visitors.ExpressionKeyVisitor.VisitConditionalExpression(ConditionalExpression expression)\r\n   at NHibernate.Linq.Visitors.ExpressionKeyVisitor.VisitMemberExpression(MemberExpression expression)\r\n   at NHibernate.Linq.Visitors.SelectJoinDetector.VisitMemberExpression(MemberExpression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitConditionalExpression(ConditionalExpression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberAssignment(MemberAssignment memberAssigment)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberInitExpression(MemberInitExpression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberAssignment(MemberAssignment memberAssigment)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberInitExpression(MemberInitExpression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberAssignment(MemberAssignment memberAssigment)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberInitExpression(MemberInitExpression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberAssignment(MemberAssignment memberAssigment)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberInitExpression(MemberInitExpression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberAssignment(MemberAssignment memberAssigment)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberInitExpression(MemberInitExpression expression)\r\n   at Remotion.Linq.Clauses.SelectClause.TransformExpressions(Func`2 transformation)\r\n   at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)\r\n   at NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root)\r\n   at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory, Boolean filter)\r\n   at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)\r\n   at NHibernate.Engine.Query.QueryExpressionPlan..ctor(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)\r\n   at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)\r\n   at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)\r\n   at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)\r\n   at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)\r\n   at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)\r\n   at Remotion.Linq.QueryableBase`1.System.Collections.IEnumerable.GetEnumerator()\r\n   at System.Web.OData.Formatter.Serialization.ODataFeedSerializer.WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, ODataWriter writer, ODataSerializerContext writeContext)\r\n   at System.Web.OData.Formatter.ODataMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content, HttpContentHeaders contentHeaders)\r\n   at System.Web.OData.Formatter.ODataMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()"
      }
    }
  }
}

我整理了一个简单的例子来说明问题并将其发布给NH用户Google小组。

编辑:@MartinSmit

以下是我在下面的SO评论中提到的NH代码。我在这段代码中添加了一些C#注释。

public class ExpressionKeyVisitor : ExpressionTreeVisitor
{
    private readonly IDictionary<ConstantExpression, NamedParameter> _constantToParameterMap;

    private ExpressionKeyVisitor(IDictionary<ConstantExpression, NamedParameter> constantToParameterMap)
    {
        // Don L: When this constructor is called, constantToParameterMap is null.
        _constantToParameterMap = constantToParameterMap;
    }

    protected override Expression VisitConstantExpression(ConstantExpression expression)
    {
        NamedParameter param;

        // Don L: The NullReferenceException occurs here because _constantToParameterMap is null.
        if (_constantToParameterMap.TryGetValue(expression, out param) && insideSelectClause == false)
        {
            // Nulls generate different query plans.  X = variable generates a different query depending on if variable is null or not.
            if (param.Value == null)
                _string.Append("NULL");
            if (param.Value is IEnumerable && !((IEnumerable)param.Value).Cast<object>().Any())
                _string.Append("EmptyList");
            else
                _string.Append(param.Name);
        }
        else
        {
            if (expression.Value == null)
                _string.Append("NULL");
            else
                _string.Append(expression.Value);
        }

        return base.VisitConstantExpression(expression);
    }
}

原始问题

我正在使用OData Web API创建OData 4.0端点,我遇到了$expand选项的问题。我尝试扩展时遇到异常:

http://localhost/MyApp/OData/Profile(2385)/AuthorshipsAsAuthor?$expand=Author/ProfileSubject

http://localhost/MyApp/OData/Profile(2385)/AuthorshipsAsAuthor?$expand=Author,Author/ProfileSubject

我明白了:

The query specified in the URI is not valid. Found a path traversing multiple navigation properties. Please rephrase the query such that each expand path contains only type segments and navigation properties.

我可以毫无问题地使用单级扩展($expand=Author,Publication)。我也试过$expand=Author($expand=ProfileSubject)。这让我:

The 'ObjectContent``1' type failed to serialize the response body for content type 'application/json; odata.metadata=minimal'.

我见过OData v4 Web API 2.2 deep level expand not working,但这似乎是集合的问题,而我的数据模型从多方面转向一方。我已经大大简化了数据模型,因此可能存在转录错误。

public class Authorship : IMyDomainObject
{
    public virtual Publication Publication { get; set; }

    public virtual Profile Author { get; set; }
}

public class Profile : IMyDomainObject
{
    public virtual InstitutionalAccount ProfileSubject { get; set; }

    public virtual IList<Authorship> AuthorshipsAsAuthor { get; set; }
}

public abstract class Publication : IMyDomainObject
{
    public virtual IList<Authorship> Authorships { get; set; }
}

我正在使用反射来设置我的ODataConvetionModelBuilder

private static void SetUpODataModel(HttpConfiguration config)
{
    ODataModelBuilder builder = new ODataConventionModelBuilder();

    Type oDataModelBuilderType = builder.GetType();
    MethodInfo entitySetMethodInfo = oDataModelBuilderType.GetMethod("EntitySet");
    Type domainObjectInterfaceType = typeof(IMyDomainObject);

    // Ignore properties when appropriate.
    var institutionalAccountEntityType = 
        builder.EntitySet<InstitutionalAccount>("InstitutionalAccount").EntityType;
    institutionalAccountEntityType.Ignore(ia => ia.SomethingPrivate);

    // This doesn't help.
    //var authorshipEntityType = builder.EntitySet<Authorship>("Authorship").EntityType;
    //authorshipEntityType.ContainsRequired(x => x.Author);
    //var profileEntityType = builder.EntitySet<Profile>("Profile").EntityType;
    //profileEntityType.ContainsRequired(x => x.ProfileSubject);

    foreach (
        Type domainObjectType
        in
        domainObjectInterfaceType
            .Assembly
            .DefinedTypes
            .Where(t => t.GetInterfaces().Any(i => i.Equals(domainObjectInterfaceType)))
            .Where(t => t.IsClass)
    )
    {
        // Skip the type if we've already added it, e.g., it's already
        // been done by hand.
        if (builder.EntitySets.Any(es => es.ClrType.Equals(domainObjectType)))
        {
            continue;
        }

        // This is equivalent to:
        // builder.EntitySet<MyDomainObjectType>("MyDomainObjectType");
        MethodInfo entitySetGenericMethodInfo = entitySetMethodInfo.MakeGenericMethod(domainObjectType);
        Object entitySet = entitySetGenericMethodInfo.Invoke(builder, new[] { domainObjectType.Name });
    }

    config.EnableEnumPrefixFree(true);
    config.MapODataServiceRoute(
        routeName: "ODataRoute",
        routePrefix: "OData",
        model: builder.GetEdmModel());
}

我正在使用NHibernate,但我不认为这与此相关。

编辑:我发现Failed to serialize the response body for content type甚至没有在搜索字词中包含NHibernate,但这不起作用。

编辑:为了回应@ FanOuyang的评论,我仍然收到错误消息。我的代码现在看起来像     var w = new Authorship [] {/ *长篇大论没有循环引用* /};     返回w.AsQueryable();

编辑:我使用的测试代码没有按照我的想法去做。我写了一些新的代码,将结果集复制到新对象,包括循环引用,这似乎是有效的,所以问题确实与NH有关。我得到的错误取决于我扩展的内容:

{
  "error":{
    "code":"","message":"An error has occurred.","innererror":{
      "message":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; odata.metadata=minimal'.","type":"System.InvalidOperationException","stacktrace":"","internalexception":{
        "message":"Argument types do not match","type":"System.ArgumentException","stacktrace":"   at System.Linq.Expressions.Expression.Condition(Expression test, Expression ifTrue, Expression ifFalse)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitConditionalExpression(ConditionalExpression expression)\r\n   at NHibernate.Linq.NestedSelects.SelectClauseRewriter.VisitExpression(Expression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberAssignment(MemberAssignment memberAssigment)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberInitExpression(MemberInitExpression expression)\r\n   at NHibernate.Linq.NestedSelects.SelectClauseRewriter.VisitExpression(Expression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberAssignment(MemberAssignment memberAssigment)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberInitExpression(MemberInitExpression expression)\r\n   at NHibernate.Linq.NestedSelects.SelectClauseRewriter.VisitExpression(Expression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberAssignment(MemberAssignment memberAssigment)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberInitExpression(MemberInitExpression expression)\r\n   at NHibernate.Linq.NestedSelects.SelectClauseRewriter.VisitExpression(Expression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberAssignment(MemberAssignment memberAssigment)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberInitExpression(MemberInitExpression expression)\r\n   at NHibernate.Linq.NestedSelects.SelectClauseRewriter.VisitExpression(Expression expression)\r\n   at NHibernate.Linq.NestedSelects.NestedSelectRewriter.ReWrite(QueryModel queryModel, ISessionFactory sessionFactory)\r\n   at NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root)\r\n   at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory, Boolean filter)\r\n   at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)\r\n   at NHibernate.Engine.Query.QueryExpressionPlan..ctor(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)\r\n   at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)\r\n   at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)\r\n   at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)\r\n   at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)\r\n   at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)\r\n   at Remotion.Linq.QueryableBase`1.System.Collections.IEnumerable.GetEnumerator()\r\n   at System.Web.OData.Formatter.Serialization.ODataFeedSerializer.WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, ODataWriter writer, ODataSerializerContext writeContext)\r\n   at System.Web.OData.Formatter.ODataMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content, HttpContentHeaders contentHeaders)\r\n   at System.Web.OData.Formatter.ODataMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()"
      }
    }
  }
}   

{
  "error":{
    "code":"","message":"An error has occurred.","innererror":{
      "message":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; odata.metadata=minimal'.","type":"System.InvalidOperationException","stacktrace":"","internalexception":{
        "message":"Object reference not set to an instance of an object.","type":"System.NullReferenceException","stacktrace":"   at NHibernate.Linq.Visitors.ExpressionKeyVisitor.VisitConstantExpression(ConstantExpression expression)\r\n   at NHibernate.Linq.Visitors.ExpressionKeyVisitor.VisitBinaryExpression(BinaryExpression expression)\r\n   at NHibernate.Linq.Visitors.ExpressionKeyVisitor.VisitConditionalExpression(ConditionalExpression expression)\r\n   at NHibernate.Linq.Visitors.ExpressionKeyVisitor.VisitMemberExpression(MemberExpression expression)\r\n   at NHibernate.Linq.Visitors.SelectJoinDetector.VisitMemberExpression(MemberExpression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitConditionalExpression(ConditionalExpression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberAssignment(MemberAssignment memberAssigment)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberInitExpression(MemberInitExpression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberAssignment(MemberAssignment memberAssigment)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberInitExpression(MemberInitExpression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberAssignment(MemberAssignment memberAssigment)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberInitExpression(MemberInitExpression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberAssignment(MemberAssignment memberAssigment)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberInitExpression(MemberInitExpression expression)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberAssignment(MemberAssignment memberAssigment)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod)\r\n   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMemberInitExpression(MemberInitExpression expression)\r\n   at Remotion.Linq.Clauses.SelectClause.TransformExpressions(Func`2 transformation)\r\n   at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)\r\n   at NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root)\r\n   at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory, Boolean filter)\r\n   at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)\r\n   at NHibernate.Engine.Query.QueryExpressionPlan..ctor(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)\r\n   at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)\r\n   at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)\r\n   at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)\r\n   at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)\r\n   at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)\r\n   at Remotion.Linq.QueryableBase`1.System.Collections.IEnumerable.GetEnumerator()\r\n   at System.Web.OData.Formatter.Serialization.ODataFeedSerializer.WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, ODataWriter writer, ODataSerializerContext writeContext)\r\n   at System.Web.OData.Formatter.ODataMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content, HttpContentHeaders contentHeaders)\r\n   at System.Web.OData.Formatter.ODataMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()"
      }
    }
  }
}

0 个答案:

没有答案