Method not found in Web API 2 - c#

Im trying to figure out how to use Web API. I have gone through some tutorials and now Im trying to set up my web service.
I have a really hard time trying to figure out why it cant find my methods. To me it just seems like random (the tutorials worked fine).
During my experiments sometimes the get method returns "method not allowed".
This is my service:
public class ContentFilesController : ApiController
{
[Route("api/contentfile/{id}")]
[HttpGet]
public IHttpActionResult GetContentFiles(int count)
{
if (_contentFiles == null)
GenerateContentFileList();
List<ContentFile> files = new List<ContentFile>();
int i = 0;
while(true)
{
ContentFile cf = _contentFiles[i];
if(!_filesOutForProcessing.Contains(cf))
{
files.Add(cf);
i++;
}
if (i == count)
break;
}
return Ok(files);
}
[HttpPost]
[Route("api/contentfile/{files}")]
public IHttpActionResult Post([FromBody] List<ContentFile> files)
{
return Ok();
}
}
Edit:
This is the code I am using to call the service:
static async Task TestAsync() {
using (var client = new HttpClient()) {
client.BaseAddress = new Uri("http://localhost:46015/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("api/contentfile/1");
if (response.IsSuccessStatusCode)
{
var contentfiles = await response.Content.ReadAsAsync<List<ContentFile>>();
}
}
}
static async Task ReportTest()
{
List<ContentFile> files = new List<ContentFile>()
{
new ContentFile(){Path="hej"},
new ContentFile(){Path="då"}
};
using(var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:46015");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.PostAsJsonAsync<List<ContentFile>>("api/contentfile", files);
if(response.IsSuccessStatusCode)
{
}
}
}
Where do you start looking?
Im going crazy here.
Thanks!
Edit: to clarify the error, the problem with both client methods are that the HttpResponseMessage has response.IsSuccessStatusCode false and the StatusCode = MethodNotAllowed or MethodNotFound.

Problems with the GET method
For the HTTP Get method, there is a problem with your routing.
You have declared the GET route as this:
[Route("api/contentfile/{id}")]
but then the method parameter is declared as this:
public IHttpActionResult GetContentFiles(int count)
When using Attribute-based routing, the parameter names have to match.
I made a very simple reproduction of your code (obviously I don't have your classes but the infrastructure will be the same)
In the WebAPI project
public class ContentFile
{
public int ID { get; set; }
}
public class ContentFilesController : ApiController
{
[Route("api/contentfile/{count}")] //this one works
[Route("api/contentfile/{id}")] //this one does not work
[HttpGet]
public IHttpActionResult GetContentFiles(int count)
{
var files = new List<ContentFile>();
for (int x = 0; x < count; x++)
{
files.Add(new ContentFile(){ID=x});
}
return Ok(files);
}
}
In the client project
public class ContentFile
{
public int ID { get; set; }
}
class Program
{
static void Main(string[] args)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:51518/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync("api/contentfile/1").Result;
var data = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(data);
Console.ReadKey();
}
}
}
So the code is not quite identical to yours but it's pretty much the same code. Running the WebAPI project and then the client gives me:
[{"ID":0}]
Problems with the POST method
In the case of the POST method, you are declaring a route parameter, but this is never sent as part of the route, it's a POST body:
[HttpPost]
[Route("api/contentfile/{files}")] //{files} here tells routing to look for a parameter in the *Route* e.g api/contentfile/something
public IHttpActionResult Post([FromBody] List<ContentFile> files)
So the simple fix is to remove {files} from the Route template for this one.
Hope this helps.

Related

API POST call from Console Application

