how to save an object using .net webapi - c#

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 !

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.

How to return whatever is returned from remote server?

I have the following WebClient code that is supposed my code acts as a proxy, and link to remote server, I would like to throw up whatever response that is returned from the remote server, how can I do so? I do not want to handle exceptions or anything, just merely throwing responses.
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/json";
Uri NODE_LOGIN_PATH = new Uri(URI_Combine(NodeAPI, "auth/login"));
string jsonString = JsonConvert.SerializeObject(login_details);
JObject data = JObject.Parse(await client.UploadStringTaskAsync(NODE_LOGIN_PATH, jsonString));
return data;
}
You appear to be using WebClient in an MVC 4 project, so you're on old stuff. Consider upgrading to HttpClient and ASP.NET Core.
The principle that you want goes something like this:
public class FooController : ApiController
{
public HttpResponseMessage Get()
{
// Do the HTTP call
var httpResponse = client.DoSomeRequest();
// Translate
var apiResponse = new HttpResponseMessage
{
StatusCode = httpResponse.StatusCode.Map(...),
Headers = httpResponse.Headers.Map(...),
Body = httpResponse.Body.Map(...),
};
// Return
return apiResponse;
}
}
So: do the request, and translate (map) it to the HttpResponseMessage (or IHttpActionResult, or ...) that your Web API platform requires.

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 ... ).

Trouble calling a ASP.NET MVC 4 WebApi from a Windows Store Application

I've got the following code running in a Windows Store application that is supposed to call one of my WebApis:
using (var client = new HttpClient())
{
var parms = new Dictionary<string, string>
{
{"vinNumber", vinNumber},
{"pictureType", pictureType},
{"blobUri", blobUri}
};
HttpResponseMessage response;
using (HttpContent content = new FormUrlEncodedContent(parms))
{
const string url = "http://URL/api/vinbloburis";
response = await client.PostAsync(url, content);
}
return response.StatusCode.ToString();
}
The WebApi code looks like this:
[HttpPost]
public HttpResponseMessage Post(string vinNumber, string pictureType, string blobUri)
{
var vinEntity = new VinEntity
{
PartitionKey = vinNumber,
RowKey = pictureType,
BlobUri = blobUri
};
_vinRepository.InsertOrUpdate(vinEntity);
return new HttpResponseMessage { Content = new StringContent("Success"), StatusCode = HttpStatusCode.OK };
}
Using Fiddler, I've observed the following ... here's what the request looks like:
POST http://URL/api/vinbloburis HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: URL
Content-Length: 113
Expect: 100-continue
vinNumber=vinNumber&pictureType=top&blobUri=https%3A%2F%2Fmystorage.blob.core.windows.net%2Fimages%2Fimage.png
But the response is an error with little/no information:
{"Message":"An error has occurred."}
I've even tried locally with the debugger attached to the WebApis and my Post method never catches.
Does anyone see something I've missed here? I feel like I'm looking right at it but not seeing it. I should add that I am able to call an HttpGet method while passing a parameter through the querystring. Right now the problem is only with this HttpPost.
Thanks!
UPDATE: Based on some good comments from folks I'm adding some more details.
I have the default routes configured for WebApis ...
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Consequently, I think /URL/api/vinbloburis should work. Additionally, as alluded above, I currently have this working with an HttpGet. Here's what's working in the Windows Store app to call the HttpGet WebApi ...
using (var client = new HttpClient())
{
using (var response = await client.GetAsync(uri))
{
if (response.IsSuccessStatusCode)
{
var sasUrl = await response.Content.ReadAsStringAsync();
sasUrl = sasUrl.Trim('"');
return sasUrl;
}
}
}
... and it's calling the following WebApi ...
[HttpGet]
public HttpResponseMessage Get(string blobName)
{
const string containerName = "images";
const string containerPolicyName = "policyname";
_helper.SetContainerPolicy(containerName, containerPolicyName);
string sas = _helper.GenerateSharedAccessSignature(blobName, containerName, containerPolicyName);
return new HttpResponseMessage
{
Content = new StringContent(sas),
StatusCode = HttpStatusCode.OK
};
}
I hope the additional information helps!
I copied your code, as is and I was getting a 404 error.
I changed the signature to
public HttpResponseMessage Post(FormDataCollection data)
and it worked.
You can also just do this,
public HttpResponseMessage Post(VinEntity vinEntity)
and the model binder will do the mapping work for you.
Rick Strahl has a post on the issue here http://www.west-wind.com/weblog/posts/2012/Sep/11/Passing-multiple-simple-POST-Values-to-ASPNET-Web-API
Have you turned on Internet Networking in your manifest?
It may be a Cross Domain Ajax Security issue. See JSONP info here. => http://json-p.org/

How to use System.Net.HttpClient to post a complex type?

