I'm new to writing .net APIs and I'm working in Visual Studio 2017. I've been working on this for a couple of days and I'm completely stumped. I'm trying to create a simple web API that a Post call sends a cXML string passed into it via the Post Body. I then take the incoming cXML string and simply save it to a text file on a network drive. That is all I need to do, I don't need to de-serialize the xml, read any of the fields or extract any data out of the XML, I just need to grab the entire input xml string and save it to a text file. The problem I'm having is no matter what I've tried the incoming body always seems to be null. My code is simple:
[HttpPost]
[Route("api/Pass_XML_to_File")]
public HttpResponseMessage Post([FromBody] dynamic IncomingXML)
{
//do work here: take Incoming xml string and save it to a file which should be simple...
}
Unfortunately my IncomingXML variable is always null, so I have no data to save into a text file. I've been testing this from Postman and no matter what I've tried the variable is always null.
I've tried many other ways such as
Post([FromBody] XmlDocument IncomingXML)
Post([FromBody] string IncomingXML), etc.
I've tried changing in Content-Type header in Postman from application/xml, text/xml, text and a few others without any success. The funny thing is if I pass a JSON string in the body (changing the Content-Type to text/JSON) the data comes in perfectly without issue. Just when I pass xml the incoming body is always null.
Does anyone know how I can get the body xml to come in as a string so I can simply save it to a text file for later processing on a separate system? Thank you all in advance for your assistance.
Can you post the form you sent on the client side?
[HttpPost]
[Route("api/Pass_XML_to_File")]
public HttpResponseMessage Post([FromBody] dynamic IncomingXML)
{
// data is coming in correctly.
return null;
}
Postman Client Send :
{
"IncomingXML":"<note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don'tforgetmethisweekend!</body></note>"
}
data comes to variable successfully.
if you want to accept a xml format request, you should do the below steps:
Startup.ConfigureServices edit:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddXmlSerializerFormatters();
}
Apply the Consumes attribute to controller classes or action methods that should expect XML in the request body.
[HttpPost]
[Route("api/Pass_XML_to_File")]
[Consumes("application/xml")]
public HttpResponseMessage Post([FromBody] dynamic IncomingXML)
{
// data is coming in correctly.
return null;
}
Note: Install the Microsoft.AspNetCore.Mvc.Formatters.Xml NuGet package.
Related
First of all, my English is not so good, I hope you understand what I am trying to say.
I'm new with WebApi's. I created one and all seems good. In my function I return a string, but when I test the web api with Postman it returns a status code 204 no content.
I looked for this status and apparently my request was succeded, but when I look at my database nothing happend. (my function saves some data in my database and returns a string when it is succeded or not).
So, my question is, Why am I receiving this status code when my function must to return a string? Or why when I test the Web Api with Postman it returns a 204 No Content code (that means my request was succeded) when is not true (because nothing was saved in my database)?
Here is my function in my web api:
[HttpPost]
public string IncomingPO(string request)
{
//do some stuff
return "response as a string";
}
My parameter "string request" is a string that cointains a xml. I read the string as a xml and do some stuff with it. (save some nodes from the xml in a database, for example).
If all the function is succeded or not I expect the output of my string, but I'm no receiving anything. Only the status code 204 No Content. (when content should really be returned).
Any suggestion is welcome.
It can solve my problem.
The only thing I had to do was specify the route with which my Api website will be invoked.
In addition I also had to modify the data type of my parameter and my function.
Something like this:
[HttpPost]
[Route("api/Controller/IncomingPO")]
public HttpResponseMessage IncomingPO(HttpRequestMessage request)
{
//do some stuff
return new HttpResponseMessage()
{
Content = new StringContent("My response string", System.Text.Encoding.UTF8, "application/xml"),
StatusCode = HttpStatusCode.OK
};
}
I have an third party event that post data to my hosted API but the problem is I don't know the Json structure which event posting to my API from Body. I need to read the json content posted by Event to my API.
I have tried to create post method as dynamic or string type the event able to call the service but data is not get typecast, it shows null always.
[HttpPost]
RecievedPayload([FromBody]dynamic json)
{
}
[HttpPost]
RecievedPayload([FromBody]string json)
{
}
RecievedPayload Api method is getting invoked by Third party Event but the json content is null. I need to know the Json structure so that I can make a custom class to hold the content.
There isn't a simple way to just get the whole body as a parameter.
This blog post is worth a full read: https://weblog.west-wind.com/posts/2013/dec/13/accepting-raw-request-body-content-with-aspnet-web-api
However to accomplish your goal, this is a slightly modified version of a code sample provided in the blog post, which should work for your needs:
[HttpPost]
public async Task<string> RecievedPayload()
{
string result = await Request.Content.ReadAsStringAsync();
return result;
}
Also worth reading: https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
Context: My application is behind a central login app, whenever the user apply access to my application, my application got a http request contain the user info. And I need to retrieve the user info from the HttpRequest Body.
This is what I tried so far:
currentContext.HttpContext.Request.Query["user-name"].toString(); // got nothing
using (var reader = new StreamReader(currentContext.HttpContext.Request.Body))
{
var body = reader.ReadToEnd();
} // I can get the raw HttpRequest Body as "user-name=some&user-email=something"
Is there any method I can use to parse the parameters and values from the Request.Body?
I tried the following, got nothing either.
HttpContext.Item['user-name'] \\return nothing
Request.Form["user-name"] \\ return nothing
and the reason I am not be able to use model binding is, in the HttpRequest body, the key name is "user-name", and in c#, I can't create a variable with a "-"
Meanwhile, in the my .net 4.6 application, Request["KeyName"].toString() works just fine.
I figured out a way to convert the raw HttpRequest Body to a Query String, then read parameters from it.
Here is the code:
var queryString = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(requestBody);
string paramterValueIWant = queryString["KeyName"];
There is one problem though, when the KeyName doesn't exist in the body, it will throw an exception. So you have to null check or do a try catch.
Still I feel like there should be a better way to read the parameter, as I mentioned, in my .net 4.6 application, all I need to do is Request["KeyName"].
Assuming that we are talking about POST/PUT/PATCH call, you can use
Request.Form["KeyName"]
in your API method and set the 'contentType' of the Ajax request as application/x-www-form-urlencoded
Notice that Request is automagically available inside your method. No need to explicit call it.
When using GET/DELETE call i prefer to use
[HttpGet("{UserId}")] // api/User/{UserId}
public IActionResult Get(int UserId){
// do stuff calling directly UserId
}
Or with PUT/PATCH
[Route("User/{EntityId}/{StatusFilter}")] // api/User/{EntityId}/{StatusFilter}
[HttpPut]
public IActionResult Put(int EntityId, int StatusFilter){
// do stuff calling directly EntityId and StatusFilter
}
where you can then still take data from the Body using Request.Form["KeyName"]
I am using ASP .NET Web API and I have a Controller that have code similar to this:
[Route("UpdateData")]
[HttpPost]
public HttpResponseMessage UpdateData([FromBody]RequestClasses.UpdataData data)
{
string json;
if (HttpContext.Current.Request.InputStream.Length > 0)
{
HttpContext.Current.Request.InputStream.Position = 0;
using (var inputStream = new StreamReader(HttpContext.Current.Request.InputStream))
{
json = inputStream.ReadToEnd();
}
}
// Dencrypt json
return Request.CreateResponse(HttpStatusCode.OK);
}
As input parameter I have "[FromBody]RequestClasses.UpdataData data". I have this in order to be able to show a Help page (using Microsoft.AspNet.WebApi.HelpPage).
The data object received in this method is encrypted and I need to decrypt it.
My problem is that I cannot call HttpContext.Current.Request.InputStream because the "[FromBody]RequestClasses.UpdataData data" has disposed my InputStream.
Any good ideas to solve this? As I still need the help page to show which parameters to call the method with.
By design ASP.NET Web API can only read the payload input stream once. So, if the parameter binder reads it, you don't have it available. That's way people is telling you in the comments to use parameterless methods, and read the payload yourself.
However, you want to have parameters to see them in the help page. There is a solution for that: do the decryption of the request in previous steps. To do that you can use Message handlers. Please, see this: Encrypt Request/Reponse in MVC4 WebApi
I'm trying to figure out the new ASP.NET Web API.
So far I've been able to create this method signature and connect to it just fine and get a valid response...
[HttpPost]
public HttpResponseMessage CreateAccount()
I am able to send a request to this method with fiddler and have verified that it is receiving the request.
However, when I try to pass data is when I am running into a problem.
The first thing I tried was...
[HttpPost]
public HttpResponseMessage CreateAccount([FromBody]string email, [FromBody]string password)
And I type
email:xyz,password:abc
into the body of the request in fiddler. When I do this I get a 500 error stating
'Can't bind multiple parameters ('email' and 'password') to the request's content.'
I have also tried this as a method signature...
[HttpPost]
public HttpResponseMessage CreateAccount([FromBody]UserAccountRequestData data)
with the UserAccountRequestData being a simple POCO
public class UserAccountRequestData
{
public string Email { get; set; }
public string Password { get; set; }
}
And I put
{Email:xyz,Password:abc}
or
data:{Email:xyz,Password:abc}
into the body of the request. In both cases trying to populate the POCO I am able to reach the method while debugging, but the data object is always null.
I need to understand how to create API methods that accept both strongly typed POCOs and others that accept multiple primitive types like strings and ints.
Thanks
You need to set the Content-Type header to application/json and then provide valid JSON.
{"Email":"xyz","Password":"abc"}