The issue started here, where I am unable to call $select
or $expand
on results
.
Given:
var results = options.ApplyTo(_uow.Repository<ContentType>()
.Query()
.Get()
.Include(u => u.User)
.Where(u => u.UserId == userId)
.OrderBy(o => o.Description)).Cast<ContentType>()
.Select(x => new ContentTypeDTO()
{
//projection goes here
ContentTypeId = x.ContentTypeId,
Description = x.Description,
UserDTO = new UserDTO
{
UserId = x.UserId,
UserName = x.User.UserName
}
});
Exception:
Unable to cast the type 'System.Web.Http.OData.Query.Expressions.SelectExpandBinder+SelectSome`1[[Project.DAL.Data.Models.ContentType, Project.DAL.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' to type 'Project.DAL.Data.Models.ContentType'. LINQ to Entities only supports casting EDM primitive or enumeration types."
Based on this solution, I understand that when $select
or $expand
are applied to the result, it is no longer a ContentType
, as is expected by the Cast<ContentType>()
. That solution uses HierarchyNodeExpressionVisitor
, which I am unable to locate.
I want to use 'options.ApplyTo()' as I want the filtering done on the db server, to ensure I don't get back an inflated data set with hundreds of thousands of rows.
Is there a suggested way of getting around this?
-- UPDATE --
In using @Schandlich 's suggested solution below, the operation still fails with the Ok
override:
Locals:
+ this {Project.AdminWebsite.Api.Controllers.ContentTypeController} Project.AdminWebsite.Api.Controllers.ODataBaseController {Project.AdminWebsite.Api.Controllers.ContentTypeController}
+ content {System.Data.Entity.Infrastructure.DbQuery<Project.Core.UI.Models.ContentTypeDTO>} object {System.Data.Entity.Infrastructure.DbQuery<Project.Core.UI.Models.ContentTypeDTO>}
+ type {Name = "DbQuery`1" FullName = "System.Data.Entity.Infrastructure.DbQuery`1[[Project.Core.UI.Models.ContentTypeDTO, Project.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"} System.Type {System.RuntimeType}
+ resultType {Name = "OkNegotiatedContentResult`1" FullName = "System.Web.Http.Results.OkNegotiatedContentResult`1[[System.Data.Entity.Infrastructure.DbQuery`1[[Project.Core.UI.Models.ContentTypeDTO, Project.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"} System.Type {System.RuntimeType}
+ result {System.Web.Http.Results.OkNegotiatedContentResult<System.Data.Entity.Infrastructure.DbQuery<Project.Core.UI.Models.ContentTypeDTO>>} System.Web.Http.IHttpActionResult {System.Web.Http.Results.OkNegotiatedContentResult<System.Data.Entity.Infrastructure.DbQuery<Project.Core.UI.Models.ContentTypeDTO>>}
Call stack:
> Project.AdminWebsite.dll!Project.AdminWebsite.Api.Controllers.ODataBaseController.Ok(object content, System.Type type) Line 27 C#
Project.AdminWebsite.dll!Project.AdminWebsite.Api.Controllers.ContentTypeController.Get(System.Web.Http.OData.Query.ODataQueryOptions<Project.DAL.Data.Models.ContentType> odataQueryOptions) Line 132 C#
[Lightweight Function]
System.Web.Http.dll!System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.GetExecutor.AnonymousMethod__9(object instance, object[] methodParameters) Unknown
System.Web.Http.dll!System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(object instance, object[] arguments) Unknown
System.Web.Http.dll!System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(System.Web.Http.Controllers.HttpControllerContext controllerContext, System.Collections.Generic.IDictionary<string,object> arguments, System.Threading.CancellationToken cancellationToken) Unknown
System.Web.Http.dll!System.Web.Http.Tracing.Tracers.HttpActionDescriptorTracer.ExecuteAsync.AnonymousMethod__1() Unknown
System.Web.Http.dll!System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEndAsync<object>(System.Web.Http.Tracing.ITraceWriter traceWriter, System.Net.Http.HttpRequestMessage request, string category, System.Web.Http.Tracing.TraceLevel level, string operatorName, string operationName, System.Action<System.Web.Http.Tracing.TraceRecord> beginTrace, System.Func<System.Threading.Tasks.Task<object>> execute, System.Action<System.Web.Http.Tracing.TraceRecord,object> endTrace, System.Action<System.Web.Http.Tracing.TraceRecord> errorTrace) Unknown
System.Web.Http.dll!System.Web.Http.Tracing.Tracers.HttpActionDescriptorTracer.ExecuteAsync(System.Web.Http.Controllers.HttpControllerContext controllerContext, System.Collections.Generic.IDictionary<string,object> arguments, System.Threading.CancellationToken cancellationToken) Unknown
System.Web.Http.dll!System.Web.Http.Controllers.ApiControllerActionInvoker.InvokeActionAsyncCore() Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<System.Web.Http.Controllers.ApiControllerActionInvoker.InvokeActionAsyncCore>(ref System.Web.Http.Controllers.ApiControllerActionInvoker.InvokeActionAsyncCore stateMachine) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.__Canon>.Start<System.Web.Http.Controllers.ApiControllerActionInvoker.InvokeActionAsyncCore>(ref System.Web.Http.Controllers.ApiControllerActionInvoker.InvokeActionAsyncCore stateMachine) Unknown
System.Web.Http.dll!System.Web.Http.Controllers.ApiControllerActionInvoker.InvokeActionAsyncCore(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken) Unknown
System.Web.Http.dll!System.Web.Http.Controllers.ApiControllerActionInvoker.InvokeActionAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken) Unknown
System.Web.Http.dll!System.Web.Http.Tracing.Tracers.HttpActionInvokerTracer.System.Web.Http.Controllers.IHttpActionInvoker.InvokeActionAsync.AnonymousMethod__1() Unknown
System.Web.Http.dll!System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEndAsync<System.Net.Http.HttpResponseMessage>(System.Web.Http.Tracing.ITraceWriter traceWriter, System.Net.Http.HttpRequestMessage request, string category, System.Web.Http.Tracing.TraceLevel level, string operatorName, string operationName, System.Action<System.Web.Http.Tracing.TraceRecord> beginTrace, System.Func<System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage>> execute, System.Action<System.Web.Http.Tracing.TraceRecord,System.Net.Http.HttpResponseMessage> endTrace, System.Action<System.Web.Http.Tracing.TraceRecord> errorTrace) Unknown
System.Web.Http.dll!System.Web.Http.Tracing.Tracers.HttpActionInvokerTracer.System.Web.Http.Controllers.IHttpActionInvoker.InvokeActionAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken) Unknown
System.Web.Http.dll!System.Web.Http.Controllers.ActionFilterResult.ActionInvoker.InvokeActionAsync() Unknown
System.Web.Http.dll!System.Web.Http.Controllers.ActionFilterResult.ExecuteAsync() Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<System.Web.Http.Controllers.ActionFilterResult.ExecuteAsync>(ref System.Web.Http.Controllers.ActionFilterResult.ExecuteAsync stateMachine) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.__Canon>.Start<System.Web.Http.Controllers.ActionFilterResult.ExecuteAsync>(ref System.Web.Http.Controllers.ActionFilterResult.ExecuteAsync stateMachine) Unknown
System.Web.Http.dll!System.Web.Http.Controllers.ActionFilterResult.ExecuteAsync(System.Threading.CancellationToken cancellationToken) Unknown
System.Web.Http.dll!System.Web.Http.ApiController.ExecuteAsync(System.Web.Http.Controllers.HttpControllerContext controllerContext, System.Threading.CancellationToken cancellationToken) Unknown
System.Web.Http.dll!System.Web.Http.Tracing.Tracers.HttpControllerTracer.ExecuteAsyncCore() Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<System.Web.Http.Tracing.Tracers.HttpControllerTracer.ExecuteAsyncCore>(ref System.Web.Http.Tracing.Tracers.HttpControllerTracer.ExecuteAsyncCore stateMachine) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.__Canon>.Start<System.Web.Http.Tracing.Tracers.HttpControllerTracer.ExecuteAsyncCore>(ref System.Web.Http.Tracing.Tracers.HttpControllerTracer.ExecuteAsyncCore stateMachine) Unknown
System.Web.Http.dll!System.Web.Http.Tracing.Tracers.HttpControllerTracer.ExecuteAsyncCore(System.Web.Http.Controllers.HttpControllerContext controllerContext, System.Threading.CancellationToken cancellationToken) Unknown
System.Web.Http.dll!System.Web.Http.Tracing.Tracers.HttpControllerTracer.System.Web.Http.Controllers.IHttpController.ExecuteAsync.AnonymousMethod__0() Unknown
System.Web.Http.dll!System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEndAsync<System.Net.Http.HttpResponseMessage>(System.Web.Http.Tracing.ITraceWriter traceWriter, System.Net.Http.HttpRequestMessage request, string category, System.Web.Http.Tracing.TraceLevel level, string operatorName, string operationName, System.Action<System.Web.Http.Tracing.TraceRecord> beginTrace, System.Func<System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage>> execute, System.Action<System.Web.Http.Tracing.TraceRecord,System.Net.Http.HttpResponseMessage> endTrace, System.Action<System.Web.Http.Tracing.TraceRecord> errorTrace) Unknown
System.Web.Http.dll!System.Web.Http.Tracing.Tracers.HttpControllerTracer.System.Web.Http.Controllers.IHttpController.ExecuteAsync(System.Web.Http.Controllers.HttpControllerContext controllerContext, System.Threading.CancellationToken cancellationToken) Unknown
System.Web.Http.dll!System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) Unknown
System.Web.Http.dll!System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync() Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync>(ref System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync stateMachine) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.__Canon>.Start<System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync>(ref System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync stateMachine) Unknown
System.Web.Http.dll!System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) Unknown
System.Net.Http.dll!System.Net.Http.HttpMessageInvoker.SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) Unknown
System.Web.Http.dll!System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) Unknown
System.Net.Http.dll!System.Net.Http.DelegatingHandler.SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) Unknown
System.Web.Http.dll!System.Web.Http.Tracing.Tracers.RequestMessageHandlerTracer.AnonymousMethod__FabricatedMethod6() Unknown
System.Web.Http.dll!System.Web.Http.Tracing.Tracers.RequestMessageHandlerTracer.SendAsync.AnonymousMethod__1() Unknown
System.Web.Http.dll!System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEndAsync<System.Net.Http.HttpResponseMessage>(System.Web.Http.Tracing.ITraceWriter traceWriter, System.Net.Http.HttpRequestMessage request, string category, System.Web.Http.Tracing.TraceLevel level, string operatorName, string operationName, System.Action<System.Web.Http.Tracing.TraceRecord> beginTrace, System.Func<System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage>> execute, System.Action<System.Web.Http.Tracing.TraceRecord,System.Net.Http.HttpResponseMessage> endTrace, System.Action<System.Web.Http.Tracing.TraceRecord> errorTrace) Unknown
System.Web.Http.dll!System.Web.Http.Tracing.Tracers.RequestMessageHandlerTracer.SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) Unknown
System.Net.Http.dll!System.Net.Http.DelegatingHandler.SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) Unknown
System.Web.Http.dll!System.Web.Http.HttpServer.AnonymousMethod__FabricatedMethod9() Unknown
System.Web.Http.dll!System.Web.Http.HttpServer.SendAsync() Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<System.Web.Http.HttpServer.SendAsync>(ref System.Web.Http.HttpServer.SendAsync stateMachine) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.__Canon>.Start<System.Web.Http.HttpServer.SendAsync>(ref System.Web.Http.HttpServer.SendAsync stateMachine) Unknown
System.Web.Http.dll!System.Web.Http.HttpServer.SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) Unknown
System.Net.Http.dll!System.Net.Http.HttpMessageInvoker.SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) Unknown
System.Web.Http.WebHost.dll!System.Web.Http.WebHost.HttpControllerHandler.ProcessRequestAsyncCore() Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start<System.Web.Http.WebHost.HttpControllerHandler.ProcessRequestAsyncCore>(ref System.Web.Http.WebHost.HttpControllerHandler.ProcessRequestAsyncCore stateMachine) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start<System.Web.Http.WebHost.HttpControllerHandler.ProcessRequestAsyncCore>(ref System.Web.Http.WebHost.HttpControllerHandler.ProcessRequestAsyncCore stateMachine) Unknown
System.Web.Http.WebHost.dll!System.Web.Http.WebHost.HttpControllerHandler.ProcessRequestAsyncCore(System.Web.HttpContextBase contextBase) Unknown
System.Web.Http.WebHost.dll!System.Web.Http.WebHost.HttpControllerHandler.ProcessRequestAsync(System.Web.HttpContext context) Unknown
System.Web.dll!System.Web.HttpTaskAsyncHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest.AnonymousMethod__0() Unknown
System.Web.dll!System.Web.TaskAsyncHelper.BeginTask(System.Func<System.Threading.Tasks.Task> taskFunc, System.AsyncCallback callback, object state) Unknown
System.Web.dll!System.Web.HttpTaskAsyncHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(System.Web.HttpContext context, System.AsyncCallback cb, object extraData) Unknown
System.Web.dll!System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() Unknown
System.Web.dll!System.Web.HttpApplication.ExecuteStep(System.Web.HttpApplication.IExecutionStep step, ref bool completedSynchronously) Unknown
System.Web.dll!System.Web.HttpApplication.PipelineStepManager.ResumeSteps(System.Exception error) Unknown
System.Web.dll!System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext context, System.AsyncCallback cb) Unknown
System.Web.dll!System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest wr, System.Web.HttpContext context) Unknown
System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) Unknown
System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) Unknown
[Native to Managed Transition]
[Managed to Native Transition]
System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) Unknown
System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) Unknown
[AppDomain Transition]
Error Message:
Unable to cast the type 'System.Web.Http.OData.Query.Expressions.SelectExpandBinder+SelectAll`1[[Project.DAL.Data.Models.ContentType, Project.DAL.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' to type 'Project.DAL.Data.Models.ContentType'. LINQ to Entities only supports casting EDM primitive or enumeration types.
OData query option $expand is used to read multiple entities or entity sets in a single service call instead of two different calls. Prerequisite, entity sets which are used should be associated. To know about Association in OData service click here.
The $value option is used to get individual properties of an Entity. There are two ways to get individual properties from an entity. We can get the response in either OData format or get the raw value of the property. We need to add method to the controller named GetProperty here property is a name of the property.
Now to implement support for OData Query Options we have to do a few things listed down here. Install package 'Microsoft.AspNet.WebApi.OData.5.7.0' Enable support for OData query options in Web API Configuration class.
Instantiating ODataQueryOptions (generic or non-generic) requires an ODataQueryContext and an HttpRequestMessage. Both of these are available as properties on the original ODataQueryOptions. So in order to override our query options we only have to split the incoming RequestUri and create new options from it.
To override the default, set the MaxExpansionDepth property on the [Queryable] attribute. For more information about the $expand option, see Expand System Query Option ($expand) in the official OData documentation. The $select option specifies a subset of properties to include in the response body.
$expand causes related entities to be included inline in the response. $select selects a subset of properties to include in the response. $value gets the raw value of a property. For this article, I'll use an OData service that defines three entities: Product, Supplier, and Category. Each product has one category and one supplier.
From $select and $expand break ODataQueryOptions -- how to fix?
public IHttpActionResult Get(ODataQueryOptions<YourEntity> odataQueryOptions)
{
//Your applyTo logic and results.
if (odataQueryOptions.SelectExpand != null)
{
Request.SetSelectExpandClause(odataQueryOptions.SelectExpand.SelectExpandClause);
}
return Ok(results, results.GetType());
}
private IHttpActionResult Ok(object content, Type type)
{
Type resultType = typeof(OkNegotiatedContentResult<>).MakeGenericType(type);
return Activator.CreateInstance(resultType, content, this) as IHttpActionResult;
}
But as I stated in your other question, keep looking for ways to avoid manually applying the results if you can.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With