Entities Framework SaveChanges() Not Working - c#

I have a problem when calling API for update and savechanges() is not working (the data is not update).
However, when I add Thread.Sleep(1000); the data update correctly.
Working Methods
public async Task<ResponseBaseModel> AddOrderRemark2(AddOrderRemarkRequestModel model)
{
try
{
using (ChatEntities context = new ChatEntities(CurrentUsername))
{
List<string> statusList = getPendingStatus(context).Result;
OrderHeader orderHeader = getOrderHerderByOrderCode(context, model.OrderCode, model.SalesChannelId).Result;
if (statusList.Contains(orderHeader.Status))
{
if (orderHeader != null)
{
Thread.Sleep(1000);
orderHeader.Remark = model.Remark;
context.DBEntry(orderHeader, EntityState.Modified);
context.SaveChanges();
}
}
}
return new ResponseBaseModel(MessageCode.OK);
}
catch (Exception ex)
{
return new ResponseBaseModel(MessageCode.Fail, ex.InnerException.Message);
}
}
Fail Methods
public async Task<ResponseBaseModel> AddOrderRemark2(AddOrderRemarkRequestModel model)
{
try
{
using (ChatEntities context = new ChatEntities(CurrentUsername))
{
List<string> statusList = getPendingStatus(context).Result;
OrderHeader orderHeader = getOrderHerderByOrderCode(context, model.OrderCode, model.SalesChannelId).Result;
if (statusList.Contains(orderHeader.Status))
{
if (orderHeader != null)
{
orderHeader.Remark = model.Remark;
context.DBEntry(orderHeader, EntityState.Modified);
context.SaveChanges();
}
}
}
return new ResponseBaseModel(MessageCode.OK);
}
catch (Exception ex)
{
return new ResponseBaseModel(MessageCode.Fail, ex.InnerException.Message);
}
}
Edit
I have realise that there are two APIs call at the same times from client sides. Moreover, these two APIs update on the same table 'OrderHeader' which contain both receiver info and remark that why it causes this issue!!. How can I prevent this issue guys?
[HttpPost]
[ActionName("AddReceiverAddress")]
[ChatAuthentication]
public async Task<ResponseBaseModel> AddReceiverAddress(AddReceiverAddressRequestModel model)
{
return _orderService.Value.AddReceiverAddress(model).Result;
}
[HttpPost]
[ActionName("AddOrderRemark")]
[ChatAuthentication]
public async Task<ResponseBaseModel> AddOrderRemark(AddOrderRemarkRequestModel model)
{
return _orderService.Value.AddOrderRemark(model).Result;
}

