Send JSON to GET method in C# - c#

I have a web service with a controller that looks like this:
[HttpGet]
[Customizing.RequestSizeLimit(1048576)] // 1 MB
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
public async Task<IActionResult> ValidateTicketAsync([FromBody]KerberosTicketDto ticket)
{//code in here//}
Swagger states the web service accepts:
{
"ticket": "string"
}
From the client, I get a Kerberos ticket and convert it to a string:
KerberosSecurityTokenProvider tokenProvider = new KerberosSecurityTokenProvider(ServiceServer, TokenImpersonationLevel.Identification);
KerberosRequestorSecurityToken token = tokenProvider.GetToken(TimeSpan.FromMinutes(1)) as KerberosRequestorSecurityToken;
...
tokenString = Convert.ToBase64String(token.GetRequest());
Then attempt to send the data to the web server, and return a response code (i.e. hopefully 200):
WebClient webClient = new WebClient();
webClient.QueryString.Add("ticket", tokenString);
//webClient.QueryString.Add("spn", ServiceServer);
string result = webClient.DownloadString(urlTest);
The debug windows then sends me this:
[10:40:21 DBG] Attempting to bind parameter 'ticket' of type 'Kerberos.TicketValidator.WebApi.Model.KerberosTicketDto' using the name 'ticket' in request data ...
[10:40:21 DBG] Rejected input formatter 'Microsoft.AspNetCore.Mvc.Formatters.JsonPatchInputFormatter' for content type 'null'.
[10:40:21 DBG] Rejected input formatter 'Microsoft.AspNetCore.Mvc.Formatters.JsonInputFormatter' for content type 'null'
It appears the parameter the web service gets is not the type it expects it to be.
Can anyone help me in converting it to the right type? Or how to send it as the right type in the first place?
Thank you!

I think you need to send the ticket as an object with a property called ticket not as as string.
With HttpClient it could be something like the following.
var tokenJson = jsonSerializer.Serialise(new {token = tokenString });
using(var client = new HttpClient())
{
var req = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("some url"),
Content = new StringContent(tokenJson, Encoding.UTF8, ContentType.Json),
};
var res = await client.SendAsync(req).ConfigureAwait(false);
res.EnsureSuccessStatusCode();
var res = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}

Related

C# REST API File Upload from Client Code gets 400 Bad Request

