I have .NET Core 2.0 application. The Code below serializes the object using XmlSerializer and POST the content to api. (default is DataContractSerializer so i am explicitly passing XmlSerializer)
// use XmlSerializer
var formatter = new XmlMediaTypeFormatter();
formatter.UseXmlSerializer = true;
// Post as Xml
var httpResponse = await httpClient.PostAsync<TSource>(url, source, formatter).ConfigureAwait(false);
Here the request object
[XmlRoot(ElementName = "Request", Namespace = "")]
public class RequestDTO
{
[XmlArray("Invoices")]
[XmlArrayItem("InvoiceId")]
public string[] Invoices { get; set; }
}
However POST fails with HTTP 400 error. When i check the request in fiddler i noticed the following
so serialization wrapping the actual request around bd and o.
Not sure why?
Related
I have XML Web API like this
http://test/REST?hiInstanceId=7
XML parameters
<request_info>SALE</request_info><location_id>36</location_id>
<from_dt>01-JUN-22</from_dt><to_dt>10-JUN-22</to_dt>
how to get the response from the XML web API?
how to get response from the xml web Api
To make the Asp.net Core API return the XML format response. We need to configure XML formatters implemented using XmlSerializer, call AddXmlSerializerFormatters:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers()
.AddXmlSerializerFormatters();
Then, in the API controller, use the [Produces] attribute to specify a format.
[Route("api/[controller]")]
[ApiController]
public class TodoController : ControllerBase
{
[HttpGet]
[Produces("application/xml")]
public TestModel GetCustomers( )
{
return new TestModel()
{
request_info = "Sale",
location_id = 36,
from_dt = "01-JUN-22",
to_dt = "10-JUN-22"
};
}
}
Then, use the following code to call the API method and get the XML response:
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(new Uri("https://localhost:44374/api/todo"));
httpRequest.ContentType = "application/xml";
httpRequest.Method = "Get";
using (HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse())
{
using (Stream stream = httpResponse.GetResponseStream())
{
string xml = (new StreamReader(stream)).ReadToEnd(); //get the XML response
//Using XMLSerializer to convert the XML response to the object.
XmlSerializer serializer = new XmlSerializer(typeof(TestModel));
StringReader rdr = new StringReader(xml);
var result = (TestModel)serializer.Deserialize(rdr);
}
}
The debug screenshot like this:
I am calling a .NET WebApi2 endpoint from a dotnet core webapi. When I debug into the .NET WebApi2 POST endpoint, my value is always null. Is this not possible to do?
When I call the GET endpoint with an ID, the ID is passed with no issues.
I have used both Postman and Fiddler to debug. Whenever I pass my JSON object from Postman to the .NET WebApi2 POST endpoint, my value is populated.
Beyond frustrated as this seems pretty simple. :,(
Updated to include code
dotnet core web api (calling from Postman)
[HttpPost]
public async Task PostAsync([FromBody] string value)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var jsonObject = new JObject();
jsonObject.Add("text", "Rich");
var response = await client.PostAsJsonAsync("http://localhost:54732/api/Rich", jsonObject);
var responseResult = response.Content.ReadAsStringAsync().Result;
}
.NET WebApi2 (JObject is always null)
// POST: api/Rich
public void Post(JObject value)
{
}
This boils down to using JObject basically. For your older Web Api action, JObject works merely because you're posting JSON, and JObject is a dynamic. However, that is an entirely incorrect approach. You should be binding to a concrete class that represents the JSON being posted. That said, you may or may not be able to change anything there, and its not technically the source of your current issue.
The actual source is that you're attempting to send a JObject, which is not doing what you think it is. Again, JObject is a dynamic. It has accessors to parse and access the underlying JSON, but it does not actually expose the members of that JSON object directly. As a result, if you attempt to serialize it, you won't get anything usable from it. Passing it to PostAsJsonAsync causes it to be serialized.
What you actually need is something like:
var jsonObject = new { text = "Rich" };
Then, what you're passing to PostAsJsonAsync will be an anonymous object with actual members that can be serialized.
My "REAL" issue turned out to be Transfer-Encoding: chunked was being sent in the request header.
Here is my corrected code (dotnet core web api):
public async Task PostAsync([FromBody] JObject value)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/json"));
var jsonObject = new { variable1 = "Rich" };
var json = JsonConvert.SerializeObject(jsonObject);
var content = new StringContent(json, Encoding.UTF8, "application/json");
content.Headers.ContentLength = json.Length;
var response = await client.PostAsync("http://localhost:54732/api/Rich", content);
var responseResult = response.Content.ReadAsStringAsync().Result;
}
Here is my .NET WebApi2 code:
public IHttpActionResult Post([FromBody]RichTest value)
{
return Ok(value.variable1 + " done");
}
public class RichTest
{
public string variable1 { get; set; }
}
When I set the content.Headers.ContentLength, the Transfer-Encoding: chunked is removed. Now my code is working!!
I am still curious why the original PostAsJsonAsync does not work...
My scenario:
I'm using ASP .NET 5 Web API and I'm using content-type: application/json to post data to server.
Message:
Request headers
{...}
Content-Type:application/json
{...}
Request payload
{"Property1":"2280910","Property2":"734"}
MyController method:
[HttpPost]
public MyClassOutput GetDataRequest([FromBody] GetDataInput input) { ... }
I override the OnException method from the ExceptionFilterAttribute class which gives me the ExceptionContext instance. I want to get the parameter values from the request for exceptions logging purposes. I tried to read the body content, but it is empty.
public override void OnException(ExceptionContext context)
{
JsonSerializer serializer = new JsonSerializer();
var content = context.HttpContext.Request;
using (var stream = new StreamReader(content.Body, Encoding.UTF8))
using(var jsonTextReader = new JsonTextReader(stream))
{
var bodyContent = serializer.Deserialize(jsonTextReader);
if (bodyContent != null)
exceptionData.Parameters = bodyContent.ToString();
}
}
Can anyone give me directions?
I assume you created your own attribute for exception handling, implementing ExceptionFilterAttribute and overrided OnException(HttpActionExecutedContext actionExecutedContext) method. Basically, you have to revert the position in content stream to 0, as it was already read by the framework when calling proper controller method. Your code should look something like this:
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
base.OnException(actionExecutedContext);
var content = actionExecutedContext.Request.Content;
using (var streamReader = new StreamReader(content.ReadAsStreamAsync().Result))
{
streamReader.BaseStream.Position = 0;
using (var jsonReader = new JsonTextReader(streamReader))
{
var serializer = JsonSerializer.Create();
var parameters = serializer.Deserialize<GetDataInput>(jsonReader);
}
}
}
Since you can't read the content stream twice because of how ASP .NET implements the model binding process, the solution that I found to get the parameters values was in the context.ModelState.Values property. As simple as this... (I did not realize this before).
What is the best way to inspect the Request Headers for a service endpoint?
ContactService : Service
Having read this https://github.com/ServiceStack/ServiceStack/wiki/Access-HTTP-specific-features-in-services I'm curious as to the preferred way to get to the Interface.
Thank you,
Stephen
Inside a ServiceStack Service you can access the IHttpRequest and IHttpResponse objects with:
public class ContactService : Service
{
public object Get(Contact request)
{
var headerValue = base.Request.Headers[headerKey];
//or the same thing via a more abstract (and easier to Mock):
var headerValue = base.RequestContext.GetHeader(headerKey);
}
}
The IHttpRequest is a wrapper over the underlying ASP.NET HttpRequest or HttpListenerRequest (depending if you're hosting on ASP.NET or self-hosted HttpListener). So if you're running in ASP.NET you can get the underlying ASP.NET HttpRequest with:
var aspnetRequest = (HttpRequest)base.Request.OriginalRequest;
var headerValue = aspnetRequest.Headers[headerKey];
I get this error in my client (an ASP.NET MVC application) from a call to my ASP.NET Web API. I checked and the Web API is returning the data alright.
No MediaTypeFormatter is available to read an object of type
'IEnumerable`1' from content with media type 'text/plain'.
I believe that I can inherit from DataContractSerializer and implement my own serializer which can attach the Content-Type HTTP header as text/xml.
But my question is: is that necessary?
Because if it was, it would mean that the default DataContractSerializer does not set this essential header. I was wondering if Microsoft could leave such an important thing out. Is there another way out?
Here's the relevant client side code:
public ActionResult Index()
{
HttpClient client = new HttpClient();
var response = client.GetAsync("http://localhost:55333/api/bookreview/index").Result;
if (response.IsSuccessStatusCode)
{
IEnumerable<BookReview> reviews = response.Content.ReadAsAsync<IEnumerable<BookReview>>().Result;
return View(reviews);
}
else
{
ModelState.AddModelError("", string.Format("Reason: {0}", response.ReasonPhrase));
return View();
}
}
And here's the server side (Web API) code:
public class BookReviewController : ApiController
{
[HttpGet]
public IEnumerable<BookReview> Index()
{
try
{
using (var context = new BookReviewEntities())
{
context.ContextOptions.ProxyCreationEnabled = false;
return context.BookReviews.Include("Book.Author");
}
}
catch (Exception ex)
{
var responseMessage = new HttpResponseMessage
{
Content = new StringContent("Couldn't retrieve the list of book reviews."),
ReasonPhrase = ex.Message.Replace('\n', ' ')
};
throw new HttpResponseException(responseMessage);
}
}
}
I believe (because I don't have time to test it now) that you need to explicitly set the Status Code on the responseMessage you are passing to HttpResponseException. Normally, HttpResponseException will set the status code for you, but because you are providing a responsemessage explicitly, it will use the status code from that. By default, `HttpResponseMessage has a status code of 200.
So what is happening is you are getting an error on the server, but still returning a 200. Which is why your client is trying to deserialize the text/plain body produced by StringContent, as if it were an IEnumerable.
You need to set
responseMessage.StatusCode = HttpStatusCode.InternalServerError
in your exception handler on the server.
How about just using ReadAsStringAsync if your WebAPI is expecting to return content in plain text?
response.Content.ReadAsStringAsync().Result;