You are not using async properly. Try this instead
public async Task<ResponseBaseModel> AddOrderRemark2(AddOrderRemarkRequestModel model)
{
try
{
using (ChatEntities context = new ChatEntities(CurrentUsername))
{
List<string> statusList = await getPendingStatus(context);
OrderHeader orderHeader = await getOrderHerderByOrderCode(context, model.OrderCode, model.SalesChannelId);

When you call this method, did you await or Wait() for a result?
When you call the method you have to do either one of them as below sample.
await AddOrderRemark2(model);
Or
AddOrderRemark2(model).Wait();

Related

ASP.NET Core - call one controller method from another

I need to call from create method delete for cleanup. I want to call DeleteDevice like lazy cleanup and do not care if it will succeed or not.
People suggested to use this way:
DeleteDevice(param).ConfigureAwait(false);
Is it safe?
public async Task<ActionResult<Device>> CreateDevice([FromBody] CreateDeviceRequest request)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
try
{
var registeredDevice = await RegisterDevice(request.DisplayName);
bool isCreatePrinterSucceed = false;
try
{
var updatedDevice = await UpdateDevice(registeredDevice.Id);
isCreatePrinterSucceed = true;
return Ok(new DeviceReference
{
DisplayName = request.DisplayName,
Id = updatedDevice.Id
});
}
finally
{
if (!isCreatePrinterSucceed)
{
var param = new DeleteDeviceRequest()
{
Id = registeredDevice.Id,
AzureUserBearerToken = request.AzureUserBearerToken
};
DeleteDevice(param).ConfigureAwait(false); ;
}
}
}
catch (Exception ex)
{
return StatusCode((int)HttpStatusCode.InternalServerError, ex.Message);
}
}

New Transaction are not allowed Entity Framework 6

In an ASP.NET Webforms application on .NET 4.0 and a Web API, I attempt to add an order and orderRow to the database, but I get this error:
Error: new transactions are not allowed because there are other running threads in the session
From the client, I run an Ajax post to the controller, which has the following code for inserting a value into the database:
private readonly MyDatabaseEntities _ctx;
public ComponibileController()
{
_ctx = new MyDatabaseEntities(#"xxx");
}
[HttpPost]
public void Post([FromBody] ComponibileCreate model)
{
if (!ModelState.IsValid) return;
var taskWork = System.Threading.Tasks.Task.Run(() => SaveOnDatabase(model, utente));
...query
SendMailToUser(...);
taskWork.Wait();
}
public void SaveOnDatabase(ComponibileCreate model, string utente)
{
try
{
using (_ctx)
{
var ordine = new COM_ORDINI
{
..,
};
foreach (var item in model.Righe.ToList())
{
var righe = new COM_RIGHE
{
...
};
ordine.COM_RIGHE.Add(righe);
}
_ctx.COM_ORDINI.Add(ordine);
_ctx.SaveChanges();
}
}
catch (Exception e)
{
}
}
instead System.Threading.Tasks.Task.Run(() => SaveOnDatabase(model, utente)); , use
async Task SaveOnDatabase(ComponibileCreate model, string utente) {
...
await _ctx.SaveChangesAsync();
}
and call await SaveOnDatabase(model, utente) in action

Asp Mvc 5 Async/Await Issue

public async Task<ActionResult> Index()
{
var service = new CoreServiceFactory().GetImpersonatingService();
try
{
var data = new Impersonation()
{
ImpersonatingId = "dac733c3-01ad-447b-b0df-3a7c21fef90b",
UserId = "dac733c3-01ad-447b-b0df-3a7c21fef90b"
};
var imp = await service.Add(data);
}catch(Exception ex) { throw ex; }
return View();
}
Above is one of my controllers action method. And this works fine when the insertion is successful. This should fail if the data already exists in database(unique constraints). So when i intentionally try to make it fail(i manually add the same record in the db and then try to add it again via this action method) the action method goes into a loop or something, the exception is never thrown , chrome keeps me showing me the loading icon , looks like it went into some deadlock state. Can someone please help me understand why it goes into deadlock state when exception is thrown and how can i handle it?
Below are the reference methods
service.Add(data)
public async Task<Impersonation> Add(Impersonation t)
{
if (ValidateData(t))
{
using (var uow = GetUnitOfWork())
{
var r = GetRepository(uow);
var item = r.Add(t);
try
{
var ret = await uow.Save();
if (ret > 0)
{
return item;
}
else
{
return null;
}
}
catch (Exception ex)
{
throw ex;
}
}
}
else
{
throw new ValidationException(null, "error");
}
}
uow.Save()
public class BaseUnitOfWork : IUnitOfWork
{
public DbContext _Context { get; private set; }
public BaseUnitOfWork(DbContext context)
{
this._Context = context;
}
public async Task<int> Save()
{
try
{
var ret = await this._Context.SaveChangesAsync();
return ret;
}catch(Exception ex)
{
throw ex;
}
}
}
Here is my suggestion: in uow.Save, log the error in the catch block and return zero (do not throw any exceptions).
public class BaseUnitOfWork : IUnitOfWork
{
public DbContext _Context { get; private set; }
public BaseUnitOfWork(DbContext context)
{
this._Context = context;
}
public async Task<int> Save()
{
try
{
var ret = await this._Context.SaveChangesAsync();
return ret;
}catch(Exception ex)
{
// log the error here
return 0;
}
}
}
I'm not sure if returning the null in the Add service is a good idea or not, you might need to handle that differently too.

Refactor Error Handling in WebAPI Controller

I have lots of controllers methods in WebAPI similar to the following:
public IHttpActionResult Delete(int id)
{
var command = new DeleteItemCommand() { Id = id };
try
{
_deleteCommandHandler.Handle(command);
}
catch (CommandHandlerResourceNotFoundException)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
catch(CommandHandlerException)
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
// More catches etc...
return Ok();
}
The command handlers (in this instance _deleteCommandHandler) is injected earlier in the execution and the commands may be built in the method or using WebApi's automatic method.
What I would like to do is to encapsulate the try/catch error handling in a private method and end up with a controller similar to:
public IHttpActionResult Delete(int id)
{
var command = new DeleteItemCommand() { Id = id };
return ExecuteCommand(x => _deleteCommandHandler.Handle(command));
}
I'm not sure what the signature of the private ExecuteCommand method should be though.
I think you can Invoke your action in a method like this:
public IHttpActionResult Delete(int id)
{
return ExecuteCommand(() => {
var command = new DeleteItemCommand() { Id = id };
_deleteCommandHandler.Handle(command);
});
}
private IHttpActionResult ExecuteCommand(Action action)
{
try
{
action.Invoke();
//or: action();
}
catch (CommandHandlerResourceNotFoundException)
{
return HttpResponseException(HttpStatusCode.NotFound);
}
catch (CommandHandlerException)
{
return HttpResponseException(HttpStatusCode.InternalServerError);
}
return Ok();
}
A good reference for HttpResponseException.
I would create a custom error handler filter, and handle all possible errors there in a centralized form. That way you can just throw whatever exception from the action methods, and then they will be caught at the filter where you can handle them and change the response accordingly.
public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
}
}
}
The example is taken from this article where you can find the concept in more detail.
Here's a solution similar to shA.t's answer, but the exceptions are mapped in a dictionary and the try/catch logic is in an extension method:
public class TestController:ApiController
{
public IHttpActionResult Delete(int id)
{
return ExecuteCommand(() => {
var command = new DeleteItemCommand() { Id = id };
_deleteCommandHandler.Handle(command);
});
}
private IHttpActionResult ExecuteCommand(Action action)
{
return action.SafeInvoke();
}
}
public static class ActionExtensions
{
private static readonly Dictionary<Type, HttpStatusCode> _exceptionToStatusCodeLookup = new Dictionary<Type, HttpStatusCode>
{
{typeof(CommandHandlerResourceNotFoundException), HttpStatusCode.NotFound },
{typeof(CommandHandlerException), HttpStatusCode.InternalServerError },
};
public static IHttpActionResult SafeInvoke(this Action action)
{
try
{
action();
}
catch (Exception ex)
{
var statusCode = _exceptionToStatusCodeLookup.ContainsKey(ex.GetType()) ? _exceptionToStatusCodeLookup[ex.GetType()] : HttpStatusCode.InternalServerError;
return new HttpResponseException(statusCode);
}
return new OkResult();
}
}

