I need to accept xml as request body
Here is my controller
[HttpPost]
[Route("UpdateLeaveBalance")]
[ProducesResponseType(typeof(RootLeaveBalanceDto), (int)HttpStatusCode.OK)]
public async Task<IActionResult> CreateOrUpdate([FromBody] RootLeaveBalanceDto model)
{
var result = await _leaveBalanceService.SetLeaveBalance(model);
return OkResult(result);
}
here is the program.cs
services.AddControllersWithViews(options =>
{
options.Filters.Add(typeof(GlobalModelStateValidatorAttribute));
}).AddXmlDataContractSerializerFormatters();
I tried using this code i gave but when i set debuger i got no data but the post request gives 200
Related
I have a following situation which I have never seen before. I am using code below to declare a Post action.
[HttpPost]
[Route("")]
public async Task<HttpResponseMessage> Insert(InsertRequest request)
{
var body = await Request.Content.ReadAsStringAsync();
}
Now, when I am sending request to this endpoint using Postman with Content-Type = Application/Json I get some value for request and empty string for body.
If I do PostAsJsonAsync with HttpClient to this endpoint I will get null for request and request content for body.
How is that possible?
To support POST you need to add attribute [FromBody] to the request parameter.
[HttpPost]
[Route("")]
public async Task<HttpResponseMessage> Insert([FromBody] InsertRequest request)
{
var body = await Request.Content.ReadAsStringAsync();
}
i'm sending an array of Guids to an ASP.NET Core Web app using aurelia-fetch-client, however on the server side the model binder doesn't pick it up and the list of notificationIds is null. However when i make the request through Swagger, or CURL it binds just fine.
I changed the signature of my controller method to accept a list of strings just in case there was something wrong with the GUID formatting, but same issue.
JS
var body = {notificationIds : this.notifications.map(x => x.notificationId) };
console.log("Dismissing All notifications");
await this.httpClient.fetch('http://localhost:5000/api/notifications/clear',
{
method: 'POST',
body: json(body),
headers: {
'Authorization': `Bearer ${localStorage.getItem('access_token')}`,
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-Requested-With': 'Fetch'
},
mode: 'cors'
}).then(response => {
if(response.status == 204){
//Success! Remove Notifications from VM
}
else{
console.log(response.status)
}
})
Controller Method
// POST: api/Notifications
[HttpPost]
[Route("clear")]
[ProducesResponseType((int)HttpStatusCode.NoContent)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> Post([FromBody]List<string> notificationIds)
{
if (notificationIds.IsNullOrEmpty())
{
return BadRequest("No notifications requested to be cleared");
}
var name = User.Claims.ElementAt(1);
await _notificationRepository.Acknowledge(notificationIds, name.Value);
return NoContent();
}
Interesting thing is that Chrome (V62) shows nothing posted.
But Fiddler does
The shape of the object you are passing from JavaScript isn't the same shape of an object you are telling the ASP.NET framework to expect.
There are two ways that you could fix this issue:
Option 1:
In your JavaScript, change your body to var body = this.notifications.map(x => x.notificationId);
Option 2:
Create an object in c# that reflects what you are passing from your JavaScript.
namespace Foo
{
public class Bar
{
public List<string> NotificationIds { get; set; }
}
}
and then update your controller method to the following:
// POST: api/Notifications
[HttpPost]
[Route("clear")]
[ProducesResponseType((int)HttpStatusCode.NoContent)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> Post([FromBody]Bar bar)
{
if (bar.NotificationIds.IsNullOrEmpty())
{
return BadRequest("No notifications requested to be cleared");
}
var name = User.Claims.ElementAt(1);
await _notificationRepository.Acknowledge(bar.NotificationIds, name.Value);
return NoContent();
}
The problem here is that you're not sending a list of GUIDs you are sending an object with a property that contains a list of GUIDs. Either create and use a view model (as described by peinearydevelopment) or accept a dynamic parameter that refers to the json object.
public async Task<IActionResult> Post([FromBody] dynamic json)
{
var notificationIds = json.notifcationIds;
...
I am using Angular 2 in order to send http requests to the server.
The server is running with ASP.Net.
My API:
public class LagerController : ApiController
{
public IHttpActionResult RepHistorie(string vnr, string lagerort)
{
...
}
}
So I would call the API with
http://123.456.7.89/api/lager?vnr=W17291092373&lagerort=0382691395
This works fine when using a tool called postman with wich you can test API's.
But when making a post request with Angular 2, it doesn't work.
It says that the HTTP-resource is not found.
Angular 2:
submit() {
var body = 'vnr=W17291092373&lagerort=0382741400';
var link = 'http://123.456.7.89/api/lager';
this.http.post(link, body)
.subscribe(data => {
console.log(data);
}, error => {
console.log("Oooops!");
});
}
It seems like the parameters aren't added correctly.
Edit: Changed tag
This needs clarification, since the API above seems to be a GET Request.
In case it is a POST Request , then you should use the whole URL while running the API
In case you want to submit an object , you should use [FromBody] as a parameter
Example
[HttpPost]
public IHttpActionResult( [FromBody]YourObject item ) {
}
====
Client-side
var postUrl = 'http://123.456.7.89/api/lager?vnr=W17291092373&lagerort=0382691395';
var postObject = {};
http.post(postUrl,postObject)
For GET request where you would like to use QueryString
[HttpGet]
public IHttpActionResult RepHistorie([FromQuery]string vnr,[FromQuery]string lagerort){
...
}
====
// Query string can be built using RequestOptionsArgs as well
var builtUrl = 'http://123.456.7.89/api/lager?vnr=W17291092373&lagerort=0382691395';
http.get(builtUrl)
Alternative way is to
var getUrl = 'http://webapi/api/lager';
var requestOptions = {};
http.get(getUrl,requestOptions);
Reference:
Angular HTTP: https://angular.io/api/http/Http , check get() and post() methods
RequestOptionsArgs : https://angular.io/api/http/RequestOptionsArgs
I created a custom Result I use in the Web API Controller actions where I return a custom async Task<IHttpActionResult>.
public class CustomResult<T> : NegotiatedContentResult<T>
{
public CustomResult(HttpStatusCode statusCode, T content, ApiController controller)
: base(statusCode, content, controller)
{
}
public CustomResult(HttpStatusCode statusCode, T content, IContentNegotiator contentNegotiator, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
: base(statusCode, content, contentNegotiator, request, formatters) { }
public override async Task<HttpResponseMessage> ExecuteAsync(System.Threading.CancellationToken cancellationToken)
{
HttpResponseMessage response = await base.ExecuteAsync(cancellationToken);
return response;
}
}
And basically in my action I return it like this:
public async Task<IHttpActionResult> Register(RegisterViewModel model)
{
if (!ModelState.IsValid)
{
return new CustomResult<string>(HttpStatusCode.BadRequest,"Model is invalid", this);
}
else
{
return new CustomResult<string>(HttpStatusCode.Ok,"Model is valid", this);
}
}
The problem is the custom message I want to return. It doesn't work! If the model is invalid I always get the 400 Bad Request and the custom message: "The remote server returned the following error while establishing a connection - 'Bad Request', instead of getting 400 Bad Request and my custom message Model is invalid.
This however works when I return 200 OK.
Is there something I am doing wrong?
Try to set
<system.webServer>
<httpErrors existingResponse="PassThrough"/>
</system.webServer>
in web.config. PassThrough option - leaves the response untouched if an existing response exists. (more about httperrors)
I am trying to call the RegisterExternal method in Web API, after having retrieved a token from facebook. But I keep getting a 401 Unauthorized from my Web API. I am not sure I am correctly implementing the logic flow. My code is;
Ask for supported external login providers;
public async Task<List<ExternalLoginViewModel>> GetExternalLoginsAsync()
{
using (var client = GetNewHttpClient(false))
{
var response = await client.GetAsync("api/account/externalLogins?returnUrl=/&generateState=true");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsAsync<List<ExternalLoginViewModel>>();
}
}
From this, I am returned a facebook URL. I follow this and then enter in my facebook username and password. I return back to my app via a deep link and then try and call the RegisterExternal method in the web API like this, passing the facebook "access token" that is returned.
public async Task<bool> SendSubmitRegisterExternalAsync(RegisterExternalBindingModel ro, string accessToken)
{
using (var client = GetNewHttpClient(true))
{
client.DefaultRequestHeaders.Add("Authorization", String.Format("Bearer {0}", accessToken));
HttpResponseMessage response = await client.PostAsJsonAsync("api/Account/RegisterExternal", ro);
if (response.IsSuccessStatusCode) return true;
var value = await response.Content.ReadAsStringAsync();
throw new ResponseErrorException(ErrorHelper.GetErrorString(value));
}
}
I receive 'Unauthorized' every time. I do not know what is wrong. My Web API method looks like this, and the class is marked with the [Authorize] attribute.
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
...
I have found three different posts this evening of people asking this exact same question, and in all cases there are no replies, so I am not hopeful but if anyone can shed some light on this it would be great!
EDIT: I have also changed the method signature to 'allowanonymous' and still get unauthorized!
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[AllowAnonymous]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
I have sorted this by not using FacebookSessionClient and doing it via a WebBrowser control instead.
I use the URL from the first step (provided to me by the WebAPI). Then on the Navigated event from the WebBrowser control, i parse the Url for the access token;
public async void ParseUrlForAccessToken(string url)
{
string fieldName = "access_token";
int accessTokenIndex = url.IndexOf(fieldName, StringComparison.Ordinal);
if (accessTokenIndex > -1)
{
int ampersandTokenIndex = url.IndexOf("&", accessTokenIndex, StringComparison.Ordinal);
string tokenField = url.Substring(accessTokenIndex, ampersandTokenIndex - accessTokenIndex);
string token = tokenField.Substring(fieldName.Length);
token = token.Remove(0, 1);
await _dataService.SubmitLoginExternal("Test", token);
}
}
Then as shown above, I call SubmitLoginExternal, which is a call to the following code which uses the access token retrieved from the WebBrowser control Url to register the account (in this case a 'Test' account);
using (var client = GetNewHttpClient(true))
{
client.DefaultRequestHeaders.Add("Authorization", String.Format("Bearer {0}", accessToken));
HttpResponseMessage response = await client.PostAsJsonAsync("api/Account/RegisterExternal", ro);
if (response.IsSuccessStatusCode) return true;
var value = await response.Content.ReadAsStringAsync();
throw new ResponseErrorException(ErrorHelper.GetErrorString(value));
}
This has worked and now I have the user registered in my database.
The key was to use a WebBrowser control and not the FacebookSessionClient object or a WebBrowserTask. You cannot use a WebBrowserTask as you need to hook in to the navigated event once the page has loaded to call ParseUrlForAccessToken().