Put method in web api (EF) - asp.net

I am using a web api put method. I need to update two columns in the database. But I'm having an issue on updating both column.
I've got an error stated below
System.NullReferenceException: 'Object reference not set to an
instance of an object.'
emp was null.
This is my current code;
public class EmployeeController : ApiController
{
public HttpResponseMessage Put(int id, [FromBody] Employee emp)
{
try
{
using (EmpDBContext dbContext = new EmpDBContext())
{
var entity = dbContext.Employees.FirstOrDefault(e => e.Index == id);
if (entity != null)
{
entity.Name = emp.Name;
entity.EmpNum = emp.EmpNum;
dbContext.SaveChanges();
return Request.CreateResponse(HttpStatusCode.OK, entity);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound,
"Employee with Id " + id.ToString() + " not found to update");
}
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}
}
Need some advice regarding this issue.

When you try to use any value in c# which is null then you will get 'Object reference error'. You need to see the API calling method to check why emp is coming null.
Below are the possibility -
Passing parameter name from calling method should exactly same as the name in parameter of the API, in your case it should be emp.
Check your Employee Model if it matching with your calling method properties.
You can check this info from Network tab of your browser.

Related

Entity Framework API Put method, only update one column

I am using Entity Framework API and I am trying to update just one column using the Put method...
[ResponseType(typeof(void))]
[Authorize]
public IHttpActionResult PutLCTimeSlots(int id, LCTimeSlots lCTimeSlots)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != lCTimeSlots.id)
{
return BadRequest();
}
db.Entry(lCTimeSlots).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!LCTimeSlotsExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
My question, what do I need to change in this method to only update one column?
I have tried replacing db.Entry(lCTimeSlots).State = EntityState.Modified; with db.Entry(lCTimeSlots).Property(x => x.taken).IsModified = true; But that didn't work....anyone have any ideas?
You shouldn't use the default PUT for such an operation as it implies a client should be able to update more than a single property. I'd suggest a PUT operation using a route that describes the property being updated w/ parameter of the property's type instead of an LCTimeSlots object:
[HttpPut( "{id}/yourProperty" )]
[Authorize]
public IHttpActionResult YourProperty( int id, TypeOfProperty yourProperty )
{
// validate value of `yourProperty` if you can before loading entity from DB
// load entity from DB
var loadedEntity = dbContext.Set<LCTimeSlots>().Find( id );
// if not found, 404 it
// update property, e.g.:
loadedEntity.YourProperty = yourProperty;
// validate entity in its entirety if necessary
// save changes
}
I'll start by suggesting use of the PATCH verb if you only want to modify certain properties.
Also, it's not a great idea to accept an entity object from the client, instead accept a model object that only has the properties that you aim to modify with this method.
Lastly, verify that the entity exists before attempting to make any change.
Now, do something like this:
var timeSlot = db.LCTimeSlots.SingleOrDefault(e => e.Id == model.Id);
if (timeSlot != null)
{
db.Entry(timeSlot).CurrentValues.SetValues(model);
db.SaveChanges();
}
else
{
//404
}

FromBody value get null in web api

