PUT request to API is setting values to NULL - asp.net-core

I have this .Net Core API controller below that does a PUT request.
The table affected in Sql Server, looks like this:
carID (varchar(15), NULL)
optionID (varchar(15), NOT NULL)
optionDescription (varchar(255), NULL)
optionType (varchar(50), NULL)
factoryID (varchar(15), NULL)
In testing, I am sending along the properties I want changed like this in my PUT API call:
{
" optionID": "633fr",
"optionDescription": "Full Tech Package A"
}
It does update the entry in the database, but it's also setting all the values not sent in the PUT call to NULL. So while it does update optionDescription, it is setting all the other values to NULL except optionID.
How do I stop it from setting the other values?
thanks!
Here is the controller:
// PUT: api/CarOptions/5
[HttpPut("{id}")]
public async Task<IActionResult> PutCarOptions(Guid id, CarOptions carOptions)
{
if (id != carOptions.OptionId)
{
return BadRequest();
}
_context.Entry(carOptions).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CarOptionsExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}

According to your description, I suggest you could try to attach the model firstly and then set the specific property IsModified to true.
This will only update specific fields instead of updating whole model.
More details, you could refer to below example:
// PUT: api/CarOptions/5
[HttpPut("{id}")]
public async Task<IActionResult> PutCarOptions(Guid id, CarOptions carOptions)
{
_context.Documents.Attach(carOptions);
_context.Entry(carOptions).Property(x => x.optionDescription).IsModified = true;
_context.SaveChanges();
return NoContent();
}

Related

Asp.net core api I can't enter more than one data on the same line

I have 3 tables, customer table has one to many relation with the other tables
a customer needs to add more than one address and phone number. With HTTPGET, I can pull data as follows, but I cannot perform crud operations.
enter image description here
GET:
[HttpGet("{id}")]
public async Task<ActionResult<Customer>> GetCustomer(int id)
{
var customers = _context.Customers
.Include(customer => customer.Adresses)
.Include(customer=> customer.Phones)
.Where(customer => customer.CId == id)
.FirstOrDefault();
if (customers == null)
{
return NotFound();
}
return customers;
}
POST:
[HttpPost]
public async Task<ActionResult<Customer>> PostCustomer(Customer customer)
{
_context.Customers.Add(customer);
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException)
{
if (CustomerExists(customer.CId))
{
return Conflict();
}
else
{
throw;
}
}
return CreatedAtAction("GetCustomer", new { id = customer.CId }, customer);
}
I can't enter more than one data on the same line
I want to receive customer information (how many addresses and phone numbers) at the same time as a record, I don't know how to do this.

update values in selected columns in using EF core