I have a custom complex type that I want to work with using Web API.
public class Widget
{
public int ID { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
And here is my web API controller method. I want to post this object like so:
public class TestController : ApiController
{
// POST /api/test
public HttpResponseMessage<Widget> Post(Widget widget)
{
widget.ID = 1; // hardcoded for now. TODO: Save to db and return newly created ID
var response = new HttpResponseMessage<Widget>(widget, HttpStatusCode.Created);
response.Headers.Location = new Uri(Request.RequestUri, "/api/test/" + widget.ID.ToString());
return response;
}
}
And now I'd like to use System.Net.HttpClient to make the call to the method. However, I'm unsure of what type of object to pass into the PostAsync method, and how to construct it. Here is some sample client code.
var client = new HttpClient();
HttpContent content = new StringContent("???"); // how do I construct the Widget to post?
client.PostAsync("http://localhost:44268/api/test", content).ContinueWith(
(postTask) =>
{
postTask.Result.EnsureSuccessStatusCode();
});
How do I create the HttpContent object in a way that web API will understand it?
The generic HttpRequestMessage<T> has been removed. This :
new HttpRequestMessage<Widget>(widget)
will no longer work.
Instead, from this post, the ASP.NET team has included some new calls to support this functionality:
HttpClient.PostAsJsonAsync<T>(T value) sends “application/json”
HttpClient.PostAsXmlAsync<T>(T value) sends “application/xml”
So, the new code (from dunston) becomes:
Widget widget = new Widget()
widget.Name = "test"
widget.Price = 1;
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:44268");
client.PostAsJsonAsync("api/test", widget)
.ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode() );
You should use the SendAsync method instead, this is a generic method, that serializes the input to the service
Widget widget = new Widget()
widget.Name = "test"
widget.Price = 1;
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:44268/api/test");
client.SendAsync(new HttpRequestMessage<Widget>(widget))
.ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode() );
If you don't want to create the concrete class, you can make it with the FormUrlEncodedContent class
var client = new HttpClient();
// This is the postdata
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("Name", "test"));
postData.Add(new KeyValuePair<string, string>("Price ", "100"));
HttpContent content = new FormUrlEncodedContent(postData);
client.PostAsync("http://localhost:44268/api/test", content).ContinueWith(
(postTask) =>
{
postTask.Result.EnsureSuccessStatusCode();
});
Note: you need to make your id to a nullable int (int?)
Note that if you are using a Portable Class Library, HttpClient will not have PostAsJsonAsync method.
To post a content as JSON using a Portable Class Library, you will have to do this:
HttpClient client = new HttpClient();
HttpContent contentPost = new StringContent(argsAsJson, Encoding.UTF8,
"application/json");
await client.PostAsync(new Uri(wsUrl), contentPost).ContinueWith(
(postTask) => postTask.Result.EnsureSuccessStatusCode());
If you want the types of convenience methods mentioned in other answers but need portability (or even if you don't), you might want to check out Flurl [disclosure: I'm the author]. It (thinly) wraps HttpClient and Json.NET and adds some fluent sugar and other goodies, including some baked-in testing helpers.
Post as JSON:
var resp = await "http://localhost:44268/api/test".PostJsonAsync(widget);
or URL-encoded:
var resp = await "http://localhost:44268/api/test".PostUrlEncodedAsync(widget);
Both examples above return an HttpResponseMessage, but Flurl includes extension methods for returning other things if you just want to cut to the chase:
T poco = await url.PostJsonAsync(data).ReceiveJson<T>();
dynamic d = await url.PostUrlEncodedAsync(data).ReceiveJson();
string s = await url.PostUrlEncodedAsync(data).ReceiveString();
Flurl is available on NuGet:
PM> Install-Package Flurl.Http
After investigating lots of alternatives, I have come across another approach, suitable for the API 2.0 version.
(VB.NET is my favorite, sooo...)
Public Async Function APIPut_Response(ID as Integer, MyWidget as Widget) as Task(Of HttpResponseMessage)
Dim DesiredContent as HttpContent = New StringContent(JsonConvert.SerializeObject(MyWidget))
Return Await APIClient.PutAsync(String.Format("api/widget/{0}", ID), DesiredContent)
End Function
Good luck! For me this worked out (in the end!).
Regards,
Peter
I think you can do this:
var client = new HttpClient();
HttpContent content = new Widget();
client.PostAsync<Widget>("http://localhost:44268/api/test", content, new FormUrlEncodedMediaTypeFormatter())
.ContinueWith((postTask) => { postTask.Result.EnsureSuccessStatusCode(); });
In case someone like me didn't really understand what all above are talking about, I give an easy example which is working for me.
If you have a web api which url is "http://somesite.com/verifyAddress", it is a post method and it need you to pass it an address object. You want to call this api in your code. Here what you can do.
public Address verifyAddress(Address address)
{
this.client = new HttpClient();
client.BaseAddress = new Uri("http://somesite.com/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var urlParm = URL + "verifyAddress";
response = client.PostAsJsonAsync(urlParm,address).Result;
var dataObjects = response.IsSuccessStatusCode ? response.Content.ReadAsAsync<Address>().Result : null;
return dataObjects;
}
This is the code I wound up with, based upon the other answers here. This is for an HttpPost that receives and responds with complex types:
Task<HttpResponseMessage> response = httpClient.PostAsJsonAsync(
strMyHttpPostURL,
new MyComplexObject { Param1 = param1, Param2 = param2}).ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
//debug:
//String s = response.Result.Content.ReadAsStringAsync().Result;
MyOtherComplexType moct = (MyOtherComplexType)JsonConvert.DeserializeObject(response.Result.Content.ReadAsStringAsync().Result, typeof(MyOtherComplexType));
Make a service call like this:
public async void SaveActivationCode(ActivationCodes objAC)
{
var client = new HttpClient();
client.BaseAddress = new Uri(baseAddress);
HttpResponseMessage response = await client.PutAsJsonAsync(serviceAddress + "/SaveActivationCode" + "?apiKey=445-65-1216", objAC);
}
And Service method like this:
public HttpResponseMessage PutSaveActivationCode(ActivationCodes objAC)
{
}
PutAsJsonAsync takes care of Serialization and deserialization over the network

Categories

Resources