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.
Related
I need to save the changes I make in my model through API call in my database. I have checked my API is working fine when I am running it individually on Web. But its giving me an error StatusCode: 405, ReasonPhrase: 'Method Not Allowed'. I am trying to send and object and trying to see whether the request made was completed or not. When I am trying to debug it, it is not sending hit on my API controller.
Here is my model class:
public class Customer
{
[Required]
public Guid CustomerId { get; set; }
public int Age { get; set; }
public int Phone { get; set; }
}
PUT Method in API:
[HttpPut]
[Route("api/[controller]/{customer}")]
public IActionResult EditCustomer(Customer customer)
{
var cust = _customerData.EditCustomer(customer);
if (cust == string.Empty)
{
return Ok();
}
else
{
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
}
}
The method I am using in project to call API:
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(apiBaseUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")
);
var sum = await client.PutAsJsonAsync("api/Customer/", customer);
if (sum.StatusCode == System.Net.HttpStatusCode.OK)
{
return RedirectToActionPermanent(actionName: "SingIn");
}
else
{
TempData["msg"] = "There is an error";
return View();
}
where baseaddress= {https://localhost:44398/}
EditCustomer Method
public string EditCustomer(Customer customer)
{
try
{
var pro = _customerContext.Customer.Where(e => e.CustomerId == customer.CustomerId).FirstOrDefault();
pro.Age = customer.Age;
pro.Phone = customer.Phone;
pro.Name = customer.Name;
_customerContext.Entry(pro).State = EntityState.Modified;
_customerContext.SaveChanges();
}
catch(Exception e)
{
return e.Message;
}
return string.Empty;
}
You need to fix your action route by removing {Customer}, since you send customer in request body, not as a route value
[Route("~/api/Customer")]
and request
var sum = await client.PutAsJsonAsync("/api/Customer", customer);
or better fix the acttion route name to meaningfull
[Route("~/api/EditCustomer")]
and
var sum = await client.PutAsJsonAsync("/api/EditCustomer", customer);
AsJsonAsync sometimes causes problems
try this code
var json = JsonSerializer.Serialize(customer);
//or if you are using Newtonsoft
var json = JsonConvert.SerializeObject(customer);
var contentData = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PutAsync("/api/Customer", contentData);
if (response.IsSuccessStatusCode)
return RedirectToActionPermanent("SingIn");
else
{
TempData["msg"] = "There is an error";
return View();
}
but IMHO I would prefer to use
client.PostAsync("/api/EditCustomer", contentData);
instead of Put.
and added [FromBody] to action
[HttpPost("~/api/EditCustomer")]
public IActionResult EditCustomer([FromBody] Customer customer)
I am no pro in web APIs but I suspect it could be due to the fact that the API expects customer to be in request URL.
Try and change the API route to [Route("api/[controller]")]
This could've been a comment but I don't have enough reputation :)
I have trouble trying to create an integration test for my post call that accepts a viewmodel that has amongst other values, an IFormFile, which makes this call from an application/json to a multipart/form-data
My IntegrationSetup class
protected static IFormFile GetFormFile()
{
byte[] bytes = Encoding.UTF8.GetBytes("test;test;");
var file = new FormFile(
baseStream: new MemoryStream(bytes),
baseStreamOffset: 0,
length: bytes.Length,
name: "Data",
fileName: "dummy.csv"
)
{
Headers = new HeaderDictionary(),
ContentType = "text/csv"
};
return file;
}
My Test Method
public async Task CreateAsync_ShouldReturnId()
{
//Arrange
using var content = new MultipartFormDataContent();
var stringContent = new StringContent(
JsonConvert.SerializeObject(new CreateArticleViewmodel
{
Title = "viewModel.Title",
SmallParagraph = "viewModel.SmallParagraph",
Url = "viewModel.Url",
Image = GetFormFile()
}),
Encoding.UTF8,
"application/json");
stringContent.Headers.Add("Content-Disposition", "form-data; name=\"json\"");
content.Add(stringContent, "json");
//Act
var response = await httpClient.PostAsync($"{Url}", content);
//Assert
response.StatusCode.ShouldBe(HttpStatusCode.OK);
int id = int.Parse(await response.Content.ReadAsStringAsync());
id.ShouldBeGreaterThan(0);
}
My Controller Method
[HttpPost]
public async Task<IActionResult> CreateArticleAsync([FromForm] CreateArticleViewmodel viewModel)
{
var id = await _service.CreateAsync(viewModel).ConfigureAwait(false);
if (id > 0)
return Ok(id);
return BadRequest();
}
It throws a BadRequest without getting inside the method.
The way you are posting the request contents to the API, in your code, is not correct.
When the API expects a FileInfo in the request payload, posting JSON content never works. You need to send the payload as MultipartFormData and not as JSON.
Consider following example.
This is a an API endpoint which expects and model with FileInfo in it as payload.
[HttpPost]
public IActionResult Upload([FromForm] MyData myData)
{
if (myData.File != null)
{
return Ok("File received");
}
else
{
return BadRequest("File no provided");
}
}
public class MyData
{
public int Id { get; set; }
public string Title { get; set; }
// Below property is used for getting file from client to the server.
public IFormFile File { get; set; }
}
This is pretty much the same API as yours.
Following is the client code which calls the above API with file and other model properties.
var apiURL = "http://localhost:50492/home/upload";
const string filename = "D:\\samplefile.docx";
HttpClient _client = new HttpClient();
// Instead of JSON body, multipart form data will be sent as request body.
var httpContent = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(File.ReadAllBytes(filename));
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
// Add File property with file content
httpContent.Add(fileContent, "file", filename);
// Add id property with its value
httpContent.Add(new StringContent("789"), "id");
// Add title property with its value.
httpContent.Add(new StringContent("Some title value"), "title");
// send POST request.
var response = await _client.PostAsync(apiURL, httpContent);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
// output the response content to the console.
Console.WriteLine(responseContent);
The client code is running from a Console application. So when I run this, the expectation is to get File received message in the console and I am getting that message.
Following is the screen capture of the model content at the API end while debugging it.
And if I am calling this API from postman, it would look like following.
I hope this will help you solve your issue.
When I call the asp.net mvc 5 web api in Asp.net Core the input parameter FromBody always is null
asp.net Mvc 6 web api
public void Post([FromBody]string id)
{
}
calling web api in asp.net core
using (var client = new HttpClient())
{
string stringData = JsonConvert.
SerializeObject("test");
var contentData = new StringContent(stringData, System.Text.Encoding.UTF8,"application/json");
HttpResponseMessage response1 = client.PostAsync("http://localhost:49741/api/values/", contentData).Result;
}
As Crowcoder said. You should register MediaTypeFormatter. Here simple arctile how do that provides to do what you want.
But simpler is choose another way to work with incoming data. As application/json. Create simple Dto class like:
public class TestDataDto
{
public string Id { get; set; }
}
And change argument type of your Post method:
// POST api/values
public void Post([FromBody]TestDataDto value)
{
}
Then code of your core client should be like this:
static void Main(string[] args)
{
using (HttpClient httpClient = new HttpClient())
{
var someData = JsonConvert.SerializeObject(new { Id = "test" });
var content = new StringContent(someData, System.Text.Encoding.UTF8, "application/json");
var result = httpClient.PostAsync("http://localhost:55878/api/values", content).Result;
if (result.IsSuccessStatusCode)
{
Console.WriteLine("All is fine");
}
else
{
Console.WriteLine($"Something was wrong. HttpStatus: {result.StatusCode}");
}
}
Console.ReadKey();
}
I am doing an MVC 5 Application, and I am calling a API controller method that is in another Solution.
I am using HttpClient(). and I am calling PostAsJsonAsync with some parameters, an instance of a class.
It looks like this.
string apiUrl = "localhost:8080/api/";
ContactWF contactWF = new contactWF();
contactWF.contact_id=0;
contactWF.UserOrigin_id=20006
contactWF.ProcessState_id=2;
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(apiUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.PostAsJsonAsync(apiUrl + "Contact/Method", contactWF);
if (response.IsSuccessStatusCode)
{
return response.Content.ReadAsAsync<int>().Result;
}
}
My API controller method is like this.
[ActionName("Method")]
[HttpGet]
public int Method([FromBody] ContactWF userwf)
{
return 10;
}
It Works fine...
My problem is when I try Serialized the parameter class instance
I replace line
HttpResponseMessage response = await client.PostAsJsonAsync(apiUrl + "Contact/Method", contactWF);
with this one
string jsonData = JsonConvert.SerializeObject(contactWF);
HttpResponseMessage response = client.PostAsJsonAsync("api/Contact/Method", jsonData).Result;
I've got an Error:405...
It looks like the Json string it is not recognize as a Parameter.
My Json string looks like this.
"{\"Contact_id\":0,\"Description\":null,\"ProcessState_id\":2,\"Type_id\":0,\"Object_id\":0,\"Parent_id\":null}"
that is ContactWD class converter to json.
What´s wrong?
Method PostAsJsonAsync serialize parameter object himself, so it serialized your json string again.
If you need serialize object himself for some reason, then use method HttpClient.PostAsync
string jsonData = JsonConvert.SerializeObject(contactWF);
var stringContent = new StringContent(jsonData, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync("api/Filler/CountMensajeByUser", stringContent);
Change verb to HttpPost in your api controller
[ActionName("Method")]
[HttpPost]
public int Method([FromBody] ContactWF userwf)
{
return 10;
}
Update
You don't need to serialize object in PostAsJsonAsync
HttpResponseMessage response = client.PostAsJsonAsync("api/Contact/Method", contactWF).Result;
Take a look at sample code from microsoft
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/testing
internal class NewIdeaDto
{
public NewIdeaDto(string name, string description, int sessionId)
{
Name = name;
Description = description;
SessionId = sessionId;
}
public string Name { get; set; }
public string Description { get; set; }
public int SessionId { get; set; }
}
//Arrange
var newIdea = new NewIdeaDto("Name", "", 1);
// Act
var response = await _client.PostAsJsonAsync("/api/ideas/create", newIdea);
// Assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
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.