Why is my $resource POST resulting in a 404 error? - c#

I have a .Net mobile service API that accepts an Id and a bool. If I call the API from Postman with the correct parameters and headers, it works fine. When I call it from my AngularJs app, I get a 404 error and I cannot figure out why.
My backend API method looks like this:
[HttpPost]
public async Task<IHttpActionResult> SetHoldStatus(string id, bool isHeld)
=> Ok(new
{
Transfer = await _workItemRepository.SetTransferHoldStatus(id, isHeld)
});
My AngularJs controller looks like this:
(function () {
angular
.module("pinnacleWarehouser")
.controller("TransferListCtrl",
["transfers",
"transferWorkItemHoldResource",
TransferListCtrl]);
function TransferListCtrl(transfers, transferWorkItemHoldResource) {
var vm = this;
vm.transfers = transfers;
vm.length = transfers.length;
if (vm.length > 0) {
vm.branch = transfers[0].branchId;
for (var i = 0; i < vm.transfers.length; i++) {
vm.transfers[i].transferId = vm.transfers[i].transferId.trim();
};
}
vm.changeHold = function (transferId, isHeld) {
transferWorkItemHoldResource.save({ Id: transferId, IsHeld: isHeld });
};
}}());
My resource looks like this:
(function () {
"use strict";
angular
.module("common.services")
.factory("transferWorkItemHoldResource",
["$resource", transferWorkItemHoldResource]);
function transferWorkItemHoldResource($resource) {
return $resource("https://my-test-url.net/api/TransferWorkItem/SetHoldStatus", {}, {
save: {
method: 'POST',
headers: { 'ZUMO-API-VERSION': '2.0.0' }
}
});
}}());
So, when I just call the API from Postman, it updates the record with the bool that I send as a parameter. It works.
When I run the app, and call the API, this is what I get:
Looking at the request header in dev tools, I can see that my parameters are in a request payload:
I've never tried using $resource to POST with a custom header and parameters, so I may be missing something. I'm hoping someone can point out what I'm doing wrong.

You should define the action parameter as complex object.
Change it
public async Task<IHttpActionResult> SetHoldStatus(string id, bool isHeld)
to
public async Task<IHttpActionResult> SetHoldStatus(SetHoldStatusInput input)
public class SetHoldStatusInput
{
public string Id { get; set; }
public bool IsHeld { get; set; }
}

Related

Swagger ASP.NET API Multiple OpenAPI Servers

