Db context on azure app service (mobile) not working

I have a controller running in Azure App Service - Mobile. The trace shows that the code below works until db.SaveChanges() completes.

 var telemetry = new Microsoft.ApplicationInsights.TelemetryClient(); telemetry.TrackTrace("Create User"); using (BCMobileAppContext db = new BCMobileAppContext()) { string Username_NoSpaces = username.Username.Replace(" ", ""); var user = db.Users.FirstOrDefault(u => u.Username_NoSpaces == Username_NoSpaces || u.MicrosoftToken == this.User.Identity.Name); telemetry.TrackTrace("1"); if (user == null && !Username_NoSpaces.Contains(",")) { telemetry.TrackTrace("2"); DateTime now = DateTime.UtcNow; telemetry.TrackTrace("3"); string username_noSpaces = username.Username.Replace(" ", ""); DataObjects.User userItem = new DataObjects.User() { Created = now, UserId = this.User.Identity.Name, MicrosoftToken = this.User.Identity.Name, Username_NoSpaces = username_noSpaces, Update = now, Username = username.Username, Gold = 1, Level = 1, Title = "Sir", InGameCrest = "", ReceiveNotifications = true }; telemetry.TrackTrace("4"); UserDTO returnObject1 = new UserDTO() { Created = userItem.Created, isCreated = true, MicrosoftId = userItem.MicrosoftToken, Username = userItem.Username }; telemetry.TrackTrace("5"); db.Users.Add(userItem); telemetry.TrackTrace("6"); db.SaveChanges(); //Trace and code fails telemetry.TrackTrace("7"); UserDTO returnObject = new UserDTO() { Created = userItem.Created, isCreated = true, MicrosoftId = userItem.MicrosoftToken, Username = userItem.Username }; telemetry.TrackTrace("8"); return Ok(returnObject); } } 

In the stack from the diagnostics in the application service (which I, unfortunately, do not understand):

 2016-04-07T17:29:19 PID[5008] Error Operation=ReflectedHttpActionDescriptor.ExecuteAsync, Exception=System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. at System.Data.Entity.Internal.InternalContext.SaveChanges() at System.Data.Entity.Internal.LazyInternalContext.SaveChanges() at System.Data.Entity.DbContext.SaveChanges() at BCMobileAppService.Controllers.Test2Controller.Post(UserDTO username) in C:\Users\johann\Desktop\BCMobileApp_Runtime\BCMobileAppService\Controllers\TestController.cs:line 78 at lambda_method(Closure , Object , Object[] ) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary 2 arguments, CancellationToken cancellationToken) --- 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.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 2016-04-07T17:29:19 PID[5008] Error Operation=ApiControllerActionInvoker.InvokeActionAsync, Exception=System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. at System.Data.Entity.Internal.InternalContext.SaveChanges() at System.Data.Entity.Internal.LazyInternalContext.SaveChanges() at System.Data.Entity.DbContext.SaveChanges() at BCMobileAppService.Controllers.Test2Controller.Post(UserDTO username) in C:\Users\johann\Desktop\BCMobileApp_Runtime\BCMobileAppService\Controllers\TestController.cs:line 78 at lambda_method(Closure , Object , Object[] ) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary 2 arguments, CancellationToken cancellationToken) --- 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.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.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.ApiControllerActionInvoker.<InvokeActionAsyncCore>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.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 2016-04-07T17:29:19 PID[5008] Error Operation=Test2Controller.ExecuteAsync, Exception=System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. at System.Data.Entity.Internal.InternalContext.SaveChanges() at System.Data.Entity.Internal.LazyInternalContext.SaveChanges() at System.Data.Entity.DbContext.SaveChanges() at BCMobileAppService.Controllers.Test2Controller.Post(UserDTO username) in C:\Users\johann\Desktop\BCMobileApp_Runtime\BCMobileAppService\Controllers\TestController.cs:line 78 at lambda_method(Closure , Object , Object[] ) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.< >c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary 2 arguments, CancellationToken cancellationToken) --- 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.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.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.ApiControllerActionInvoker.<InvokeActionAsyncCore>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.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.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.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.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.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>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.Tracing.Tracers.HttpControllerTracer.<ExecuteAsyncCore>d__5.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.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 