How to do the REST API POST Call from the console Application ?
I want to pass the class from the Console application to the REST API. My below code is working if I have to do the GET call but not for the POST. It is hitting the API but in the Parameter it is not passing anything.
API
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
//public void Post([FromBody]string value)
//{
//}
public void Post([FromBody]Student value)
{
}
}
Console Application
static async Task CallWebAPIAsync()
{
var student = new Student() { Id = 1, Name = "Steve" };
using (var client = new HttpClient())
{
//Send HTTP requests from here.
client.BaseAddress = new Uri("http://localhost:58847/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.PostAsJsonAsync("api/values", student);
if (response.IsSuccessStatusCode)
{
}
else
{
Console.WriteLine("Internal server Error");
}
}
}
The Same is working if I call from fiddler.
User-Agent: Fiddler
Content-Length: 31
Host: localhost:58847
Content-Type: application/json
Request Body:
{
"Id":"1",
"Name":"Rohit"
}
This is working for me.
public async Task CallWebAPIAsync()
{
var student = "{'Id':'1','Name':'Steve'}";
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:58847/");
var response = await client.PostAsync("api/values", new StringContent(student, Encoding.UTF8, "application/json"));
if (response != null)
{
Console.WriteLine(response.ToString());
}
}
You are not serializing the student object.
You can try to send a StringContent
StringContent sc = new StringContent(Student)
HttpResponseMessage response = await client.PostAsJsonAsync("api/values", sc);
if this doesn't work (a long time I used StringContent).
Use NewtonSoft sterilizer
string output = JsonConvert.SerializeObject(product);
HttpResponseMessage response = await client.PostAsJsonAsync("api/values", output);
To be honest I don't know. It seems like your StringContent did not sterilize it to UTF8 which your restful API is trying to do by default. However, your console application should also do that by default.
The issue seemed to be that the restful API could not bind the byte data and therefor not assign the data to your class Student in the restful API.
What you can try to do is add following code before you make your post to API:
var encoding = System.Text.Encoding.Default;
It will tell you what is your default encoding type. It could be that UTF8 is not the default encoding for some reason.

Error while returning HttpResponseMessage in.NET core

I have a simple API gateway controller which returns an IActionResult. The issue is I am not able to read the body of the response.
If I comment out the using block in ExecuteResultAsync it seems to work fine but there is not content/body.
Not sure how to get this working with the httpbody being returned. RouteRequest returning HttpResponseMessage is not an option as it puts the response from the microservice as the body of the response from the Gateway.
So I need to use the HttpResponseMessageResult middleware, which works as expected for headers but not for the body.
public async Task<IActionResult> RouteRequest()
{
// Calls a method which send a request and gets a response and constructs a HttpResponseMessage
_contextAccessor.HttpContext.Response.RegisterForDispose(response);
return new HttpResponseMessageResult(response);
}
public class HttpResponseMessageResult : IActionResult
{
private readonly HttpResponseMessage _responseMessage;
public HttpResponseMessageResult(HttpResponseMessage responseMessage)
{
_responseMessage = responseMessage;
}
public async Task ExecuteResultAsync(ActionContext context)
{
context.HttpContext.Response.StatusCode = (int)_responseMessage.StatusCode;
var responseMessageHeadersArray = _responseMessage.Headers.ToArray();
for (int i = 0; i < responseMessageHeadersArray.Length; i++)
{
var header = responseMessageHeadersArray[i];
context.HttpContext.Response.Headers.TryAdd(header.Key, new StringValues(header.Value.ToArray()));
}
using (var stream = await _responseMessage.Content.ReadAsStreamAsync())
{
await stream.CopyToAsync(context.HttpContext.Response.Body);
await context.HttpContext.Response.Body.FlushAsync();
}
}
}
Try this out, based on this good answer to a similar question, I used the ObjectResult class instead of manually manipulating the streams. When I run it with response from one of our API's (JSON), I get the same amount of data in the body of objectResult when it calls ExecuteAsync as were in the initial response.
public class HttpResponseMessageResult : IActionResult
{
private readonly HttpResponseMessage _responseMessage;
public HttpResponseMessageResult(HttpResponseMessage responseMessage)
{
_responseMessage = responseMessage;
}
public async Task ExecuteResultAsync(ActionContext context)
{
var objectResult = new ObjectResult(await _responseMessage.Content.ReadAsStreamAsync())
{StatusCode = (int)_responseMessage.StatusCode};
foreach (KeyValuePair<string, IEnumerable<string>> h in _responseMessage.Headers)
{
context.HttpContext.Response.Headers.TryAdd(h.Key, string.Join("", h.Value));
}
await objectResult.ExecuteResultAsync(context);
}
}

c# asp.net website calling a webApi

I meet a problem because of my inexperience managing Threads.
I have this Action bellow :
public static async Task<joueurs> loadjoueurs(int id)
{
joueurs EmpInfo = new joueurs();
using (var client = new HttpClient())
{
//Passing service base url
client.BaseAddress = new Uri("http://www.myWebApi.fr/api/");
client.DefaultRequestHeaders.Clear();
//Define request data format
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Sending request to find web api REST service resource GetAllEmployees using HttpClient
HttpResponseMessage Res = await client.GetAsync("joueurs?id=" + id);
//Checking the response is successful or not which is sent using HttpClient
if (Res.IsSuccessStatusCode)
{
//Storing the response details recieved from web api
var EmpResponse = Res.Content.ReadAsStringAsync().Result;
//Deserializing the response recieved from web api and storing into the Employee list
EmpInfo = JsonConvert.DeserializeObject<joueurs>(EmpResponse);
return EmpInfo;
}
return null;
}
it s just client to get my data from a webApi (no ssl no authentication, when I test it I receive the right values)
but when I make a call using the function above (in my asp.net website) .... it stay stucked at the HttpResponseMessage = await .... eternally.
In my webApi I have two functions same name but different parameters .
public async Task<IHttpActionResult> Getjoueur(int iduser, int idsport)
and
public async Task<IHttpActionResult> Getjoueur(int id)
So I am don't know where the problem comes from.
(sequel) Here is the place where I call the Task :
public SuperModel(int id)
{
this.joueur = Repojoueurs.loadjoueurs(id).Result;
/* this.classificationSport = Repoclassificationsport.loadclassificationsport().Result;
...
*/
}
And then my Supermodel is instantiated here in my Home controller :
public ActionResult Index(int id)
{
SuperModel superModel = new SuperModel(id);
return View(superModel);
}
Can you try not to use the async and wait. Around three changes like below
public static HttpResponseMessage loadjoueurs(int id)
{
HttpResponseMessage Res = client.GetAsync("joueurs?id=" + id);
return Request.CreateResponse(HttpStatusCode.OK,EmpInfo, "application/json");
}

Modify List<T> object to work with method that receives <T> or viceversa in C#

I need some suggestion on how to fix my code. I'm working on some existing project which has a bunch of dependencies, so the less I have to modify, the better. In this case, my controller needs BuildingReportModel as LIST, and at the end this controller returns this list to some view. My issue is when I try to call GetWSObject which receives a model/class, no a LIST. How would be the best way or best practices to make this code work? BuildingReportModel needs to be declare as List<> since I have some previous validation that can't be changed. Any suggestions?
List<BuildingReportModel> rc = new List<BuildingReportModel>();
BuildingWSObjects ws = new BuildingWSObjects();
rc = await ws.GetWSObject<BuildingReportModel>("all");
return View(rc);
public class BuildingReportModel
{
public string message1 { get; set; }
public string message2 { get; set; }
}
public class BuildingWSObjects
{
public async Task<T> GetWSObject<T>(string uriActionString)
{
T returnValue =
default(T);
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost/logger");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(uriActionString);
response.EnsureSuccessStatusCode();
returnValue = JsonConvert.DeserializeObject<T>(((HttpResponseMessage)response).Content.ReadAsStringAsync().Result);
}
return returnValue;
}
catch (Exception e)
{
throw (e);
}
}
}
I would modify BuildingWSObjects class and add new method:
public async Task<List<T>> GetWSObjects<T>(string uriActionString)
{
return new List<T> { await this.GetWSObject<T>(uriActionString)};
}
pass list to your GetWSObject than it will return you a list.
rc = await ws.GetWSObject<List<BuildingReportModel>>("all");

