HttpPut Request in C# - c#

I'm fairly new to this Web API stuff and I'm trying to set up simple http requests to a local database on my computer. I have a get request that looks like this:
[HttpGet]
[Route("")]
[Route("{ID:int}")]
public IQueryable<ListTable> Get(int id = -1)
{
if(id == -1)
return db.ListTables;
else
return db.ListTables.Where(lt => lt.ID == id);
}
This just returns all items in the database or one item relating to the specified ID. Now I'm trying to make a put request where I can add a new item to the database or edit item related to a certain ID. I was trying something like this:
[HttpPut]
[Route("{ID:int}")]
[Route("{ID:int}/{TITLE:string}")]
[Route("{ID:int}/{TITLE:string}/{DESCRIPTION:string}")]
public ListTable Put(int id = -1, string title = null, string descr = null)
{
//if ID == -1 add a new item to the DB
//else add title and description to the item with the specified ID
}
I am a little unsure of how to add a new item to the database and save the changes. I tried something like db.ListTables.Add(new ListTable()) and db.SaveChanges() but those didn't seem to actually save anything because when I called the Get() method again the new item wasn't there.

You will need to new up an instance of the entity to add [ListTable] and then add it to your database context (assuming it's db based on your GET example. Once you add it to the context, then you .SaveChanges() - I'm assuming your ListTable entity has columns called Title and Description (change those lines to whatever you have them named):
ListTable listTableToAdd = new ListTable()
{
Title = title,
Description = descr
}
db.ListTables.Add(listTableToAdd);
db.SaveChanges();

You need to set the properties after new ListTable(). Something like new ListTable() { Title = title, ... }

Related

How to use a Generic Parameter in Web Api Method

I want to have one API Endpoint that allow me to perform multiple operations with a generic input. for instance, i want to delete an employee either by ID or BY name. Just by changing parameter.
what i have tried is using the OR operator (||):
public int DeleteBusinessStream(int id, string name)
{
var deleteBusinessStream = this.dbcontext.BusinessStreams.FirstOrDefault(p => p.BusinessStreamId == id || p.BusinessStreamName == name);
if(deleteBusinessStream == null)
{
return 1;
}
else
{
this.dbcontext.BusinessStreams.Remove(deleteBusinessStream);
this.dbcontext.SaveChanges();
return 0;
}
}
Controller
[HttpDelete]
[Route("deletebusinessstream")]
public ActionResult deleteBusinessStream(int id, string name)
{
PostMessage pm = new PostMessage();
int returnedValue = this.jobsApi.DeleteBusinessStream(id, name);
if(returnedValue == 1)
{
pm.error = true;
pm.message = "Delete Business Stream was not successful!!";
}
else
{
pm.error = false;
pm.message = "Delete Business Stream was successful";
var deleteStream = this.jobsApi.DeleteBusinessStream(id, name);
}
return Ok(pm);
}
This works well but it requires input two parameter values ( id and name ) i want to be able to use one to switch and perform delete based on any one i choose like
https://localhost:7190/api/Employer/deletebusinessstream?id=111
or
https://localhost:7190/api/Employer/deletebusinessstream?name=ICT
instead of passing both at the same time
You can make both parameters optional like this in your Web API Action
public ActionResult deleteBusinessStream(int id = 0, string name = null)
And later check in code if the id is 0, then use the name to delete and vice-versa i.e if the name is null use id to delete the records
Also, you cannot restrict user from passing both parameters in the request so you need to handle that request separately and return BadRequest maybe
This way you can call your endpoint with either of the URLs
https://localhost:7190/api/Employer/deletebusinessstream?id=111
https://localhost:7190/api/Employer/deletebusinessstream?name=ICT
Although I would say that Name will not be a unique identifier for a record, so I suggest you take a dig and check whether you actually want to delete the record using the name

MVC ASP - Stopping edit function from modifying fields to NULL

So I'm trying to update ONLY specific data in my MVC application. Whenever I only edit a list view, I would edit the data (which works) but the rest of the database table would be NULL.
So for example -
Fields in List View
EmployeeID, FirsName, LastName, Email, Moderator, Admin
Fields not in list view
LoginID
So in my edit page, I have set up read-only for the info like EmployeeID, FirstName, LastName, and Email with two checkboxes for Moderator and Admin which are the only values I want to edit.
They work fine but when doing so, the data in the database for LoginID only becomes NULL.
Here is the code from my edit GET and POST methods
GET
public ActionResult Edit(int id)
{
EmpContext ec = new AppContext();
Employee e = ec.Employees.Single(x => x.Id == id);
return View();
}
POST
public ActionResult Edit(Employee employee)
{
if (ModelState.IsValid)
{
EmpContext ec = new EmpContext();
ec.Entry(employee).State = EntityState.Modified;
ec.SaveChanges();
return RedirectToAction("List");
}
return View(employee);
}
So, how would I stop this executing in the field LoginID within the database when there are no text boxes at all for LoginID, even on the edit page?
According to Attaching an existing but modified entity to the context
When you change the state to Modified all the properties of the entity
will be marked as modified and all the property values will be sent to
the database when SaveChanges is called.
Thus, this Entry method will update all the properties. For my recommendation, to update some Entity's columns only, you have to manually query the record and update desired properties only.
In your Edit (POST) method, change the Entry() way to:
EmpContext ec = new EmpContext();
Employee _employee = ec.Employees.Single(x => x.Id == employee.Id);
// TO-DO Update required properties only
_employee.FirstName = employee.FirstName;
ec.SaveChanges();

ASP.NET MVC Attribute-Routing with Null Values

Here is a paste of the action method MovieCustomer in the EverythingController.
The Viewmodel is used to Combine two Models: Customer & Movies, and is populated with information from the Database via the ApplicationDbContext (_context).
The Routeing works successfully and renders the page when there are values for MovieId and CustomerId
e.g. /Everything/MovieCustomer/1/1
I want the page to also load if one or both of the values are null. So far both of the int parameters were made nullable and there is an if statement in the method to change the parameters to 1 if either is null.
So far if the values are null the browser returns a 404 error.
How can I get the page to function when one or either of the parameters are null? Thanks
[Route("Everything/MovieCustomer/{movieId}/{customerId}")]
public ActionResult MovieCustomer(int? movieId, int? customerId)
{
var viewmodel = new ComboViewModel
{
_Customers = new List<Customer>(),
_Movies = new List<Movies>(),
_customer = new Customer(),
_movie = new Movies()
};
viewmodel._Customers = _context.Customers.ToList();
viewmodel._Movies = _context.Movies.ToList();
if (!movieId.HasValue)
movieId = 1;
if (!customerId.HasValue)
customerId = 1;
viewmodel._customer = viewmodel._Customers.SingleOrDefault(a => a.Id == customerId);
viewmodel._movie = viewmodel._Movies.SingleOrDefault(a => a.Id == movieId);
return View(viewmodel);
}
You can achieve this using separate routes, or change your parameters to be optional.
When using 3 attributes, you add separate routes for each of the options that you have - when no parameters are specified, when only movieId is specified, and when all 3 parameters are specified.
[Route("Everything/MovieCustomer/")]
[Route("Everything/MovieCustomer/{movieId}")]
[Route("Everything/MovieCustomer/{movieId}/{customerId}")]
public ActionResult MovieCustomer(int? movieId, int? customerId)
{
// the rest of the code
}
Alternatively you an combine change your route parameters to optional (by adding ? in route definition) and this should cover all 3 cases that you have:
[Route("Everything/MovieCustomer/{movieId?}/{customerId?}")]
public ActionResult MovieCustomer(int? movieId, int? customerId)
{
// the rest of the code
}
Keep in mind that neither sample supports the case where you provide only customerId.
Keep in mind that neither sample supports the case where you provide only customerId.
Check it out. I think you can use the multiple route method with EVEN ANOTHER route like this if you do want to provide only customerId:
[Route("Everything/MovieCustomer/null/{customerId}")]
Interstingly, I had to add optional parameter to the signature as well for it to work from Angular client like so:
[HttpGet]
[Route("IsFooBar/{movieId?}/{customerId?}")]
[Route("IsFooBar/null/{customerId?}")]
public bool IsFooBar(int? movieId = null, int? customerId = null)
{
// the rest of the code
}
In Angular
public IsFoobar(movieId: number | null, customerId: number | null): Observable<boolean> {
return this.httpService.get<boolean>(`api/IsFooBar/${movieId}/${customerId}`);
}

In 3 level JqGrid, get the first table's primary key when the 2nd table's "+" sign is pressed

I am new to JqGrid and please help me with this request.
I have a 3 level hierarchical JqGrid setting as shown in the link. It is not exactly the same, but very similar. My requirement is to have the CustomerGrid's primary key also passed when OrderGrid is expanded.
Or in short, I would like to have
public void SetUpThreeLevelGrids(ThreeLevelHierarchyJqGridModel model)
{
var customersGrid = model.CustomersGrid;
// code here
int cId;
//cId = <CustomerId from the CustomerGrid>; //*****How to get this******
ordersGrid.DataUrl = Url.Action("ThreeLevel_OrdersDataRequested", new { customerId = cId });
// code here
}
I would like to use that variable passed to the ThreeLevel_OrderDetailsDataRequested method:
public JsonResult ThreeLevel_OrderDetailsDataRequested(int customerId, string parentRowID)
{
// code here
}
I created a static variable named CustomerId in my Controller. I do not know whether this can break anything or not. I just wanted to make it work.
public static int customerId = 0;
In the Action method for the second grid, I assigned the CustomerId value.
public JsonResult ThreeLevel_OrdersDataRequested(string parentRowID)
{
var northWindModel = new NorthwindDataContext();
var model = new ThreeLevelHierarchyJqGridModel();
customerId = int.Parse(parentRowID);
SetUpThreeLevelGrids(model);
//code
}
Accessed the global static variable in the third level grid.
public JsonResult ThreeLevel_OrderDetailsDataRequested(string parentRowID)
{
//Code
var orderDetails = from o in myDbModel.MyCustomerOrderDetails
where o.OrderID == Convert.ToInt32(parentRowID)
and o.CustomerId == customerId //static global variable
select o;
//Code
}
If anyone has a better suggestion to get the 1st level table's selected primary key in the third level grid, please let me know.

How to check existing record field and compare with post data before change ?

I am very new to MVC and hope someone can assist me.
I have a controller method to save post back data from a form. It has a field called OrderStatus. If the order status value is "Received" then only I want to execute a block of code.
What I am doing in this code is, read the post values and read the EF data again using Find and compare the values. All seems ok but when I try to save the record, it gives me below error.
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
I do understand the problem but how can I check the existing values in the database and compare and save.
My code is below
// POST: /Purchasing/Edit/5
[HttpPost]
public ActionResult Edit(PurchaseMaster purchasemaster)
{
if (ModelState.IsValid)
{
if (purchasemaster.OrderStatus == "Received")
{
string myId = purchasemaster.PurchaseId;
//check if the existing status is already set as Received or not
PurchaseMaster pm = db.PurchaseMasters.Find(myId);
if (pm.OrderStatus != "Received") //this will prevent duplicate stock updates
{
//load the items and loop through to update the stock
List<PurchaseDetail> purchasedetails = db.PurchaseDetails.Where(x => x.PurchaseId == myId).ToList();
foreach (PurchaseDetail singleitem in purchasedetails)
{
string itemcode = singleitem.ItemCode;
Item item = db.Items.Find(itemcode);
item.QtyInHand = item.QtyInHand + singleitem.Quantity;
db.Entry(item).State = EntityState.Modified;
db.SaveChanges();
}
}
}
db.Entry(purchasemaster).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(purchasemaster);
}
Try this it should work
//don't get this object from database
//PurchaseMaster pm = db.PurchaseMasters.Find(myId);
if (db.PurchaseMasters.Any(x =>x.Id == myId && x.OrderStatus != "Received") {
// Do your stuff
}

Categories

Resources