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);
}
}
Related
I'm getting an exception instead of a HttpStatusCode.BadResult when I use GetAsync RestSharp method.
Request failed with status code BadRequest
Let me say that Postman and Swagger return the proper value, so I'm doing something wrong in my code.
It works fine when it returns Ok().
That's my controller:
[HttpGet]
public async Task<IActionResult> Get()
{
Sysmac dbStore = new();
var result = await dbStore.AturadesSql.Llista();
return (dbStore.Error) ? BadRequest(dbStore.ErrorMessage) : Ok(result);
}
It simply calls a database procedure and returns an error message in case of error. For the sake of the question I'm forcing that error message to be: 'This is an error'. That is the values returned by Postman.
I tried with this code to avoid network related errors:
[HttpGet]
public async Task<IActionResult> Get()
{
return BadRequest("This is an error");
}
And that's my API client method:
public async Task<APIResult<T>> GetAsync<T>(string apiUrl)
{
APIResult<T> result = new APIResult<T>();
try
{
var request = new RestRequest(apiUrl);
var response = await RestClient.GetAsync(request);
if (response.StatusCode != HttpStatusCode.OK)
{
throw new Exception($"ERROR: API:{apiUrl} (Status: {response.StatusDescription})");
}
var settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
if (response.Content != null)
{
result.Content = JsonConvert.DeserializeObject<T>(response.Content, settings);
}
}
catch (Exception ex)
{
result.Error = true;
result.ErrorMsg = ex.Message;
}
return result;
}
I can't never check response.StatusCode because await RestClient.GetAsync(request) is throwing the exception.
I am using .txt file instead of using excel file so I should be getting 400 error but I am getting 500 error. I want to catch the exception and send a 400 response code with an appropriate response body.
[Route("file/")]
[AuthorizeFunction(AuthFunctions.Schema.Create)]
[HttpPost]
[ResponseType(typeof(Schema))]
public async Task<IActionResult> Create([FromBody] Guid fileId)
{
var result = await _SchemaService.Create(fileId);
return Created("GetSchema", new { id = result.Id }, result);
}
You can use this code to catch specific error
[Route("file/")]
[AuthorizeFunction(AuthFunctions.Schema.Create)]
[HttpPost]
[ResponseType(typeof(Schema))]
public async Task<IActionResult> Create([FromBody] Guid fileId)
{
try {
var result = await _SchemaService.Create(fileId);
return Created("GetSchema", new { id = result.Id }, result);
}
catch (Exception exc){
if (exc.GetType().FullName == "Your_Exception_Name")
{
// Check your exception name here
}
}
}
or
catch(Exception ex)
{
if(ex.InnerException is ExceptionInstance)// exception instance type you want to check
{
}
}
Update
You can just use catch(Exception ex) for general exception then return BadRequest()
catch(Exception ex)
{
return BadRequest();
}
I have a post method to add a new category and save it to the database. and I want to return CreateAtAction to another getmethod.but as I execute the code the data saves in the database with 200 success.
When I try to use Swagger UI though I get "Can not parse json data" and this post method does not move to another get method.
CategoryController.cs
[HttpPost]
public async Task<IActionResult> AddCategory([FromBody] Category category)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_categoryRepository.Add(category);
await Task.Run(() => _categoryRepository.SaveChanges());
return CreatedAtAction(nameof(GetCategoryById) , new { id = category.Id }, category);
}
[HttpGet("{id}")]
public IActionResult GetCategoryById([FromRoute]long id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
//var category = await _context.Category.FirstOrDefaultAsync(i => i.ParentId == id);
var ListCategories = _categoryRepository.GetById(id);
if (ListCategories == null)
{
return NotFound();
}
return Ok(ListCategories);
}
I am using .net core C#, WebApi & AngularJs.
For saving data my Angularjs code makes a $http call to my WebApi. I can return single data from my api fine but not sure whats the best method to return multiple values here. I can make it comma separated and then return as well, but wanted to know if there is a better approach to this.
So basically when the API saves data to my db, I want to return a variable, boolean value if the save was successful and an exception message in case the save was not successfully. Below is my code.
AngularJs Code:
service.saveData(data).then(function (res) {
//get someDataToReturn, dataSaved & exception raised if any from db save here.
}, function (err) {
});
WebApi Code:
[HttpPost("data/save")]
public async Task<IActionResult> SaveData([FromBody] List<UserData> data)
{
bool dataSaved = true;
string someDataToReturn = string.Empty;
//do some processing and updating someDataToReturn here
//Saving data to DB
dataSaved = SaveData(data);
//I want to return someDataToReturn, dataSaved(true or false) and exception raised from SaveData if any
return Ok(someDataToReturn);
}
//DB Call to save data
public bool SaveData(List<UserData> data)
{
try
{
foreach (var set in data)
{
//creating query etc
_db.Execute(query);
}
return true;
}
catch (SqlException ex)
{
}
return false;
}
Let me know the best approach for this.
First of, you should check if the values in your request body is correctly populated.
Take a look at DataAnnotations.
You can use annotations to specify which properties in your model that are Required, Min and Maxlength etc.
Here's an example on how to define a Name property to be required on the UserData class
public class UserData
{
[Required]
public string Name { get; set; }
}
If the request model do not fulfill the specified rules set on the UserData class DataAnnotations, the context ModelState will be set to false and contain the DataAnnotations errors.
This can be used to determind if the current request is a bad request and return a proper http status code from that.
[HttpPost("data/save")]
public async Task<IActionResult> SaveData([FromBody] List<UserData> data)
{
if (!ModelState.IsValid)
return BadRequest(ModelState); //will return a 400 code
...
Then regarding the SaveData method. Capture the exception in the controller and return a proper status code from there
[HttpPost("data/save")]
public async Task<IActionResult> SaveData([FromBody] List<UserData> data)
{
if (!ModelState.IsValid)
return BadRequest(ModelState); //400 status code
try
{
SaveData(data);
}
catch(Exception e)
{
return InternalServerError(e); //500 status code
}
string someDataToReturn = string.Empty;
return Ok(someDataToReturn ); //200 status code
}
public void SaveData(List<UserData> data)
{
foreach (var set in data)
{
//creating query etc
_db.Execute(query);
}
}
You can use the Controller class method Json(object data). Something like:
[HttpPost("data/save")]
public async Task<IActionResult> SaveData([FromBody] List<UserData> data)
{
return this.Json(SaveData(data));
}
See this.
you can create an entity and return it
public class BaseResult{
public bool Result{get;set;}
public string Errors{get;set;}
}
or only
return Ok( new { result = dataSaved , error= exception.Message});
the standard way is:
return 201 status code
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/201
[HttpPost("data/save")]
public async Task<IHttpActionResult> SaveData([FromBody] List<UserData> data)
{
try
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
// return response of 201 if you created the resource successfully
// typically return this with a uri to the new resource
return Created("location", saveData(data));
}
catch (Exception)
{
return InternalServerError();
}
}
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();