I have a Rest API written in .Net core that accepts a File as input as Multipart/Form-data. The API works absolutely fine when I run it from Swagger/Postman.
Here is the API endpoint.
[HttpPost("CreateStudy")]
public ActionResult CreateStudy([FromForm] APIRequest request)
{
// rest of the code
Also here is the APIRequest object. it has only one property which is IFormFile Type.
public class APIRequest
{
public IFormFile XMLFile { get; set; }
}
So far it works well. The problem is that I am trying to write a client side code that will call this API and pass the File from C# code.
But I am always getting a 400-Bad request in the client code.
This is the client code I am trying with.
public string CallServiceWithFileAsync(string EndPointURL, string FilePath)
{
string ResultStatusCode;
Uri uri = new Uri(EndPointURL);
var Client = new HttpClient();
Client.DefaultRequestHeaders.Clear();
//Prepare Message
HttpRequestMessage Message = new HttpRequestMessage();
Message.Method = HttpMethod.Post;
Message.Headers.Add("Accept", "application/octet-stream");
Message.RequestUri = new Uri(EndPointURL);
using (Stream fileStream = File.OpenRead(FilePath))
{
var content = new StreamContent(fileStream);
var response = Client.PostAsync(uri, content);
ResultStatusCode = response.Result.StatusCode.ToString();
}
return ResultStatusCode;
}
What am I doing wrong here? What is the correct way of sending a file into REST endpoint ?
[FromForm] expects an accept header with application/x-www-url-formencoded. If this is not the case, check your output-logs to see why the request is not processed.

Define header for upload file in API

I am trying to upload excel file to convert it to Json, but i need to passing through API Gateway. I have problem to passing the file from API Gateway.
I try to set header in ContentDisposition, ContentLength and ContentType manually.
using (var client = new HttpClient())
{
using (var Content = new MultipartFormDataContent())
{
var name = Path.GetFileName(postedFile.FileName);
HttpContent content = new StringContent("");
content.Headers.Clear();
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = name,
FileName = name
};
content.Headers.Add("Content-Length", postedFile.ContentLength.ToString());
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("multipart/form-data");
Content.Add(content);
}
HttpResponseMessage reply = new HttpResponseMessage();
reply = await client.GetAsync(#"http://localhost:60897/api/ExceltoJSONConversion");
if (reply.IsSuccessStatusCode)
{
var responseString = await reply.Content.ReadAsStringAsync();
return Json(JsonConvert.DeserializeObject(responseString));
}
}
I have been tried several code but reply always return code 405 MethodNotAllowed.
here my controller where i proceed file
[HttpPost]
[Route("api/ExceltoJSONConversion")]
public IHttpActionResult ExceltoJSONConversion()
{
// Process the file from API Gateway
}
Am i missing something when define Header multipart/form-data? or my code just a mess?
Your API method accepts POST requests only ([HttpPost] attribute).
And in your client you are trying to get API through GET method (client.GetAsync ... ).
Either decorate your API method with [HttpGet] instead of [HttpPost], either change client part to use POST (client.PostAsync ... ).

C# Web API - POST Request doesn't get executed

I am trying to send a POST request from my ASP.NET Core Web API Project but the request is never sent. The method gets executed with no errors but the request never gets sent out from the async method.
My Implementation:
public async void notify(String message)
{
String url = "MY_WEBSERVICE_URL";
var client = new HttpClient();
client.BaseAddress = new Uri(url);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "relativeAddress");
request.Content = new StringContent("application/x-www-form-urlencoded;charset=UTF-8",
Encoding.UTF8, "application/json");
Byte[] byteArray = Encoding.UTF8.GetBytes("{\"text\":\"" + message + "\"}");
request.Content.Headers.ContentLength = byteArray.Length;
await client.SendAsync(request).ContinueWith(responseTask =>
{
Console.WriteLine("Response: {0}", responseTask.Result);
});
}
Is this the proper way of making a POST request from a Core Web API project? Thank you in advance
First of all, there is a dedicated method PostAsync in the HttpClient class ( or even PostAsJsonAsync extension) which you can use to send POST requests without creating HttpRequstMessage manually.
Now about your code - I believe you want to post following JSON string:
{"text":"someMessage"}
You should set this string as a content of StringContent which you are sending:
var json = "{\"text\":\"" + message + "\"}";
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
Currently you are trying to post mediatype string as a value to your API endpoint. Of course it cannot be deserialized into your model.
Note1: StringContent will automatically add Content-Length header with the appropriate value. You should not do that manually.
Note2: Unless this is an event handler, you should not use async void - use async Task instead.
Same task with PostAsJsonAsync usage will look like:
public async Task Notify(string message)
{
var string url = "MY_WEBSERVICE_URL";
var client = new HttpClient();
client.BaseAddress = new Uri(url);
var notification = new Notification { Text = message }; // use some model class
var resonse = await client.PostAsJsonAsync("relativeAddress", notification);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
}
}
In this case, your model will be automatically serialized into JSON, appropriate content will be created and POST request will be sent.
Try Adding [IgnoreAntiforgeryToken] on top of the Post Action like this

why RestSharp Request method Change from POST to GET?

I am using RestSharp to post some data to a url. I am monitoring this operation using fiddler. when I use Simple .net HttpClient with this code:
using (var client = new HttpClient())
{
var values = new Dictionary<string, string> {
{ "par1", "1395/11/29" },
{ "par2", "2" }};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("http://someurl.com/resource", content);
var responseString = await response.Content.ReadAsStringAsync();
}
every thing is good and this return true result. but when i try to use RestSharp with this code:
RestSharp.RestRequest request = new RestSharp.RestRequest("/resource");
request.AddParameter("par1", val, RestSharp.ParameterType.RequestBody);
request.AddParameter("par2", val, RestSharp.ParameterType.RequestBody);
request.AddHeader("Origin", "http://someurl.com");
request.Method = RestSharp.Method.POST;
RestSharp.RestClient client = new RestSharp.RestClient("http://someurl.com");
var response = client.Execute(request);
then fiddler show me the request sent by GET method instead of POST?
I check another time my fiddler and found this issue:
Content-Type: par1
why this is happening for me?
Change your ParameterType argument to GetOrPost and it will work
request.AddParameter("par1", val, RestSharp.ParameterType.GetOrPost);
request.AddParameter("par2", val, RestSharp.ParameterType.GetOrPost);
Initialize Request as POST with JSON.
var client = new RestClient(PreUri);
var request = new RestRequest(Uri, Method.POST) {RequestFormat = DataFormat.Json};
Add object in body
request.AddBody(obj);
Execute
var cancellationTokenSource = new CancellationTokenSource();
var response = await client.ExecuteTaskAsync(request, cancellationTokenSource.Token);
I was stupidly doing mistake to call "client.Get" instead of "client.Post". May be this post helps other.
var client = new RestClient("https://someservice.com");
var request = new RestRequest("/token/", Method.POST, DataFormat.Json).AddJsonBody(SomeObject);
var response = client.Get(request);
I was expecting this code to make POST request. Because i specified it as Method.POST.
But after a few hours, i saw my mistake. Yeas i was specifying the method. But just after i am calling client.Get(request); This changes the metod to GET.
So, the right way to use POST request is like follows:
var client = new RestClient("https://someservice.com");
var request = new RestRequest("/token/", DataFormat.Json).AddJsonBody(SomeObject);
var response = client.Post(request);

