修改
我现在只剩下一个错误:
{
"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()"
}
}
}
}