Access to web API from a console application

In the process of learning about web API, I have created (or actually Visual Studio has) a simple controller. I have also created a WPF program that can read from web API's GET() part, but I can't access the others.
I have tried a lot and found many blogs and pages that say: "Just do like this..." but nothing works. What am I doing wrong?
MVC part:
namespace MVCWebservice.Controllers
{
public class LaLaController : ApiController
{
// GET: api/LaLa
public string Get()
{
return "Hello from API";
}
// GET: api/LaLa/5
public string Get(int id)
{
return "value";
}
// POST: api/LaLa
public void Post([FromBody]string value)
{
var a = value;
}
// PUT: api/LaLa/5
public void Put(int id, [FromBody]string value)
{
var b = value;
int c = id;
}
// DELETE: api/LaLa/5
public void Delete(int id)
{
int c = id;
}
}
}
And a method from my Console application that actually works:
private static async Task ReadFromWebApi()
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
client.BaseAddress = new Uri("http://localhost:26176/");
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var resp2 = await client.GetAsync("api/LaLa/");
resp2.EnsureSuccessStatusCode();
var aaa = resp2.Content;
string result = await aaa.ReadAsStringAsync();
Console.WriteLine(result);
}
A method that just stops:
If I remove the EnsureSuccessStatusCode I'll get the following back:
ss = "{\"Message\":\"The requested resource does not support http
method 'PUT'.\"}"
private static async Task SendToWebApi()
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
client.BaseAddress = new Uri("http://localhost:26176/");
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
Console.WriteLine("-1-");
var resp2 = client.PutAsync("api/LaLa/", new System.Net.Http.StringContent("Hey", Encoding.UTF8, "application/json")).Result;
Console.WriteLine("-2-");
resp2.EnsureSuccessStatusCode();
var ss = await resp2.Content.ReadAsStringAsync();
}
How would I write my access to the other methods?
For one thing, you are calling PUT on the URL api/LaLa/, but from the server's method signature
public void Put(int id, [FromBody]string value)
it appears that the URL should include a numeric id to satisfy the first parameter, e.g. api/LaLa/100 or similar. Perhaps you could modify your client to call PutAsync() like this:
var resp2 = client.PutAsync("api/LaLa/100", new System.Net.Http.StringContent("Hey", Encoding.UTF8, "application/json")).Result;
Does POST work? Look at this answer to a question that looks remarkably like yours, and see if you can get that to work.

Categories