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.
I am trying to store documents to the server and i am uploading them from the client side using a form as an array of IFormFiles and then hitting the client controller and from the client controller i am getting an array of those documents and then Serializing them and sending them to the API end point as below.
public IActionResult UploadDocuments(Documents obj)
{
using (var client = new HttpClient())
{
var requestContent = new MultipartFormDataContent();
var jsonData = JsonConvert.SerializeObject(obj);
var contentString = new StringContent(jsonData, Encoding.UTF8);
requestContent.Add(contentString);
client.BaseAddress = new Uri("http://localhost:59104/");
var response = client.PostAsJsonAsync("api/Document", requestContent).Result;
if (response.IsSuccessStatusCode)
{
TempData["success"] = "Documents added Successfully";
return RedirectToAction("Documents", "Documents");
}
TempData["error"] = "Failed to add a document";
return RedirectToAction("Upload", "Documents");
}
}
When i upload the documents to the above controller, i am getting them but now the problem is receiving them on the API end point. If i remove the [FromBody] or [FromForm] above the API Controller tag, the APi endpoint is being hit but if either of those tags are not present i am receiving a null Documents object and an internal server error. Below is my API end point
public async Task<ActionResult<Documents>> AddDocuments([FromBody] Documents obj)
{
var documentsobj = HttpContext.Request.Form.Files;
//Do something with the document object
}
Is there a way i can receive that Document object from my API end point?
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);
}
I have a rest endpoint that accepts a single custom object parameter containing two properties.
Let's call the param InfoParam
public class InfoParam
{
public long LongVar { get; set; }
public string StringVar { get; set; }
}
My code I have is as follows:
infoParam.LongVar = 12345678;
infoParam.StringVar = "abc"
var myRequest = (HttpWebRequest)WebRequest.Create(url);
myRequest.Method = "POST";
var content = string.Empty;
using (var theResponse = (HttpWebResponse)MyRequest.GetResponse())
{
using (var stream = theResponse.GetResponseStream())
{
using (var sr = new StreamReader(stream))
{
content = sr.ReadToEnd();
}
}
}
So I have the InfoParam variable, with the two values, but I can't figure out where to pass it in to the REST endpoint.
You need to turn the object into a stream of bytes that can be added to the Request stream - which will in turn be sent as the HTTP POST body. The format of these bytes needs to match what the server expects. REST endpoints usually expect these bytes to resemble JSON.
// assuming you have added Newtonsoft.JSON package and added the correct using statements
using (StreamWriter writer = new StreamWriter(myRequest.GetRequestStream()) {
string json = JsonConvert.SerializeObject(infoParam);
writer.WriteLine(json);
writer.Flush();
}
You'll probably want to set various other request parameters, like the Content-Type header.
You have to write it int the `Content (and set content-type). Check out How to: Send data by using the WebRequest class
The recommendation is to use System.Net.Http.HttpClient instead.
Please note that you should know what content the server expects ('application/x-www-form-urlencoded`, json, etc.)
The following snippet is from POST JSON data over HTTP
// Construct the HttpClient and Uri. This endpoint is for test purposes only.
HttpClient httpClient = new HttpClient();
Uri uri = new Uri("https://www.contoso.com/post");
// Construct the JSON to post.
HttpStringContent content = new HttpStringContent(
"{ \"firstName\": \"Eliot\" }",
UnicodeEncoding.Utf8,
"application/json");
// Post the JSON and wait for a response.
HttpResponseMessage httpResponseMessage = await httpClient.PostAsync(
uri,
content);
// Make sure the post succeeded, and write out the response.
httpResponseMessage.EnsureSuccessStatusCode();
var httpResponseBody = await httpResponseMessage.Content.ReadAsStringAsync();
Debug.WriteLine(httpResponseBody);
In your case the content would be something like this
HttpStringContent content = new HttpStringContent(
JsonConvert.SerializeObject(infoParam), // using Json.Net;
UnicodeEncoding.Utf8,
"application/json");
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 !