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.
Related
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.
The Get and Post methods work fine, but when I try to call the Delete endpoint, it seems like it is never executed.
UserController.cs
[HttpDelete]
[MapToApiVersion("1.0")]
public async Task<IActionResult> Delete([FromForm] string userName)
{
return await RemoveUser(userName);
}
I am using the HttpClientto perform the request as follows:
using (Client = new HttpClient())
{
Client.BaseAddress = new Uri("https://localhost:44332/");
var result = await Client.DeleteAsync(new Uri($"/api/v{Version}/User" +"/xxx"));
return result.ToString();
}
I have created a console application to test the API:
Program.cs
public class Program
{
private static readonly HttpClient Client = new HttpClient { BaseAddress = new Uri("https://localhost:44332/") };
public static void Main(string[] args)
{
Task.Run(() => RunAsync(args));
Console.ReadLine();
}
private static async Task RunAsync(IReadOnlyList<string> args)
{
var result = await Client.DeleteAsync(new Uri($"/api/v1/user/gareth"));
Console.WriteLine(result.ToString());
}
}
When I call the same endpoint using Postman it works, what am I doing wrong?
You are trying to parse the username from the request body ([FromBody]), but you are not providing any payload to the HTTP client, instead you are specifying the parameter within the URL. Therefore, your API method should look something like this:
UserController.cs
[HttpDelete("{userName}")]
public async Task<IActionResult> Delete(string userName)
{
return await RemoveUser(userName);
}
The code below will issue a DELETE request against the UserController and pass john-doe as the userName parameter.
Program.cs
private static void Main(string[] args)
{
var httpClient = new HttpClient { BaseAddress = new Uri("https://localhost:44332") };
httpClient.DeleteAsync(new Uri("/api/v1/user/john-doe", UriKind.Relative)).Wait();
}
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");
}
I am trying to call an externally hosted Web API within my Web API Application.
While attempting to use Get () method, everything seems to work fine.
However, when I try to implement Get(int value) I am getting an error:
Multiple operations with path 'api/External' and method 'GET'.
What is wrong with my Controller?
public class ExternalController : ApiController
{
static string _address = "http://localhost:00000/api/Values";
private string result;
// GET api/values
public async Task<IEnumerable<string>> Get()
{
var result = await GetExternalResponse();
return new string[] { result, "value2" };
}
private async Task<string> GetExternalResponse()
{
var client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(_address);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadAsStringAsync();
return result;
}
public async Task<string> Get(int value)
{
var result = await GetExternalResponse();
return result;
}
}
I have also tried the below approach, which also seems to throw the same error:
private async Task<string> GetExternalResponse2(int value)
{
var client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(_address + "/" + value);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadAsStringAsync();
return result;
}
public async Task<string> Get(int value)
{
var result = await GetExternalResponse2(value);
return result;
}
When you do your get like this
Get api/External/{id}
web api is not sure whether to call the Get Method with no parameter or the Get Method with Parameter because of the default routing defined in your web api config
I would suggest using attribute routing to fix your problem
[Route("api/External/Get")]
public async Task<IEnumerable<string>> Get()
[Route("api/External/Get/{id}")]
public async Task<string> Get(int value)
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.