this is my post method in apiController
[HttpPost]
public String Post([FromBody]String key)
{
Users ws;
try
{
ws = JsonConvert.DeserializeObject<Users>(key);
// return "success "+ key;
return db.InsertFineInfo(ws);
}
catch (Exception ex)
{
return "ERROR Testing Purposes: " + ex;
}
}
This is part of my model calss.(Users class)there are many attributes but here i have mentioned only few of em with getters and setters
{
private String UserID;
private String UserName;
private String UserHeight;
private String UserWeight;
private String UserBMI;
private String RequiredNeutrition;
public string UserID1
{
get
{
return UserID;
}
set
{
UserID = value;
}
}
i tried to call this post method using postmen .in every attempt i get a null value for key .
this is how i tried the post method with one header parameter application/json
what went wrong ? something wrong with method or the way i try to call it?
OK a couple points...
Firstly the JSON your method would be expecting would look like
{
"key": "your string....."
}
Secondly the code you have supplied is a bit counter intuitive... Why not simply have
[HttpPost]
public String Post([FromBody]Users ws)
{
... // Done ?
}
You need to publish more code for me to be able to give you a correct answer as to what the JSON would look like that would be accepted by the above method.
In Web API when the parameter comes through as null you can be pretty sure that the JSON sent to the method does not match the JSON generated when you serialize the parameter to a JSON string.
You have to model your input as a C# class, and then take that type as an input.
Assuming that you already have a "User" class, with the same properties as the JSON, that you send in the request body:
[HttpPost]
public String Post([FromBody]User user)
{
try
{
return db.InsertFineInfo(user);
}
catch (Exception ex)
{
return "ERROR Testing Purposes: " + ex;
}
}

WebApi and Swagger

I am using asp.net webapi and using swagger to create a RestApi within a WPF app via AutoRest.
I am having problem figuring out how to consume the returned data if there is an error.
My controller is as follows;
// POST: api/Personnel
//[SwaggerResponse(HttpStatusCode.InternalServerError ,Type = typeof(HttpError))]
[SwaggerOperation("AddEditContract")]
[SwaggerResponse(HttpStatusCode.OK, Description = "Add/Edit a Contract", Type =typeof(int))]
public IHttpActionResult Post(ContractDto value)
{
try
{
var _contractsService = new Business.ContractsService();
var contractToSave = _contractsService.GetContractsById(value.CC_Id);
if (contractToSave == null)
{
return NotFound();
}
var ret = _contractsService.SaveContract(value);
if (ret > 0)
{
return Ok(ret);
}
else
{
return BadRequest();
}
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
I happened to have an error appear within the WebApi based on an error with AutoMapper but it was getting swallowed up. It is returning an error message in the response, which is great.
Here is the current AutoRest code for this call.
public static int? AddEditContract(this IBuxtedConAPI operations, ContractDto value)
{
return Task.Factory.StartNew(s => ((IBuxtedConAPI)s).AddEditContractAsync(value), operations, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap().GetAwaiter().GetResult();
}
As you can see its expecting an int. If I uncomment the
//[SwaggerResponse(HttpStatusCode.InternalServerError ,Type = typeof(HttpError))]
The int return type turns to object.
So the real question.
Here is my service call from WPF to the WebApi
public async Task<int> SaveContract(ContractDto entity)
{
using (var db = new BuxtedConAPI())
{
var ret = await db.AddEditContractAsync(entity);
return (int)ret;
}
}
If an object is returned how do I pick up if an error has occurred or if the simple int (with a success) is just returned.
Thanks in advance.
Scott
Can you post the swagger file that you're generating and passing to AutoRest?
The reason return type turns to object (or whatever common base class is shared between all the possible responses), is because AutoRest treats explicitly defined responses as return values. Exceptions are used only for the default response.
We're investigating ways to specify multiple error responses that will generate the appropriate exceptions.

ASP.Net Web API Action Result

I'm building an ASP.Net Web API application and i have the following code...
public IHttpActionResult GetCustomers() {
var customers = context.Customers.ToList();
return Ok(customers);
}
I'm using the Ok() method to return customers because i'm using an IHttpActionResult return type.
Now if i have the following method
public void DeleteCustomer(int id) {
var customerInDb = context.Customers.SingleOrDefault(c => c.Id == id);
if (customerInDb == null) {
NotFound();
}
context.Customers.Remove(customerInDb);
context.SaveChanges();
}
Can I use NotFound() method here when the return type of my ActionMethod is void???
Void does not have a return type. So you can try to call NotFound(), but I'm not sure if this would even compile - Haven't tried. Why don't you just go with an out of the box IHttpActionResult?
public IHttpActionResult DeleteCustomer(int id)
{
var customerInDb = context.Customers.SingleOrDefault(c => c.Id == id);
if (customerInDb == null)
{
return NotFound();
}
context.Customers.Remove(customerInDb);
context.SaveChanges();
return Ok(customerInDb);
}
Using IHttpActionResult is the more elegant version. If the id is invalid, you can just safely exit your method and tell the calling client that something went wrong. If everything went well, you're just giving the client a thumbs-up. IF you return your deleted entity or just an empty Ok() should not matter at this point.
Using void may or may not delete the entity in your data storage. The client would never know, because the server would not return any response.

How to deserialize

How to deserialize Task response using Json .
public HttpResponseMessage Put(int id, ModelClass modelbject)
{
if (ModelState.IsValid && id == modelbject.modelbjectID)
{
db.Entry(modelbject).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
I want to derialize this and check the IsSuccessStatusCode in my class where i am calling this put method. How can i achieve ?
I want to derialize this and check the IsSuccessStatusCode in my class where i am calling this put method.
You don't have to "deserialize" anything. The method returns an HttpResponseMessage, which has the property you're looking for.
var result = yourController.Put(someId, someObject);
var success = result.IsSuccessStatusCode;
Perhaps the fact that this is a web application is adding some confusion to how you're picturing it. But if you have a class which directly calls this method, then what you get back is simply an HttpResponseMessage object. Which can be inspected just like any other object. No actual web layer is involved in that interaction.

Resources