how to save an object using .net webapi

I've create WebAPI in .net (my first). Using this api to get object from db, query db etc is easy for me. Nothing new
But I'm wondering how to save an object using this webapi ?
I have a clinet application (tablet, phone, PC) that communicates with my webapi. From my application there is an possibility to save a user news. Now I need to save it in db. I use Azure SQL. Now how can I pass this object to API so I can save it ?
For my application I use C#/XAML
For my WebAPI I use .NET
I'm tring with this code:
HttpClient httpClient = new HttpClient();
String u = this.apiUrl + "sd/Localization/insert";
Uri uri = new Uri(u);
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, uri);
But I don't know how to send object ? Should I serialize it ? If yes how to send it via post.
// UPDATE
I've constructed this
HttpClient httpClient = new HttpClient();
String u = this.apiUrl + "sd/Localization/insert";
Uri uri = new Uri(u);
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, uri);
httpRequestMessage.Content = new StringContent("{'Name':'Foo', 'Surname':'Bar'}");
await httpClient.PostAsync(uri, httpRequestMessage.Content);
But in my API the variable is null
This is code from my api
// POST sd/Localization/insert
public void Post(string test)
{
Console.WriteLine(test);
}
The "test" variable is null.
What am I doing wrong ?
// UPDATE 2
using (HttpClient httpClient = new HttpClient())
{
String u = this.apiUrl + "sd/Localization/insert";
Uri uri = new Uri(u);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri)
{
Method = HttpMethod.Post,
Content = new StringContent("my own test string")
};
await httpClient.PostAsync(uri, request.Content);
}
Routing config
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "sd/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
after all your answers I've created this but still I get null on param in my api. Where is the mistake ?
WebAPI is really good at parsing data sent to it and converting it to .NET objects.
I am not used to using a C# client with WebAPI, but I'd try the following:
var client = new HttpClient();
client.PostAsJsonAsync<YourObjectType>("uri", yourObject);
Note: You need to use System.Net.Http (from assembly with the same name) as well as System.Net.Http.Formatting (also from assembly with the same name) for this.
The HttpRequestMessage class has a property named Content which is type of HttpContent (an abstract class). You can set the request body there. For example, you can set the JSON content there and then send it to the API:
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri) {
Content = new StringContent("{'Name':'Foo', 'Surname':'Bar'}")
};
You can also use the formatting feature and supply your CLR object to ObjectContent and delegate the serialization to the Formatter.
There are lots of samples on HttpClient and Web API here: http://blogs.msdn.com/b/henrikn/archive/2012/07/20/asp-net-web-api-sample-on-codeplex.aspx
Assuming you have an action method on your web API controller that supports a POST operation that is similiar to:
[HttpPost()]
public HttpResponseMessage Post(YourObjectType value)
{
try
{
var result = this.Repository.Add(value);
var response = this.Request.CreateResponse<YourObjectType>(HttpStatusCode.Created, result);
if (result != null)
{
var uriString = this.Url.Route(null, new { id = result.Id });
response.Headers.Location = new Uri(this.Request.RequestUri, new Uri(uriString, UriKind.Relative));
}
return response;
}
catch (ArgumentNullException argumentNullException)
{
throw new HttpResponseException(
new HttpResponseMessage(HttpStatusCode.BadRequest)
{
ReasonPhrase = argumentNullException.Message.Replace(Environment.NewLine, String.Empty)
}
);
}
}
You can use the HttpClient to serialize your object to JSON and POST the content to you controller method:
using (var client = new HttpClient())
{
client.BaseAddress = baseAddress;
client.Timeout = timeout;
using (var response = client.PostAsJsonAsync<YourObjectType>("controller_name", yourObject).Result)
{
if (!response.IsSuccessStatusCode)
{
// throw an appropriate exception
}
result = response.Content.ReadAsAsync<YourObjectType>().Result;
}
}
The NuGet package for ASP.NET MVC 4 (which provides you with the web
API framework) is available at http://nuget.org/packages/AspNetMvc.
The Web API reference at
http://msdn.microsoft.com/en-us/library/hh849329(v=vs.108).aspx.
I would also recommend taking a look at Creating a Web API that Supports CRUD Operations, which covers the scenarios you are describing, specifically the Creating a Resource section.
I think I found the solution thats why I'm posting this as answer not comment so any later discussion could be grouped.
If I send request like this
using(HttpClient client = new HttpClient()) {
await client.PostAsync(uri, new StringContent("my own string");
}
Than I can get it in my webapi from
await Request.Content.ReadAsStringAsync();
IMO this is not perfect solution but at least I'm on trace. I see that params from function definitione I can get only if they are in URL even when I send a POST request.
Probably this solution also will work (i didn't check it yet) when I use more complex objects then String.
ANy thoughts from someone. Do you think that this is good solution ?
I hope this would be what you are looking for.
I created a generic Post that will accept any object and post it
Client Side
public async Task<HttpResponseMessage> Post<T>(string requestUri, T newObject) where T : class
{
using (var client = new HttpClient())
{
client.BaseAddress = this.HttpClientAddress;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var content = JsonConvert.SerializeObject(newObject, this.JsonSerializerSettings);
var clientAsync = await client.PostAsync(requestUri, new StringContent(content, Encoding.UTF8, "application/json"));
clientAsync.EnsureSuccessStatusCode();
return clientAsync;
}
}
the call to this will be as simple as
public async Task<int> PostPerson(Models.Person person)
{
//call to the generic post
var response = await this.Post("People", person);
//get the new id from Uri api/People/6 <-- this is generated in the response after successful post
var st = response.Headers.Location.Segments[3];
//do whatever you want with the id
return response.IsSuccessStatusCode ? JsonConvert.DeserializeObject<int>(st) : 0;
}
Also, you can read the object after the post using ReadAsStringAsync() if your usecase requires so.
Server Side
// POST: api/People
public IHttpActionResult Post(Models.Person personDto)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var person = new Entities.Person
{
FirstName = personDto.FirstName,
LastName = personDto.LastName,
DateOfBirth = personDto.DateOfBirth,
PreferedLanguage = personDto.PreferedLanguage
};
_db.Persons.Add(person);
_db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = person.Id }, personDto);
}
I'm not familiar with the HttpClient (I believe it's .NET 4.5), but the concepts behind WebAPI are using standard RESTful constructs. If you want to insert an object via WebAPI, you will need to send a POST request to the service. You should put the contents of the object into the BODY of the request.
Add empty constructors to your webapi model people. This will save you all the time I just wasted trying to figure out why my object was null.
Serialization (and de-serialization i suppose) need default constructors.
This is my way.it's successfully.i hope it's helpful
Fisrt:is all library you must have.you can download from nuget
using Newtonsoft.Json; and
using Newtonsoft.Json.Linq;
Client :
HttpClient client = new HttpClient();
//this is url to your API server.in local.You must change when u pushlish on real host
Uri uri = new Uri("http://localhost/");
client.BaseAddress = uri;
//declared a JArray to save object
JArray listvideoFromUser = new JArray();
//sample is video object
VideoModels newvideo = new VideoModels();
//set info to new object..id/name...etc.
newvideo._videoId = txtID.Text.Trim();
//add to jArray
listvideoFromUser.Add(JsonConvert.SerializeObject(newvideo));
//Request to server
//"api/Video/AddNewVideo" is router of API .you must change with your router
HttpResponseMessage response =client.PostAsJsonAsync("api/Video/AddNewVideo", listvideoFromUser).Result;
if (response.IsSuccessStatusCode){
//show status process
txtstatus.Text=response.StatusCode.ToString();
}
else{
//show status process
txtstatus.Text=response.StatusCode.ToString();
}
Server side:
[Route("api/Video/AddNewVideo")]
[System.Web.Http.HttpPost]
public HttpResponseMessage AddNewVideo(JArray listvideoFromUser){
if (listvideoFromUser.Count > 0){
//DeserializeObject: that object you sent from client to server side.
//Note:VideoModels is class object same as model of client side
VideoModels video = JsonConvert.DeserializeObject<VideoModels>(listvideoFromUser[0].ToString());
//that is just method to save database
Datacommons.AddNewVideo(video);
//show status for client
HttpResponseMessage response = new HttpResponseMessage { StatusCode = HttpStatusCode.Created };
return response;
}
else{
HttpResponseMessage response = new HttpResponseMessage { StatusCode = HttpStatusCode.InternalServerError };
return response;
}
}
All done !

Categories

Resources