API only returns responses with no content - c#

My methods only return responses with no content.
Controller
[HttpGet("Floors/{floorId}", Name = "FloorById")]
public IActionResult GetFloor(int floorId)
{
try
{
Floor floor = _repository.Floor.GetFloor(floorId);
if (floor == null)
return NotFound();
return Ok(floor);
}
catch (Exception e)
{
return StatusCode(500, "text");
}
}
Repository
public Floor GetFloor(int floorId)
{
return _context.Floors.FirstOrDefault(f => f.Id == floorId);
}
Ideally, this code should return an Ok response with the object as well.
Instead, I only get an Ok response when using swagger. Not even the NotFound.

Swagger is unable to determine what type the action returns based on the IActionResult.
Use the ProducesResponseType attribute:
[ProducesResponseType(typeof(Floor), 200)] // <-- THIS
[HttpGet("Floors/{floorId}", Name = "FloorById")]
public IActionResult GetFloor(int floorId) {
try {
Floor floor = _repository.Floor.GetFloor(floorId);
if (floor == null)
return NotFound();
return Ok(floor);
} catch (Exception e) {
return StatusCode(500, "text");
}
}

Related

What does it mean by catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))?

What does the below code block mean:
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
Full sample:
// PUT: api/TodoItems/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPut("{id}")]
public async Task<IActionResult> UpdateTodoItem(long id, TodoItemDTO todoItemDTO)
{
if (id != todoItemDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoItemDTO.Name;
todoItem.IsComplete = todoItemDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
This is called an exception filter clause. It is normally used like this:
// without exception filters:
try
{
var file = new StreamReader(myInputStream);
// ....
}
catch (IOException x)
{
// Handle error
}
catch (UnauthorizedAccessException x)
{
// Handle error (same as above)
}
catch (SocketException x)
{
// Handle error (again, same as above)
}
// etc., etc...
// Instead, one can write
try
{
var file = new StreamReader(myInputStream);
// ....
}
catch (Exception x) when (x is SocketException || x is UnauthorizedAccessException || x is IOException)
{
// Handle all expected exception types in one handler
}
I have never seen it being used as in your example. And I'm not sure it is used correctly. What it does is that it only enters the catch clause when TodoItemsExists returns false. That means, on the other hand, that if a DbUpdateConcurrencyException is thrown and TodoItemsExists returns true, the catch handler is not invoked and the exception falls trough, eventually crashing the server task.
I'm not sure about the actual requirement, but I think the following is intented instead:
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
}
return NoContent();
So this will return the appropriate error message to the caller (either NotFound() or NoContent()) when the exception is thrown.
The condition in the when clause can be used to do an additional test whether the handler should be invoked.

C# - Method does not contain a definition for an object

I have this block of code:
[HttpDelete("{id}")]
public async Task<IActionResult> Delete([FromBody] MonitorsDeleteRequest request)
{
if (request == null)
{
return BadRequest("Request could not be parsed.");
}
if (request.MonitorId == Guid.Empty)
{
return BadRequest("Query Monitor Id is required.");
}
try
{
await monitoringService.RemoveMonitorAsync(
new RemoveMonitorRequest()
{
MonitorId = new MonitorId(request.MonitorId)
});
return Accepted();
}
catch (Exception ex)
{
logger.LogError($"[{Request.Path.Value}]: {ex.ToString()}");
return StatusCode(500, ex.Message);
}
}
The MonitorId that is inside the RemoveMonitorRequest method (on the left of the equal sign) is underlined in red - Intellisense says "RemoveMonitorRequest does not contain a definition for MonitorId."
Just FYI, the other MonitorId earlier in the code has no Intellisense error.
What can I do to remedy this?

Can't access to my method delete of my api rest

I'm not able to access to my delete method of my api rest.
If i write the method like this it work:
[Route("api/Document/{documentId:int}")]
[HttpDelete]
public IHttpActionResult Delete([FromUri]int documentId,[FromBody] int [] documentsId)
{
try
{
documentCtrl = documentCtrl ?? new DocumentCtrl();
return Ok(documentCtrl.Delete(documentsId));
}
catch (DocumentNotFoundException)
{
return NotFound();
}
catch (Exception)
{
return InternalServerError();
}
}
It works, but if i put:
[Route("api/Document/MassiveDelete")]
[HttpDelete]
public IHttpActionResult MassiveDelete([FromBody] int[] ids)
{
try
{
documentCtrl = documentCtrl ?? new DocumentCtrl();
return Ok(documentCtrl.MassiveDelete(ids));
}
catch (DocumentNotFoundException)
{
return NotFound();
}
catch (Exception)
{
return InternalServerError();
}
}
I don't have acces, any ideas what could it be?
This is my request code:
DeleteDocument(id: number): Observable<boolean> {
return this._httpService.delete(AppModule.service + 'Document/' + id, AppModule.options)
.map((response: Response) => <boolean>response.json())
.catch(this.handleError);
}//This work if i want to delete one
DeleteDocuments2(ids:Array<number>):Observable<boolean>{
AppModule.options.body=ids;
return this._httpService.delete(AppModule.service + 'Document/MassiveDelete', AppModule.options)
.map((response: Response) => <boolean>response.json())
.catch(this.handleError);
}
You cannot send two parameters in your Api, you need to createa custom class like follow and send as follows,
MyCustomRequest {
public int[] documentIds;
public int documentId;
}
and then,
public IHttpActionResult MassiveDelete([FromBody] MyCustomRequest request)
you can access it as,
request.documentIds;
request.documentId;

How to correctly use optional route parameters in this controller to simplify it?

I have a controller that is made with ASP.NET and I really want to simplify that thing with quick view:
// REST representation of Storage
// There is always at least two options to view them
// Data as is or Quick view at metrics averages
[Route("metrics")]
public class MetricsController : Controller
{
// Get raw Storage object
[HttpGet]
public IActionResult GetStorageView()
{
// TODO: do not use in production
WSManModule.HyperVMetric.test(false);
//
var response = MetricsService.Instance.GetRawMetrics();
if (response == null)
{
return NotFound();
}
if (Request.QueryString.Value == "?q=quick")
{
return Ok(new StorageQuickView(response));
}
return Ok(response);
}
// Get metrics for specific device
[HttpGet("{deviceName}")]
public IActionResult GetDeviceView(string deviceName)
{
var response = MetricsService.Instance.GetDeviceMetrics(deviceName);
if (response == null)
{
return NotFound();
}
if (Request.QueryString.Value == "?q=quick")
{
return Ok(new DeviceQuickView(response));
}
return Ok(response);
}
// Get metrics for specific component within the device
[HttpGet("{deviceName}/{componentName}")]
public IActionResult GetComponentView(string deviceName, string componentName)
{
var response = MetricsService.Instance.GetComponentMetrics(deviceName, componentName);
if (response == null)
{
return NotFound();
}
if (Request.QueryString.Value == "?q=quick")
{
return Ok(new ComponentQuickView(response));
}
return Ok(response);
}
}
now it does have a lot of repetition and I don't like it.
Is there any way to do it right with optional parameters like {quick?} or something similar?
Simply: I want to perform different operations if we have /quick at the end of the route or no.
Just accept the q parameter with your actions:
// Get raw Storage object
[HttpGet]
public IActionResult GetStorageView(string q)
{
// TODO: do not use in production
WSManModule.HyperVMetric.test(false);
//
var response = MetricsService.Instance.GetRawMetrics();
if (response == null)
{
return NotFound();
}
if (q == "quick")
{
return Ok(new StorageQuickView(response));
}
return Ok(response);
}
// Get metrics for specific device
[HttpGet("{deviceName}")]
public IActionResult GetDeviceView(string deviceName, string q)
{
var response = MetricsService.Instance.GetDeviceMetrics(deviceName);
if (response == null)
{
return NotFound();
}
if (q == "quick")
{
return Ok(new DeviceQuickView(response));
}
return Ok(response);
}
The action method parameters are not just derived from routes. The values come from Value Providers, and one of the default providers parses the query string. So, you only need to add the query string value to your action method parameters rather than parsing or comparing the query string manually.
you can create a private method like this:
private IAction ProcessResponse<T>(IMyResponseType response)
{
if(response == null)
{
return NotFound();
}
if (Request.QueryString.Value == "?q=quick")
{
var okInstance = (T) Activator.CreateInstance(typeof (T), response);
return Ok(okInstance);
}
return Ok(response);
}
and use it like this:
// Get metrics for specific component within the device
[HttpGet("{deviceName}/{componentName}")]
public IActionResult GetComponentView(string deviceName, string componentName)
{
var response = MetricsService.Instance.GetComponentMetrics(deviceName, componentName);
return ProcessResponse<ComponentQuickView>(response);
}
// Get raw Storage object
[HttpGet]
public IActionResult GetStorageView()
{
// TODO: do not use in production
WSManModule.HyperVMetric.test(false);
//
var response = MetricsService.Instance.GetRawMetrics();
return ProcessResponse<StorageQuickView>(response);
}

How to redirect to action mvc

I am creating an ASP.NET MVC app and I would like it so when an error occurs I call another action which loads a different view.
public ActionResult Invoices()
{
invoiceClass invoice = getInvoice();
//do stuff with invoice
}
public invoiceClass getInvoice()
{
invoiceClass invoice = new invoiceClass();
try
{
// Do stuff
}
catch(exception e)
{
return RedirectToAction("Index");
}
return invoice;
}
I have a method that is very similar to this, when I step through the code, the exception is caught and it hits the redirect call then goes to the return and continues without redirecting. Am I missing something obvious?
If this is an HTTP entry point, you should be returning an ActionResult.
public ActionResult stuff()
{
try
{
// Do stuff
}
catch (Exception e)
{
//Return a RedirectResult
return RedirectToAction("Index");
}
//Return a JsonResult
//Example: return the JSON data { "number": 1 }
return Json(new { number = 1 });
}
Edit
Here is how I would address your question given the edits you just made.
public ActionResult Invoices()
{
try
{
invoiceClass invoice = getInvoice();
//do stuff with invoice
return Json(...);
}
catch
{
//Catch the exception at the top level
return RedirectToAction("Index");
}
}
public invoiceClass getInvoice()
{
invoiceClass invoice = new invoiceClass();
// Do stuff; possibly throw exception if something goes wrong
return invoice;
}
you are missing a return
return RedirectToAction("Index");
And don't forget to change your return type to ActionResult
So Ive managed to find a solution to this problem however I'm certain there will be a better more efficient way.
public ActionResult Invoices()
{
try{
invoiceClass invoice = getInvoice();
//do stuff with invoice
}catch (exception e){
return RedirectToAction("Index");
}
}
public invoiceClass getInvoice()
{
invoiceClass invoice = new invoiceClass();
try
{
// Do stuff
}
catch(exception e)
{
index(); //<--the action result
}
return invoice;
}
calling index() runs through the method then throws an exception in the Invoices() method which then redirects.

Categories

Resources