Update

So, I will try this , which will give a more detailed error message:

 catch (DbEntityValidationException dbEx) { foreach (var validationErrors in dbEx.EntityValidationErrors) { foreach (var validationError in validationErrors.ValidationErrors) { Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage); } } } 

AND

I will go through all the settings to ensure that the field, which should not be null , is null , as according to https://stackoverflow.com/a/3129668/169 .

Testing above

The exception hides that the Id field is required is the exception.

In the database, I have EntityData (described here on msdn ) where Id comes from. My use in MobileService was that Id was created when I executed a line that db.SaveChanges() did not work. Can anyone clarify this? The class is as follows:

  public abstract class EntityData : ITableData { protected EntityData(); [Index(IsClustered = true)] [TableColumn(TableColumnType.CreatedAt)] public DateTimeOffset? CreatedAt { get; set; } [TableColumn(TableColumnType.Deleted)] public bool Deleted { get; set; } [TableColumn(TableColumnType.Id)] public string Id { get; set; } [TableColumn(TableColumnType.UpdatedAt)] public DateTimeOffset? UpdatedAt { get; set; } [TableColumn(TableColumnType.Version)] public byte[] Version { get; set; } } 
+5
source share
1 answer

There is no support for automatically generating the primary key of a string in EF. This is why you must assign your primary key manually.

You can initialize Id , CreatedDate and UpdatedDate using the constructor.

  public abstract class EntityData : ITableData { //Change the constructor to initilaize required filled with meaningful data. protected EntityData() { Id=Guid.NewGuid().ToString(); CreatedDate=DateTime.UtcNow; UpdatedDate=DateTime.UtcNow; } [Index(IsClustered = true)] [TableColumn(TableColumnType.CreatedAt)] public DateTimeOffset? CreatedAt { get; set; } [TableColumn(TableColumnType.Deleted)] public bool Deleted { get; set; } [TableColumn(TableColumnType.Id)] public string Id { get; set; } [TableColumn(TableColumnType.UpdatedAt)] public DateTimeOffset? UpdatedAt { get; set; } [TableColumn(TableColumnType.Version)] public byte[] Version { get; set; } } 

You can override the savechanges method in your context. When you change the entity, this method will automatically updateate updated.

  public override int SaveChanges() { //Get Modified Entities var modifiedEntries = ChangeTracker.Entries() .Where(x => x.Entity is ITableData && (x.State == EntityState.EntityState.Modified)); foreach (var entry in modifiedEntries) { var entity = entry.Entity as ITableData; //Modify updateddate if (entity != null) { entity.UpdatedDate = DateTime.UtcNow; } } return base.SaveChanges(); } 

Change The first solution was a general solution that is not implemented with any library.

EntityData you need to serialize. When the mobile client and backend server try to interact with each other, this class will help you. For example, the mobile client does not support navigation properties, but the backend server does this. When you serialize entitydata, it will hide these properties for you.

If you are creating your own database for this application. Follow this document .

First: you must use the EntityData class, which is inside the library. Your models should not inherit from it your EntityData class.

Second: your context must have this code when creating the override model. This is necessary for automatic updates created / updated in and Id (this is the answer to your question).

  protected override void OnModelCreating(DbModelBuilder modelBuilder) { string schema = ServiceSettingsDictionary.GetSchemaName(); if (!string.IsNullOrEmpty(schema)) { modelBuilder.HasDefaultSchema(schema); } modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<TableColumnAttribute, string>( "ServiceTableColumn", (property, attributes) => attributes.Single().ColumnType.ToString())); } 

If you are using an existing database, follow this document .

+3
source

Source: https://habr.com/ru/post/1246647/


All Articles