I have an ASP.NET 5 Project with API implemented using Swagger.
I have added multiple OpenAPI Servers within AddSwaggerGen() like following:
services.AddSwaggerGen(options =>
{
for (int i = 0; i < ServersSettings.getSettings().Count; i++)
{
Dictionary<string, string> data = getServers();
if (data.ElementAt(i).Value.DatabaseType == "Server")
{
if (data.ElementAt(i).Value.ApiEnabled == true)
{
options.AddServer(new OpenApiServer() { Url = ("/" + data.ElementAt(i).Key), Description = data.ElementAt(i).Value});
}
}
}
});
And Created an API Controller with a single function to get userdata from database using a tag like this:
[ApiController]
[ApiExplorerSettings(IgnoreApi = false)]
[Route("Api")]
public class ApiController : ControllerBase
{
[HttpGet("Player/{tag}")]
[ProducesResponseType(typeof(UserData), 200)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> GetUserByTag(string tag)
{
UserData userData = await getServerDatabase("openapi server name here").getUserByTag(tag);
if (userData != null)
{
return Ok(userData);
}
return BadRequest();
}
Now the problem I am facing is that on the SwaggerUI I am getting an option to choose from the multiple servers which is great but when I try out the Get /Api/Player/Tag function, the response adds the server key/name before the /Api/ like http://localhost:5000/ServerName/Api/Player/anythinghere and it is unable to get to the function as the controller is expecting http://localhost:5000/Api/Player/anythinghere.
I have tried adding {variables} within the route, input in the GetUserByTag() function but I am unable to figure out how to get the ServerName part into the ApiController.
Swagger UI: https://gyazo.com/3f405a572bfd67b972de4763f0728f0d

Unable to submit data to action method of .net core from angular 5

I am trying to post data from angular 5 component to action method of .net core. I am able to hit the action method but values are null. As per below example Usr.FirstName is null in Sush action method.
Model-
namespace VModels
{
public class UserVM
{
public long UserId { get; set; }
public string FirstName { get; set; }
}
}
Action method of .net core-
[HttpPost]
public IActionResult Sush(UserVM Usr)
{
UserVM objOutput = new UserVM();
CommonGetPostMethod<UserVM, UserVM> objCommonMthd = new CommonGetPostMethod<UserVM, UserVM>();
UserVM objvm = new UserVM();
objvm.FirstName = "Susheel " + DateTime.Now.Ticks.ToString();
objCommonMthd.SaveData(Usr, "https://localhost:44303/api/UserAPI", ref objOutput);
return View(Usr);
}
Post method in angular 5-
SaveUser(userofrm: NgForm) {
var model = userofrm.value;
var values = JSON.stringify(model);
this.hpclient.post<UserVM>("https://localhost:44321/User/Users/Sush", values).subscribe(success => { }, fail => { });
}
Based on the code that you provided, I did a test with the following simple example, which work well on my side, you can refer to it.
// make request with testing data
var model = {'FirstName':'Test'};
var values = JSON.stringify(model);
console.log(values);
this.hpclient.post<UserVM>("https://localhost:44305/api/data/Sush", values, httpOptions).subscribe(success => { console.log(success);}, fail => { });
Define and configure headers for request(s)
import { HttpClient, HttpHeaders } from '#angular/common/http';
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
API controller action
[HttpPost("Sush")]
public IActionResult Sush(UserVM Usr)
{
Usr.UserId = 100;
return Ok(Usr);
}
Test Result
To troubleshoot the issue, you can try to make request with same data from postman etc tool and check if you can get expected data within action method. Or make request with testing data (as I did) rather than value inside userofrm, then check if it can work for you.

Cant pass parameter to API

I'm running a REST API service that has this action :
[HttpPost]
public FooResponse DoFoo(FooRequest request)
//public FooResponse DoFoo([FromBody] FooRequest request)
{
return null;
}
My request:
public class FooRequest
{
public string FooId;
}
I have an Angular client, that's making this call :
startFoo(fooId: string)
{
const url = `${this.baseUrl}StartFoo`;
const params = new HttpParams()
.set('FooId', fooId);
console.log(`params : ${params}`);
const result = this.httpClient.post<fooItem>(url, {params}).toPromise();
return result;
}
When I make the call from PostMan, the FooId is populated, when I call it from Angular, the endpoint is hit, but the param is always null. When I look in the console log, the parameters is there.
I've tried this solution, but it did not resolve my issue.
What am I missing?
You should add [FromBody] attribute in method .
[HttpPost]
public FooResponse DoFoo([FromBody] FooRequest request)
{
return null;
}
While you send the request to api, your request body must be in json format.
var fooRequest = { FooId : 1};
const result = this.httpClient.post<fooItem>(url, JSON.stringify(fooRequest) ).toPromise();
I did not try, I guess that It will work.

How to send new/updated data to all clients on SignalR for NET Core 2.2

I'm not too familiar with signalr2 on asp.net-core pardon me, am trying to create a POC on how to implement a real-time CRUD application with admin and client using signalr2, but am having issues with signalr data push, I keep getting NullReferenceException: Object reference not set to an instance of an object. on this line await Clients.All.SendAsync("BroadcastData", data);
Below is how I setup my Hub using some online examples I looked-up:
public class OddPublisher : Hub
{
private readonly IOddServices _oddService;
public OddPublisher(IOddServices oddService)
{
_oddService = oddService;
}
public async Task BroadcastData()
{
var data = _oddService.ClientQueryOdds();
await Clients.All.SendAsync("BroadcastData", data); //breaks here
}
}
and this is triggered by admin, on submiting and saving the data sucessfully I call the BroadcastData()
public class BaseController : Controller
{
public IOddServices _oddService;
public readonly OddPublisher _publisher;
public BaseController(IOddServices oddService, )
{
_oddService = oddService;
_teamService = teamService;
_publisher = new OddPublisher(oddService);
}
[HttpPost]
public async Task<IActionResult> odd_entry(CreateOdd dto)
{
//somecode here...
var results = _validator.Validate(dto);
if(!results.IsValid)
{
results.AddToModelState(ModelState, null);
return View(dto);
}
_oddService.CreateOddAndTeam(dto);
await _publisher.BroadcastData(); //Breaks
return RedirectToAction(nameof(index));
}
}
Folled all the instructions as adviced in Microsoft Asp.Net Core Signalr Documentation, my Startup has all required sevices added.
here is the client and the JS file,
"use strict";
var connection = new signalR.HubConnectionBuilder().withUrl("/oddPublisher").build();
connection.on("BroadcastData", data => {
console.table(data);
//getAll();
})
connection.start().then(function () {
getAll();
}).catch(function (err) {
return console.error(err.toString());
});
function getAll() {
var model = $('#dataModel');
$.ajax({
url: '/home/GetLatestOddData',
contentType: 'application/html ; charset:utf-8',
type: 'GET',
dataType: 'html',
success: function (result) { model.empty().append(result); }
});
}
Need some help here guys, I still don't know what am doing wrong, I'll really appreciate if I can get any help on this.
Thank you in advance.
It turns out I needed to Inject the IHubContext into my hubs to have access to the clients.

WebApi - The requested resource does not support http method 'GET'

Question Background:
I have a basic WebApi project hosted as a WebApp in Azure.
The Issue:
The problem I have is If I access any method other than a 'GET' type then I'm receiving the following error in my JSON response:
The requested resource does not support http method 'GET'
The Code:
The following code is how the project currently is.
RouteConfig.cs class:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Home",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
The ValuesController controller class:
public class ValuesController : ApiController
{
private List<CompanyData> _company;
public ValuesController()
{
_company = new List<CompanyData>
{
new CompanyData
{
CompanyName = "SmallTech.Ltd",
CompanyOwner = "John Smith",
CompanyIndustry = "Electronic Components",
EmployeeNo = "3"
}
};
}
public List<CompanyData> GetCompanyData()
{
return _company;
}
//GET api/values
public IEnumerable<string> Get()
{
return new string[] { "Test GET Method"};
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
public void Post(string value)
{
string test = value;
}
// PUT api/values/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
[HttpDelete]
public void Delete(int id)
{
}
An example of calling the above Delete method when the error occurs is:
http://testwebapisite.azurewebsites.net/api/values/Delete/5
I have read other people having the same issue and using the HTTP attributes from the System.Net.MVC. I can confirm I'm not using this and am using `System.Net.Http.HttpPostAttribute.
Any help working out why I'm receiving the GET error message would be great.
You are trying to access an action which clearly specifies delete as its verb via a GET request.
By default the browser will do a GET request if you paste a url so thats pretty much easy to test but for the other verbs you'll have to use an actual rest/http client to specify the verb. You can use Postman or Rest Console if you use chrome to dev/test
In addition to those tools, you might want to have fiddler installed .. it will help you track all http activity (both sent/received) you'll know exactly what you are sending and receiving from the wire
You could also do this from code if you want using HttpClient.
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://testwebapisite.azurewebsites.net/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.DeleteAsync("api/values/5");
}
You haven't shown the code that you are using to invoke the API, but I suspect you are not using the DELETE HTTP verb. The resource you are accessing has URI or http://testwebapisite.azurewebsites.net/api/values/5 - note the action name is not specified. Rather, as the comment of your method suggests, you should be using the DELETE HTTP verb. Example:
using (var client = new HttpClient())
await client.DeleteAsync("http://testwebapisite.azurewebsites.net/api/values/5");

Categories

Resources