Unable to use result of Async DocumentDB operation CreateDocumentAsync

I have created a documentDB on Azure and can successfully create and get documents.
However, whilst documents are successfully created in the DB, I am not able to use the response from CreateDocumentAsync. The code immediately returns to the calling method on the controller. So the debug line is never reached.
Moreover I am setting the id to a guid, but the Document that is returned to the controller has an Id of 1.
Controller
[HttpPost]
[Route("")]
public IHttpActionResult CreateNewApplication(dynamic data)
{
if (data == null)
{
return BadRequest("data was empty");
}
try
{
var doc = _applicationResource.Save(data);
return Ok(doc.Id); //code hits this point and 'returns'
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
Resource
public async Task<Document> Save(dynamic application)
{
Document created;
using (Client)
{
application.id = Guid.NewGuid();
var database = await RetrieveOrCreateDatabaseAsync(Database);
var collection = await RetrieveOrCreateCollectionAsync(database.SelfLink, CollectionName);
//persist the documents in DocumentDB
created = await Client.CreateDocumentAsync(collection.SelfLink, application);
}
Debug.WriteLine("Application saved with ID {0} resourceId {1}", created.Id, created.ResourceId);
return created;
}
Get requests return data as expected:
[HttpGet]
[Route("{id}")]
public IHttpActionResult GetApplication(string id)
{
var application = _applicationResource.GetById(id);
return Ok(application);
}
That's because you're not awaiting an asynchronous method:
This:
var doc = _applicationResource.Save(data);
Needs to be:
var doc = await _applicationResource.Save(data);
Your method should look as follows:
[HttpPost]
[Route("")]
public async Task<IHttpActionResult> CreateNewApplication(dynamic data)
{
if (data == null)
{
return BadRequest("data was empty");
}
try
{
var doc = await _applicationResource.Save(data);
return Ok(doc.Id); //code hits this point and 'returns'
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}

Categories