Validating Model Properties but allow null values - c#

I am trying to get a model property validation to work but allowing a null value in a string property.
The Property i'm trying to validate is a:
public string PhoneNumber { get; set;}
And i am validating it like this:
[Phone(ErrorMessage = "Invalid telephone number.")]
public string PhoneNumber { get; set;}
The validation works great in my case except for when a value is not sent in for Phone number, to the api with an object.
is there any thing like a: [AllowNullValue] attribute or how do i get null values pass the "Phone" attribute?
UPDATE (Anton Gorbunov's post):
{
"Message": "An error has occurred.",
"ExceptionMessage": "The field is not a valid phone number.",
"ExceptionType": "System.ComponentModel.DataAnnotations.ValidationException",
"StackTrace": " at System.ComponentModel.DataAnnotations.ValidationAttribute.Validate(Object value, String name)\r\n at RABE_BCV_API.Controllers.APIController.UpsertMember(MemberModel memberObject) in C:\\Users\\John\\Documents\\Visual Studio 2015\\Projects\\RABE_BCV_API\\RABE_BCV_API\\Controllers\\APIController.cs:line 29\r\n at lambda_method(Closure , Object , Object[] )\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, 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.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\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.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\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.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}

It looks strange, because is the first instruction of IsValid Metod in PhoneAttribute is:
public override bool IsValid(object value) {
if (value == null) {
return true;
}
...
}
Maybe you use [Required] or [BindRequired] attributes?

Related

Passing collection in querystring does not work with ODataQueryOptions

I have following existing GET endpoint
[HttpGet]
public async Task<IHttpActionResult> Get(ODataQueryOptions<Section> oDataOptions) {
//code here
return response;
}
I need to add a collection in querystring like <basequery>?$filter=id eq 1&includeCategory=A&includeCategory=B
so this would be bound as a collection in modified get endpoint as follows -
[HttpGet]
public async Task<IHttpActionResult> Get([FromUri (Name = "includeCategory"] ) List<Category> categories, ODataQueryOptions<Section> oDataOptions) {
//code here
return response;
}
Public enum Category {
A,
B
}
If I make postman request to this, I am getting An item with the same key has already been added.
System.ArgumentException: An item with the same key has already been added.
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
at System.Web.OData.Query.ODataQueryOptions..ctor(ODataQueryContext context, HttpRequestMessage request)
at System.Web.OData.Query.ODataQueryOptions`1..ctor(ODataQueryContext context, HttpRequestMessage request)
at System.Web.OData.ODataQueryParameterBindingAttribute.ODataQueryParameterBinding.CreateODataQueryOptions[T](ODataQueryContext context, HttpRequestMessage request)
at System.Web.OData.ODataQueryParameterBindingAttribute.ODataQueryParameterBinding.ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
at System.Web.Http.Controllers.HttpActionBinding.<ExecuteBindingAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
If my querystring has this <basequery>?$filter=id eq 1&includeCategory=A, this is working fine with ODataQueryOptions.
If my querystring has this <basequery>?$filter=id eq 1&includeCategory[0]=A&includeCategory[0]=B, this is working fine as well with ODataQueryOptions .
Same works for following with url <basequery>/1?includeCategory=A&includeCategory=B and endpoint with no $filter
[Route("{id}")
[HttpGet]
public async Task<IHttpActionResult> Get([FromUri (Name = "includeCategory"] ) List<Category> categories, long id) {
//code here
return response;
}
There is nothing in Section class that might collide with name Category.
That's why I am suspecting it's something to do with $filer, please suggest.

Structuremap - setup dependency which has dependency

I'm using structure map as my IOC with web api and I have an injected dependency in my controller and it's concrete type also has a dependecy.
Controller
[RoutePrefix("api/products")]
public class ProductsController : BaseApiController
{
//private readonly ProductRepository _manageProducts;
private readonly IProductFactory _productFactory;
private readonly IGenericRepository _genericRepository;
public ProductsController(IProductFactory productFactory, IGenericRepository genericRepository)
{
_productFactory = productFactory;
_genericRepository = genericRepository;
//_manageProducts = new ProductRepository();
}
[Authorize]
[Route("addProduct")]
public IHttpActionResult AddNewProduct(ProductViewModels.AddProductViewModel product)
{
if (User.IsInRole("Admin"))
{
_productFactory.CreateProduct(product);
return Ok("Product Successfully Added");
}
return BadRequest("Your must have Administrator rights to perform the operation.");
}
}
Factory
public class ProductFactory : IProductFactory
{
private readonly IGenericRepository _genericRepository;
public ProductFactory(IGenericRepository genericRepository)
{
_genericRepository = genericRepository;
}
/// <summary>
/// Creates the product.
/// </summary>
/// <returns>The product.</returns>
/// <param name="viewModel">New product.</param>
public Product CreateProduct(ProductViewModels.AddProductViewModel viewModel)
{
var productToBeAdded = new Product
{
Title = viewModel.Title,
ISBN = viewModel.ISBN,
};
return productToBeAdded;
}
}
When I try to call product controller addproducts I get this runtime error for null reference exception:
{
"Message": "An error has occurred.",
"ExceptionMessage": "Object reference not set to an instance of an object.",
"ExceptionType": "System.NullReferenceException",
"StackTrace": " at ICEBookshop.API.Factories.ProductFactory.CreateProduct(AddProductViewModel viewModel) in C:\\Users\\GOWDY_N\\Source\\Repos\\ICEBookshop.API\\ICEBookshop.API\\P00603ClientApi\\Factories\\ProductFactory.cs:line 29\r\n at ICEBookshop.API.Controllers.ProductsController.AddNewProduct(AddProductViewModel product) in C:\\Users\\GOWDY_N\\Source\\Repos\\ICEBookshop.API\\ICEBookshop.API\\P00603ClientApi\\Controllers\\ProductsController.cs:line 95\r\n at lambda_method(Closure , Object , Object[] )\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, 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.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\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.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\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.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()\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.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}
This is what I've done with structuremap
public class DefaultRegistry : Registry
{
#region Constructors and Destructors
public DefaultRegistry()
{
Scan(
scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
For<IGenericRepository>().Use<GenericRepository<ApplicationDbContext>>();
For<IProductFactory>()
.Use<ProductFactory>()
.Ctor<IGenericRepository>()
.Is<GenericRepository<ApplicationDbContext>>().Named("DefaultInstanceKey");
#endregion
}
}
I thought this would fix it so it knows how to resolve my factory:
For<IProductFactory>()
.Use<ProductFactory>()
.Ctor<IGenericRepository>()
.Is<GenericRepository<ApplicationDbContext>>().Named("DefaultInstanceKey");
But it doesn't work neither. Does anyone know how to fix this?
Just register the two interfaces and their implementations. The framework will resolve the dependencies when resolving the target.
For<IGenericRepository>().Use<GenericRepository<ApplicationDbContext>>();
For<IProductFactory>().Use<ProductFactory>();

ASP.NET Core database configuration with dependency injection issue

I ran in to a problem 6 days ago and i still can't figure it out.
I'm setting up a DBContext using DI:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddDbContext<ApplicationContext>(options =>
options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
The database file path is configurered in the appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=xxxx.db"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
And I'm creating a DBContext like this (https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext)
public class ApplicationContext : DbContext
{
public DbSet<Network> xxxx { get; set; }
public DbSet<NetworkEntry> xxxx { get; set; }
public ApplicationContext(DbContextOptions<ApplicationContext> options)
: base(options)
{ }
}
My controller code:
public JsonResult Index(ApplicationContext db)
{
return Json(db.Networks);
}
It compiles and runs. If I use the other way of configuring the DB, it works 100% problem free:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Filename=./blog.db");
}
The problem I'm having:
System.InvalidOperationException: Could not create a model binder for model object of type 'xxx.Data.ApplicationContext'.
at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory.CreateBinder(ModelBinderFactoryContext context)
at Microsoft.AspNetCore.Mvc.Internal.DefaultControllerArgumentBinder.<BindModelAsync>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Mvc.Internal.DefaultControllerArgumentBinder.<BindArgumentsCoreAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeNextResourceFilter>d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeAsync>d__20.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.<Invoke>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__7.MoveNext()
Any clues?
I have just solved a similar problem. The problem for me was that I'd misunderstood the dependency injection. The context doesn't get passed to the Controller method, but to the Controller's constructor.
public class NetworksController : Controller
{
private readonly ChoirAdminContext db;
public NetworksController(ApplicationContext context)
{
db = context;
}
public JsonResult Index()
{
return Json(db.Networks);
}
}

Using ActionFilterAttribute for model validation

I am trying to use ActionFilterAttribute to validate the model when a call is made to my Web API. I have added the following
public class ValidateModelStateAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
}
I have added standard validators to my model properties and it all works fine. However when I add a custom class level validator it fails with the following error.
A validation attribute of type XXXValidatorAttribute cannot be used to
validate values."
StackTrace: at
Microsoft.Practices.EnterpriseLibrary.Validation.Validators.BaseValidationAttribute.IsValid(Object
value)\r\n at
System.ComponentModel.DataAnnotations.ValidationAttribute.IsValid(Object
value, ValidationContext validationContext)\r\n at
System.ComponentModel.DataAnnotations.ValidationAttribute.GetValidationResult(Object
value, ValidationContext validationContext)\r\n at
System.Web.Http.Validation.Validators.DataAnnotationsModelValidator.Validate(ModelMetadata
metadata, Object container)\r\n at
System.Web.Http.Validation.DefaultBodyModelValidator.ShallowValidate(ModelMetadata
metadata, ValidationContext validationContext, Object container,
IEnumerable'1 validators)\r\n at
System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata
metadata, ValidationContext validationContext, Object container,
IEnumerable'1 validators)\r\n at
System.Web.Http.Validation.DefaultBodyModelValidator.Validate(Object
model, Type type, ModelMetadataProvider metadataProvider,
HttpActionContext actionContext, String keyPrefix)\r\n at
System.Web.Http.ModelBinding.FormatterParameterBinding.d__0.MoveNext()\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.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n at
System.Web.Http.Controllers.HttpActionBinding.d__0.MoveNext()\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.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n at
System.Web.Http.Controllers.ActionFilterResult.d__2.MoveNext()\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.Runtime.CompilerServices.TaskAwaiter'1.GetResult()\r\n at
System.Web.Http.Controllers.AuthenticationFilterResult.d__0.MoveNext()\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.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at
System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()
This validator works fine when I invoke it via a unit test using a validation factory. I am not sure why it fails during ModelState validation? What is the difference between the two?
I have the model defined as
I have a model defined as
[CashDetailValidator()]
public sealed class CashDetails : DetailsBase
{
// Reference Number
[ValidatorComposition(CompositionType.Or)]
[NotNullValidator(Negated=true)]
[StringLengthValidator(1, RangeBoundaryType.Inclusive, 16, RangeBoundaryType.Exclusive, MessageTemplate = "Reference number should be between 1 to 16 characters in length.")]
public string RelatedReference { get; set; } ...........................
}}
The composition validator also gives the same error.

Using DTO in Azure Mobile Service .NET throws target invocation exception

I use Azure Mobile Services .NET backend and we all know we have to use Entity Framework classes to map to the database creation/migration.
So I need to use DTOs to serialize only the properties I want, computed properties etc. I'm following the Field Engineer example. But Automapper gave me so much pain although I did everything as supposed to.
I have checked couple of others blog and site, some use Automapper, others not, for example this one. I feel more comfortable not using Automapper and create DTOs on the fly with Select() as I was doing it before when implementing Web API.
I reverted TableController class to Post, use the EntityDomainManager and I left the GetAllPosts method to the following.
public class PostController : TableController<Post>
{
private MobileServiceContext _context;
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
_context = new MobileServiceContext();
DomainManager = new EntityDomainManager<Post>(_context, Request, Services);
}
//[ExpandProperty("User")]
// GET tables/Post
public IQueryable<PostDto> GetAllPost()
{
return Query().Include("User").Select(x => new PostDto());
}
}
I get the following error.
{"message":"An error has occurred.","exceptionMessage":"Exception has been thrown by the target of an invocation.","exceptionType":"System.Reflection.TargetInvocationException","stackTrace":" at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)\r\n at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)\r\n at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)\r\n at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)\r\n at System.Web.Http.OData.Query.ODataQueryOptions.LimitResults(IQueryable queryable, Int32 limit, Boolean& resultsLimited)\r\n at System.Web.Http.OData.Query.ODataQueryOptions.ApplyTo(IQueryable query, ODataQuerySettings querySettings)\r\n at System.Web.Http.OData.EnableQueryAttribute.ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)\r\n at System.Web.Http.OData.EnableQueryAttribute.ExecuteQuery(Object response, HttpRequestMessage request, HttpActionDescriptor actionDescriptor)\r\n at System.Web.Http.OData.EnableQueryAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)\r\n at System.Web.Http.Filters.ActionFilterAttribute.OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, 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.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\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.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()\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.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\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.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()\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.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\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.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()\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.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at System.Web.Http.Controllers.AuthenticationFilterResult.<ExecuteAsync>d__0.MoveNext()\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.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()\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.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()","innerException":{"message":"An error has occurred.","exceptionMessage":"The specified type member 'DatePosted' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.","exceptionType":"System.NotSupportedException","stackTrace":" at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MemberAccessTranslator.TypedTranslate(ExpressionConverter parent, MemberExpression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input, DbExpressionBinding& binding)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateSet(Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.ThenByTranslatorBase.Translate(ExpressionConverter parent, MethodCallExpression call)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateSet(Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.ThenByTranslatorBase.Translate(ExpressionConverter parent, MethodCallExpression call)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateSet(Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.UnarySequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.Convert()\r\n at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)\r\n at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__6()\r\n at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)\r\n at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()\r\n at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)\r\n at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)\r\n at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()\r\n at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()\r\n at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)\r\n at System.Web.Http.OData.Query.TruncatedCollection`1..ctor(IQueryable`1 source, Int32 pageSize)\r\n at System.Web.Http.OData.Query.ODataQueryOptions.LimitResults[T](IQueryable`1 queryable, Int32 limit, Boolean& resultsLimited)"}}
If I just convert it to the Entity Framework class it works. You will notice that I don't fill any property, just for testing purposes.
I test locally with IIS Express.
Data objects and models.
public class Post : EntityData
{
public DateTimeOffset DatePosted { get; set; }
public string StatusText { get; set; }
public PostType TypeOfPost { get; set; }
[ForeignKey("Id")]
public virtual User User { get; set; }
[ForeignKey("Id")]
public virtual ICollection<PostPhotoUrl> PhotoUrls { get; set; }
}
public class PostDto
{
public PostDto()
{
PhotoUrls = new HashSet<PostPhotoUrlDto>();
}
public DateTimeOffset DatePosted { get; set; }
public string StatusText { get; set; }
public int TypeOfPost { get; set; }
public UserDto User { get; set; }
public ICollection<PostPhotoUrlDto> PhotoUrls { get; set; }
}
Searching the internet couldn't find any other more clear tutorial how to use Azure Mobile Services and DTOs, though it shouldn't introduce such difficulty. If you have any resources are welcome.
I should mention that if I don't do the following the test website raises error when trying to test the endpoints.
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
The exception snapshot:
I don't REALLY need to have DTOs for this project, but if I don't resolve what I don't understand right now it will come back and hunt me in the long run of this service.
I'm not sure but think the problem may be with this line of code
return Query().Include("User").Select(x => new PostDto());
if youre NOT using AutoMapper then you will need to manually parse the properties in your Select statement something like this
return Query().Include("User")
.Select(x => new PostDto()
{
DatePosted = x.DatePosted,
StatusText = x.StatusText,
TypeOfPost = x.TypeOfPost,
User = new UserDto
{
//Your propertoes here
//eg Id = x.User.Id etc
}
);
It seems that the Select() LINQ expression conflicts before the elements are fully loaded or the references are still unset.
I converted the method to a IEnumerable return type and eager loaded the data before transforming to DTOs.
public IEnumerable<PostDto> GetAllPost()
{
return Query().Include("User").ToList().Select(x => new PostDto
{
DatePosted = x.DatePosted,
StatusText = x.StatusText,
TypeOfPost = (int)x.TypeOfPost,
User = new UserDto
{
Id = x.User.Id
}
});
}
After testing my service, it returned the following data I have inserted in my database.
[
{
"datePosted": "2015-04-27T04:05:38.843Z",
"statusText": "Post Text",
"typeOfPost": 1,
"user": {
"id": "a59d0f12-8bb1-448e-9c08-56f862b77ee4"
},
"photoUrls": []
}
]
Should test with AutoMapper now to cover that it works with it too.
Only unknown point is why I need to set the ReferenceLoopHandling property to Ignore for the service to show properly JSON sample data.
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

Categories

Resources