I am new to ASP.NET core and EF Core. I need some help to get update values in selected colums in using EF core.
I need my view to provide List of students and give an option to updated FeePaid only with out giving an option to modify rest of the data.I have tried to modify "TryUpdateModelAsync" only include fee Paid as shown below but it updates rest of the fields with null value. I am working on SQL server LocalDb for now in visual studio 2019 and Code will be published in Azure.
Thanks for your help.
TryUpdateModelAsync<Student>(
studentToUpdate,
"student",
s=> s.FeePaid)
In SQL I can write a query to updated only selected colums with new values.
UPDATE table_name
SET column1 = value1, column2 = value2
WHERE condition;
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
Student = await _context.Students.FindAsync(id);
if (Student == null)
{
return NotFound();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(int id)
{
var studentToUpdate = await _context.Students.FindAsync(id);
if (studentToUpdate == null)
{
return NotFound();
}
if (await TryUpdateModelAsync<Student>(
studentToUpdate,
"student",
s => s.FirstMidName, s => s.LastName, s => s.EnrollmentDate, s=> s.Confirmed, s=> s.FeePaid))
{
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
return Page();
}

Advantage of using IActionResult as result type in Actions

What's the advantage or recommendation on using IActionResult as the return type of a WebApi controller instead of the actual type you want to return?
Most of the examples I've seen return IActionResult, but when I build my first site I exclusively use View Model classes as my return types.... now I feel like I did it all wrong!
The main advantage is that you can return error/status codes or redirects/resource urls.
For example:
public IActionResult Get(integer id)
{
var user = db.Users.Where(u => u.UserId = id).FirstOrDefault();
if(user == null)
{
// Returns HttpCode 404
return NotFound();
}
// returns HttpCode 200
return ObjectOk(user);
}
or
public IActionResult Create(User user)
{
if(!ModelState.IsValid)
{
// returns HttpCode 400
return BadRequest(ModelState);
}
db.Users.Add(user);
db.SaveChanges();
// returns HttpCode 201
return CreatedAtActionResult("User", "Get", new { id = user.Id} );
}
The main advantage is that you can easily test your code using a mocking framework.
And as you build your controllers, you can easily change your return object as well. IActionResult is a interface and has many implementations like JsonResult, ViewResult, FileResult and so on.

MVC4 - during post controller action, the WebSecurity.CurrentUserId is losing it's value, and becomes -1

Somehow, in this controller, after the SaveChanges, the CurrentUserId becomes -1.
The data post works, and the CurrentUserId has it's logged in value (example 8888), but after the SQL insert, the WebSecurity.CurrentUserId becomes -1. Any clue? During debug I can't find where and why.
// POST: /Account/Edit
[HttpPost]
[ValidateInput(false)]
public ActionResult Edit(UserProfile model)
{
if (ModelState.IsValid)
{
using (var context = new dbContext())
{
var id = WebSecurity.CurrentUserId;
var account = context.UserProfiles.Find(id);
UpdateModel(account);
context.SaveChanges();
return RedirectToAction("Index", "Account");
}
}
else
{
return View(model);
}
}
that will always return -1, what you need is the below code
int currentuserid = WebSecurity.GetUserId(username);
You can then validate that the userid above, matches the userid in the model, in order to prevent users, changing other users code
as Additional. I use this in my Base Controller:
public int GetUserId()
{
var userid = "0";
if (Request.IsAuthenticated && User.Identity.Name != null)
{
var membershipUser = Membership.GetUser(User.Identity.Name);
if (membershipUser != null)
{
if (membershipUser.ProviderUserKey != null)
{
userid = membershipUser.ProviderUserKey.ToString();
}
}
}
return Convert.ToInt32(userid);
}

Return View() or PartialView()? How to decide?

I hava an Action:
public ActionResult GetOrders(int id)
{
...
}
When I access it through hyperlink(~/Order/GetOrders/1), I want GetOrder return View(), the whole page.
When through #Html.Action("GetOrders"), I want it return PartialView() to be a part of a page.
Now i settled the problem using Erik Philips's method.
public ActionResult GetOrders(int id)
{
var orders = db.Order.Where(a => a.AdCompanyID == id).ToList();
ViewBag.AdCompanyName = db.AdCompany.Where(a => a.ID == id).Select(a => a.Name).First().ToString();
if (ControllerContext.IsChildAction)
{
ViewBag.isPartial = true;
return PartialView(orders);
}
ViewBag.isPartial = false;
return View(orders);
}
#{Html.RenderAction("GetOrders", new { id = Model.ID });}
#Html.ActionLink("Related orders", "GetOrders", new { id = item.ID })
in GetOrders.cshtml:
#if (ViewBag.isPartial == false)
{
...
}
to generate different view.
Queti M. Porta thanks all the same!
You can use the ControllerContext.IsChildAction.
public ActionResult Foo()
{
if (ControllerContext.IsChildAction)
{
return PartialView("GetOrdersPartial", model);
}
return View("GetOrders", model);
}
Also, I would recommend using Html.RenderAction.
Updated per Comment
I'd also mention that I've never had the need to do this, in my own experience. Either you really have a completely different view, or you are unaware that PartialView will return a view without a Layout.
An easy way would be to pass in a parameter into the action method to let it know how you want the view rendered.
public ActionResult GetOrders(int id, bool? isPartial)
{
return (isPartial.HasValue() && isPartial.Value)
? PartialView()
: View();
}
In the above example, we are passing in the isPartial, however, you can also check to see if the request was done via ajax using Request.IsAjaxRequest
Other than that, there aren't many other ways to determine the method of the request.