Hello I'm creating WebAPI and a windows8 metro app that communicates with this API.
I'll use simple example
API
public IEnumerable<string> Get() {
return new string[] { "value1", "value2" };
}
Application
using (HttpClient client = new HttpClient())
{
using (var response = await client.GetAsync(this.apiUri.GetUri("content", "Get")))
{
var result = await response.Content.ReadAsStringAsync();
}
}
Now the variable result is the response from API. But this is a string in form
"[\"value1\",\"value2\"]"
How can I parse/convert this ?
WebAPIs return JSON by default. You can request it to send XML, or use a JSON parser.
It's easy for you to deserialize back using Json.Net, in your case:
var json = "[\"value1\",\"value2\"]";
var values = JsonConvert.DeserializeObject<string[]>(json);
I use my class (MVCClient.cs) in silverlight to communicate with MVC WebAPI. In your case you'd just want to call :
DoGetMessage<string>(yourUrl, new DataDelegateArray<string>(yourCallbackFunction));
The lines that you are missing in your code would be :
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
T data = (T)serializer.ReadObject(stream);
Where T is string[].
MVCClient.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Text;
public class MVCClient
{
public delegate void DataDelegateArray<T>(T[] objects);
public delegate void DataDelegate<U>(U obj);
#region Communication Functions
public void DoPostMessage<T>(string queryURL, T item, ProcessPOSTResult<T> callback)
{
DoPostMessage<T, T>(queryURL, item, callback);
}
public void DoPostMessage<TPost, TReply>(string queryURL, TPost item, ProcessPOSTResult<TReply> callback)
{
#if SILVERLIGHT
Uri uri = new Uri(queryURL, UriKind.Absolute);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
request.BeginGetRequestStream(result =>
{
var req = (HttpWebRequest)result.AsyncState;
var stream = req.EndGetRequestStream(result);
if (stream != null)
{
var data = new
{
name = item
};
System.IO.MemoryStream ms = new System.IO.MemoryStream();
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(TPost));
serializer.WriteObject(stream, item);
stream.Close();
}
req.BeginGetResponse((requestResult) =>
{
var req2 = (HttpWebRequest)requestResult.AsyncState;
var response = req2.EndGetResponse(requestResult);
var responseStream = response.GetResponseStream();
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(TReply));
TReply responseItem = (TReply)serializer.ReadObject(responseStream);
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
{
callback(responseItem);
});
}, req);
}, request);
#endif
}
public void DoGetMessage<T>(string queryURL, DataDelegateArray<T> callback)
{
DoGetMessage<T[]>(queryURL, result => callback(result));
}
public void DoGetMessage<T>(string queryURL, DataDelegate<T> callback)
{
#if SILVERLIGHT
Uri uri = new Uri(queryURL, UriKind.Absolute);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "GET";
request.Accept = "text/json";
request.BeginGetResponse((result) =>
{
var response = request.EndGetResponse(result);
var stream = response.GetResponseStream();
if (stream != null)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
T data = (T)serializer.ReadObject(stream);
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
{
callback(data);
});
}
else
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
{
callback(default(T));
});
}, null);
#endif
}
#endregion
}
Related
I have an object.
I'am sending it this to my api project this way :
mymodel obj = new mymodel();
obj.prop = "this";
obj.prop2 = "prop2";
var content = JsonConvert.SerializeObject(obj);
var buffer = System.Text.Encoding.UTF8.GetBytes(content);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
string response = "";
using (HttpClient client = new HttpClient())
{
var rez = await client.PostAsync(uri + myenum.Insert, byteContent).ConfigureAwait(false);
response = rez.ToString();
}
In my api method i want to convert that string or http content again to model.
[ActionName("Insert")]
[HttpGet]
public bool Insert(string obj)
{
try
{
mymodel model = JsonConvert.DeserializeObject<mymodel>(obj);
How to handle object i'am sending with postasync in my api method ?
Any help ?
First you cannot use PostAsync on a HTTPGet method.
Second, I dont understand what you mean. If you are using json then you dont have to do anything. Just have a simple client method as such:
public async Task<TResult> PostAsync<TResult, TInput>(string uriString, TInput payload = null) where TInput : class
{
var uri = new Uri(uriString);
using (var client = GetHttpClient())
{
var jsonContent = JsonConvert.SerializeObject(payload, Formatting.Indented, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
HttpResponseMessage response = await client.PostAsync(uri, new StringContent(jsonContent, Encoding.UTF8, "application/json"));
if (response.StatusCode != HttpStatusCode.OK)
{
//Log.Error(response.ReasonPhrase);
return default(TResult);
}
var json = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TResult>(json);
}
}
And you can just add the same object to your API like
[ActionName("Insert")]
[HttpPost]
public bool Insert(YourObjectClass obj)
{
try
{
....code....
}
}
I want to add a record to the json service in my application. How can I do this via Service Url. Here is my code.
CustomerModel customer = new CustomerModel();
customer.Name = entryCompanyName.Text;
customer.Title = entryCompanyTitle.Text;
customer.PhoneNumber = entryTelephone.Text;
customer.FaxNumber = entryFax.Text;
customer.Email = entryEmail.Text;
customer.CityId = 6444;
string json = JsonConvert.SerializeObject(customer);
string sContentType = "application/json";
string path = "service url";
HttpClient Client = new HttpClient();
var task = Client.PostAsync(path, new StringContent(json.ToString(), Encoding.UTF8, sContentType));
I'm trying M. Wiśnicki's solution, but I took this error
I did not get an error when I added System.net :( Where do i make mistakes?
This worked for me
public static async Task<string> PostEntityToApi<T>(string yourMethodUrl, T yourModel)
{
try
{
if (_httpClient == null)
{
_httpClient = new HttpClient { BaseAddress = new Uri(yourWebSiteUrl) };
}
var stringContentInput = new StringContent(JsonConvert.SerializeObject(dto), Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(new Uri(yourWebSiteUrl. + apiUrl), stringContentInput);
if (!response.IsSuccessStatusCode)
{
throw new Exception(response.StatusCode.ToString());
}
var stringAsync = await response.Content.ReadAsStringAsync();
LoggingManager.Error("Received error response: " + stringAsync);
return stringAsync;
}
catch (Exception exception)
{
return null;
}
}
You can use WebRequest, this sample working for me, i use it in my app.
This is System.Net.WebRequest class, here you find doc.
public async Task<string> PostSample(object data, string uri)
{
// Create an HTTP web request using the URL:
var request = (HttpWebRequest) WebRequest.Create(new Uri(uri));
request.ContentType = "application/json";
request.Method = "POST";
var itemToSend = JsonConvert.SerializeObject(data);
using (var streamWriter = new StreamWriter(await request.GetRequestStreamAsync()))
{
streamWriter.Write(itemToSend);
streamWriter.Flush();
streamWriter.Dispose();
}
// Send the request to the server and wait for the response:
using (var response = await request.GetResponseAsync())
{
// Get a stream representation of the HTTP web response:
using (var stream = response.GetResponseStream())
{
var reader = new StreamReader(stream);
var message = JsonConvert.DeserializeObject<string>(reader.ReadToEnd());
return message;
}
}
}
I have the following web api client which sends data to server using json and gzip:
public void Remote_Push(BlockList Blocks)
{
// Pushes pending records to the remote server
using (var Client = new HttpClient())
{
Client.BaseAddress = new Uri(Context.ServerUrl);
Client.DefaultRequestHeaders.Accept.Clear();
Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var Content = JsonCompress(Blocks);
var T1 = Client.PostAsync("SyncPush/", Content); T1.Wait();
T1.Result.EnsureSuccess();
}
}
private static ByteArrayContent JsonCompress(object Data)
{
// Compress given data using gzip
var Bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(Data));
using (var Stream = new MemoryStream())
{
using (var Zipper = new GZipStream(Stream, CompressionMode.Compress, true)) Zipper.Write(Bytes, 0, Bytes.Length);
var Content = new ByteArrayContent(Stream.ToArray());
Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
Content.Headers.ContentEncoding.Add("gzip");
return Content;
}
}
On the server, I have created following action in web api controller:
[HttpPost]
public void SyncPush([FromBody]BlockList Blocks)
{
var Context = SyncCreateContext();
var Sync = new Processor(Context);
Sync.ServerPush(Blocks);
}
Previously, I have used PostAsJsonAsync on the client and it worked fine.
Now, I have switched to ByteArrayContent and gzip and no longer works, the Blocks is always null on the server.
What am I missing here, what is wrong or could be the problem?
Here is a sample console application to do what you are trying to do.
/*using System;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Newtonsoft.Json;
using WebApi.Models;*/
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press any key to POST");
Console.ReadLine();
RemotePush(new BlockList());
Console.ReadLine();
}
public static async void RemotePush(BlockList blocks)
{
try
{
using (var client = new HttpClient())
{
try
{
Console.WriteLine("Please wait.");
client.BaseAddress = new Uri("http://localhost:52521/Home/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var content = JsonCompress(blocks);
var response = await client.PostAsync("SyncPush/", content);
using (var stream = await response.Content.ReadAsStreamAsync())
{
using (var streamReader = new StreamReader(stream))
{
Console.WriteLine(streamReader.ReadToEnd());
}
}
Console.WriteLine("Done.");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static MultipartFormDataContent JsonCompress(object data)
{
var bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data));
var stream = new MemoryStream();
using (var zipper = new GZipStream(stream, CompressionMode.Compress, true))
{
zipper.Write(bytes, 0, bytes.Length);
}
MultipartFormDataContent multipartContent = new MultipartFormDataContent();
multipartContent.Add(new StreamContent(stream), "gzipContent");
return multipartContent;
}
}
My controller is like this.
[System.Web.Mvc.HttpPost]
public JsonResult SyncPush(BlockList content)
{
try
{
if (content != null)
{
return Json("success", JsonRequestBehavior.AllowGet);
}
return Json("failed due to null", JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json("failed " + ex.Message, JsonRequestBehavior.AllowGet);
}
}
just FYI, since .NET Core is not covered and this question is still relevant working .NET Core code. I used brotli, since that is a widely accepted standard today.
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Net.Http.Headers;
using System.IO.Compression;
public static class CompressedJsonHelper
{
private static readonly Lazy<JsonSerializerOptions>
Options = new(() =>
{
var opt = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
//opt.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
return opt;
});
public static HttpContent ToJson(this object data, bool noCompress = false)
{
if (noCompress)
{
ByteArrayContent byteContent = new (ToBytes(data));
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
return byteContent;
}
MemoryStream memoryStream = new ();
BrotliStream compress = new (memoryStream, CompressionLevel.Optimal, true);
StreamContent streamContent = new (memoryStream);
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
streamContent.Headers.ContentEncoding.Add("brotli");
JsonSerializer.Serialize(compress, data, Options.Value);
compress.Flush();
memoryStream.Position = 0;
return streamContent;
}
private static byte[] ToBytes(this object data) => JsonSerializer.SerializeToUtf8Bytes(data, Options.Value);
}
and the httpClient code:
HttpRequestMessage request = new(HttpMethod.Post, $"{yourbaseurl}/{path}")
{
Content = json.ToJson()
};
await _httpClient.SendAsync(request, ...) etc
I want to post a jsonobject to my webapi. Using normal C# code i would use PostAsJsonAsync on my httpClient object. But that doesn't seem to be supported with xamarin. So my question is how do i post json to my api using xamarin webclient or webrequest?
Here is my code right now that returns null...
protected async override void OnResume()
{
base.OnResume();
var clientRequest = new ResourceByNameRequest
{
Name = "G60",
UserId = "1"
};
HttpContent myContent = new StringContent(clientRequest.ToString());
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("XXX");
var cancellationToken = new CancellationToken();
var response = client.PostAsync("/api/Resource/ResourceByName", myContent, cancellationToken).Result;
var result = await response.Content.ReadAsStreamAsync();
//return result;
}
}
catch (Exception)
{
throw;
}
}
Try something like this:
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
//...
protected override void OnResume()
{
var request = HttpWebRequest.Create("Your_URL_XXX");
request.ContentType = "application/json";
request.Method = "POST";
var clientRequest = new ResourceByNameRequest
{
Name = "G60",
UserId = "1"
};
using (var writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(clientRequest.ToString());
}
try
{
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
string error = "";
if (response.StatusCode != HttpStatusCode.OK)
error = string.Format("Error fetching data. Server returned status code: {0} | Description: {1}", response.StatusCode, response.StatusDescription);
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var content = reader.ReadToEnd();
if (string.IsNullOrWhiteSpace(content))
{
strResponse = "Response contained empty body...";
}
else
{
var cont = JObject.Parse(content);
YOUR_OBJECT_RESPONSE.PROP1 = cont["Prop1"].NullSafeToString();
YOUR_OBJECT_RESPONSE.PROP2 = cont["Prop2"].NullSafeToString();
//...
}
}
}
}
catch (WebException wex)
{
var pageContent = new StreamReader(wex.Response.GetResponseStream()).ReadToEnd();
}
}
How I can convert my traditional HttpWebRequest "POST" call with Async / Await pattern, Here with this I am attaching my current code, Any one please help me to convert this code using Async / Await pattern for windows phone 8.
public void GetEnvironmentVariables(Action<Credentials> getResultCallback, Action<Exception> getErrorCallback)
{
CredentialsCallback = getResultCallback;
ErrorCallback = getErrorCallback;
var uri = new Uri(BaseUri);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
var jsonObject = new JObject
{
new JProperty("apiKey",_api),
new JProperty("affiliateId",_affid),
};
var serializedResult = JsonConvert.SerializeObject(jsonObject);
byte[] requestBody = Encoding.UTF8.GetBytes(serializedResult);
request.BeginGetRequestStream(GetRequestStreamCallback, new object[] { request, requestBody });
}
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
var request = (HttpWebRequest)((object[])asynchronousResult.AsyncState)[0];
using (var postStream = request.EndGetRequestStream(asynchronousResult))
{
var byteArray = (byte[])((object[])asynchronousResult.AsyncState)[1];
// Write to the request stream.
postStream.Write(byteArray, 0, byteArray.Length);
}
request.BeginGetResponse(GetResponseCallback, request);
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
var request = (HttpWebRequest)asynchronousResult.AsyncState;
try
{
var response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
if (response != null)
{
var reader = new StreamReader(response.GetResponseStream());
string responseString = reader.ReadToEnd();
Credentails = JsonConvert.DeserializeObject<Credentials>(responseString);
if (Credentails != null && string.IsNullOrEmpty(Credentails.Err))
CredentialsCallback(Credentails);
else
{
if (Credentails != null)
ErrorCallback(new Exception(string.Format("Error Code : {0}", StorageCredentails.Err)));
}
}
}
catch (WebException we)
{
var reader = new StreamReader(we.Response.GetResponseStream());
string responseString = reader.ReadToEnd();
Debug.WriteLine(responseString);
ErrorCallback(we);
}
}
Since Windows Phone 8 doesn't seem to offer the TAP methods you need such as GetRequestStreamAsync the first thing to do is write a little wrapper to provide them for yourself:
public static class WebRequestAsyncExtensions
{
public static Task<Stream> GetRequestStreamAsync(this WebRequest request)
{
return Task.Factory.FromAsync<Stream>(
request.BeginGetRequestStream, request.EndGetRequestStream, null);
}
public static Task<WebResponse> GetResponseAsync(this WebRequest request)
{
return Task.Factory.FromAsync<WebResponse>(
request.BeginGetResponse, request.EndGetResponse, null);
}
}
Note the use of Task.Factory.FromAsync - this is the preferred way to get an await-friendly wrapper around an APM-based async API such as those offered by WebRequest. This is far more efficient than using Task.Factory.StartNew as suggested by someone else, because that would spin up a new thread, whereas this won't need to.
With this in place, you can now write your code in the same way you would on platforms where these TAP-style methods are available (e.g. Windows 8 store apps, desktop apps, etc.):
public async Task GetEnvironmentVariablesAsync(Action<Credentials> getResultCallback, Action<Exception> getErrorCallback)
{
CredentialsCallback = getResultCallback;
ErrorCallback = getErrorCallback;
var uri = new Uri(BaseUri);
var request = (HttpWebRequest) WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
var jsonObject = new JObject
{
new JProperty("apiKey",_api),
new JProperty("affiliateId",_affid),
};
var serializedResult = JsonConvert.SerializeObject(jsonObject);
byte[] requestBody = Encoding.UTF8.GetBytes(serializedResult);
// ASYNC: using awaitable wrapper to get request stream
using (var postStream = await request.GetRequestStreamAsync())
{
// Write to the request stream.
// ASYNC: writing to the POST stream can be slow
await postStream.WriteAsync(requestBody, 0, requestBody.Length);
}
try
{
// ASYNC: using awaitable wrapper to get response
var response = (HttpWebResponse) await request.GetResponseAsync();
if (response != null)
{
var reader = new StreamReader(response.GetResponseStream());
// ASYNC: using StreamReader's async method to read to end, in case
// the stream i slarge.
string responseString = await reader.ReadToEndAsync();
Credentails = JsonConvert.DeserializeObject<Credentials>(responseString);
if (Credentails != null && string.IsNullOrEmpty(Credentails.Err))
CredentialsCallback(Credentails);
else
{
if (Credentails != null)
ErrorCallback(new Exception(string.Format("Error Code : {0}", StorageCredentails.Err)));
}
}
}
catch (WebException we)
{
var reader = new StreamReader(we.Response.GetResponseStream());
string responseString = reader.ReadToEnd();
Debug.WriteLine(responseString);
ErrorCallback(we);
}
}
Note the four lines with // ASYNC: comments - these show where I've made changes. I've collapsed your method down to one, because that's a) possible once you're using async and await and b) much easier than trying to pass things from one method to the next using state arguments.
Notice that the second and fourth of these actually makes async some things you were previously doing synchronously: writing data into the request stream, and reading data out of the response stream. For a small request this probably doesn't matter, but if large amounts of data are being transferred, a synchronous call to Write or ReadToEnd may block. Fortunately, although Windows Phone 8 appears to be missing the TAP methods on WebRequest, it does offer them on Stream and StreamReader so this works without needing to write any extension methods.
I'm new to the community, so here goes my first post. In this case, you can return anytype using a generic Task. This has worked well for me in the past.
Server Side
public class MyController : ApiController
{
public Task<string> PostAsync()
{
return Task.Factory.StartNew(() =>
{
return "populate me with any type and data, but change the type in the response signature.";
});
}
}
Client Side
public class HomeController : Controller
{
public Task<ViewResult> Index()
{
return Task.Factory.StartNew(() =>
{
var model = "use a provider, get some data, or something";
return View(model);
});
}
}
This should do the job:
public async void GetEnvironmentVariables(Action<Credentials> getResultCallback, Action<Exception> getErrorCallback) {
CredentialsCallback = getResultCallback;
ErrorCallback = getErrorCallback;
var uri = new Uri(BaseUri);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
var jsonObject = new JObject {
new JProperty("apiKey", _api),
new JProperty("affiliateId", _affid),
};
var serializedResult = JsonConvert.SerializeObject(jsonObject);
var requestBody = Encoding.UTF8.GetBytes(serializedResult);
var requestStream = request.GetRequestStream();
requestStream.Write(requestBody, 0, requestBody.Length);
await GetResponse(request);
}
private async Task GetResponse(WebRequest request) {
Stream resStream = null;
try {
var response = await request.GetResponseAsync();
if (response == null) {
return;
}
resStream = response.GetResponseStream();
if (resStream == null) {
return;
}
var reader = new StreamReader(resStream);
var responseString = await reader.ReadToEndAsync();
Credentails = JsonConvert.DeserializeObject<Credentials>(responseString);
if (Credentails != null && string.IsNullOrEmpty(Credentails.Err)) {
CredentialsCallback(Credentails);
}
else {
if (Credentails != null) {
ErrorCallback(new Exception(string.Format("Error Code : {0}", StorageCredentails.Err)));
}
}
}
catch (WebException we) {
if (resStream != null) {
var reader = new StreamReader(resStream);
var responseString = reader.ReadToEnd();
Debug.WriteLine(responseString);
}
ErrorCallback(we);
}
}