How I can pass Json from Win Forms to MVC Controller - c#

I have MVC Controller given below:
public ActionResult ReceiveJson(string json)
{
//--
return Content(json, "application/json");
}
I created Windows Forms Application. In the application I want to pass Json to my MVC Controller.
I use:
string json = new JavaScriptSerializer().Serialize(myObject);
using (var client = new CookieAwareWebClient())
{
var values = new NameValueCollection
{
{ "username", login },
{ "password", haslo },
};
client.UploadValues("http://localhost/xxxxx/Login", values);
string link = "http://localhost/xxx/ReceiveJson";
client.Headers.Add("Content-Type", "application/json");
var response = client.UploadString(new Uri (link), "POST", json);
}
This code doesn't work. In ReceiveJson Controller I received null.
http://s22.postimg.org/9vxu2no9t/json.jpg
Can you tell me how I can pass Json from Win Forms to MVC Controller?
Thanks ;-)

Here is working code example:
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://localhost/CONTROLLER_NAME/ReceiveJson");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = new JavaScriptSerializer().Serialize(myObject);
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
// If you need to read response
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
}

have you checked your json value before send it?
Have you tried to uploadstring without adding extra header? In your action you receave string not an object. Here is a good example.

Looks like you violated some MVC conventions.
First you should post your values in request body not in JSON. It will look like this
using(var content = new MultipartFormDataContent())
{
content.Add(new StringContent(firstPropertyName), "firstValue");
content.Add(new StringContent(secondPropertyName), "secondValue");
client.PostAsync("https://mydomain.com/xxx/ReceiveJson", content);
}
Second you should mark your Action with [HttpPost] attribute
Third you should try to receive your viewModel not a string. It will simplify your code on the server
I believe it will help.

It's a good working version:
public ActionResult NamiaryWyZapis()
{
Stream jsonDane = Request.InputStream;
jsonDane.Seek(0, System.IO.SeekOrigin.Begin);
string json = new StreamReader(jsonDane).ReadToEnd();
//--
}

ANSWER: Via POST.
You need to serialize your object(on this case Persons) to json and make a post with a method like this one. (Person model must be accessible from both applications)
public async bool SendRequestAsync(string requestUrl, object data)
{
string json = JsonConvert.SerializeObject(obj, Formatting.Indented,
new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
try
{
HttpWebRequest request = WebRequest.Create(requestUrl) as HttpWebRequest;
if (request != null)
{
request.Accept = "application/json";
request.ContentType = "application/json";
request.Method = "POST";
using (var stream = new StreamWriter(await request.GetRequestStreamAsync()))
{
stream.Write(json);
}
using (HttpWebResponse response = await request.GetResponseAsync() as HttpWebResponse)
{
if (response != null && response.StatusCode != HttpStatusCode.OK)
throw new Exception(String.Format(
"Server error (HTTP {0}: {1}).",
response.StatusCode,
response.StatusDescription));
if (response != null)
{
Stream responseStream = response.GetResponseStream();
//return true or false depending on the ok
return GetResponseModel(responseStream);
}
}
}
}
catch (WebException ex)
{
var response = ex.Response;
Stream respStream = response.GetResponseStream();
//return true or false depending on the ok
return GetResponseModel(respStream);
}
catch (Exception e)
{
return false;
}
return false;
}
The GetResponseModel method returns the model that you want to read from the web if your POST was success. Then in your WinForms you can register that success if you want.
The controller method will look like this one
[HttpPost]
public ActionResult JsonMethod(Person p)
{
if(p != null)
return Json(true);
else return Json(false);
}
The body of your GetResponse could be like this one
public static T GetResponseModel<T>(Stream respStream) where T : class
{
if (respStream != null)
{
var respStreamReader = new StreamReader(respStream);
Task<string> rspObj = respStreamReader.ReadToEndAsync();
rspObj.Wait();
T jsonResponse = JsonConvert.DeserializeObject<T>(rspObj.Result);
return jsonResponse;
}
return default(T);
}

Related

C# POST request works on POSTMAN but not on C# HttpWebRequest

I'm getting code 400 only in C# and when I use post man I get 200!
It has the same properties.
I initally created the classes as JSONProperty attributes and still after decentralize I get code 400.
Found on fiddler innder exception -
message=parameters : The property 'Changedby' does not exist on type 'XXXXX.AzureAd.XXX.Types.NewDescriptionEntry'. Make sure to only use property names that are defined by the type.
The JSON in the debugging mode in C# after creating the classes - JSON mode.
// Serialize our concrete class into a JSON String
var stringPayload = await Task.Run(() =>
JsonConvert.SerializeObject(payload_transferIncident));
// build the URL we'll hit
var url = string.Format("https://XXXXXX", "YYYYY", id, "XXXX");
//create the request
var req = HttpWebRequest.CreateHttp(url);
//add in the cert we'll authenticate with
req.ClientCertificates.Add(IcmIncidentOperation.GetCert("XXXXXX"));
req.ContentType = "application/json";
req.Method = "POST";
if (req == null)
throw new ApplicationException(string.Format("Could not create the httprequest from the url:{0}", url));
try
{
using (var streamWriter = new StreamWriter(req.GetRequestStream()))
{
streamWriter.Write(stringPayload);
}
var httpResponse = (HttpWebResponse)req.GetResponse();
}
catch (Exception ex)
{
Console.WriteLine(ex);
var httpResponse = (HttpWebResponse)req.GetResponse();
}
Try this way using HttpRequest POST METHOD
try
{
var baseAddress = new Uri("Your base url");
using (var httpClient = new HttpClient
{
BaseAddress = baseAddress
})
{
var json =Newtonsoft.Json.JsonConvert.SerializeObject( payload);
using (var content = new StringContent( json, System.Text.Encoding.Default, "application/json"))
{
try
{
using (var response = await httpClient.PostAsync("end-point url method", content))
{
result = await response.Content.ReadAsStringAsync();
}
}
catch(Exception ex)
{
return ex.Message;
}
}
}
}
catch (Exception ex)
{
result = ex.Message;
}

Post data not being sent to backend api correctly?

Trying to run a post request and no data is being sent, even though passing it through? The backend is reporting no post data was sent and I've checked it doesn't seem to send it?
I have doubled checked everything but I don't understand why? StackOverflow keeps asking me for more description so sorry for the long explanation.
var response = HttpFactory.PerformHttpWebRequest("http://localhost:8000/api/cache"
new Dictionary<string, string>()
{
{ "item", Username },
{ "name", Name },
{ "picture", Picture },
{ "additional_data", JsonConvert.SerializeObject(MetaData) },
}, "POST");
private static HttpResponse PerformHttpWebRequest(
string url,
IDictionary<string, string> data = default,
string method = "GET"
)
{
if (method == "GET" && data != null)
{
url += "?" + string.Join("&", data.Select((x) => x.Key + "=" + x.Value));
}
LAST_PROCESSED = url;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = method;
request.ContentType = "application/json; charset=UTF-8";
request.Accept = "application/json";
if (data != null && method == "POST")
{
byte[] postData = Encoding.ASCII.GetBytes(string.Join("&", data.Select((x) => x.Key + "=" + x.Value)));
using (Stream stream = request.GetRequestStream())
{
stream.Write(postData, 0, postData.Length);
}
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
return new HttpResponse(url, response.StatusCode, reader.ReadToEnd());
}
}
catch (WebException we)
{
var response = (HttpWebResponse)we.Response;
if (response == null)
{
return new HttpResponse(url, default, default, we);
}
var reponseStream = new StreamReader(we.Response.GetResponseStream());
return new HttpResponse(url, response.StatusCode, reponseStream.ReadToEnd());
}
catch (Exception e)
{
return new HttpResponse(url, default, default, e);
}
}
You're setting request.ContentType = "application/json; charset=UTF-8"; but actually POSTing application/x-www-form-urlencoded.
Can you try changing that?

Returning a value from an async call within a PCL

I have a non PCL method that grabs data from a RESTful service which is then deserialised and returns the data back. It looks like this
public WeatherData GetWeather
{
get
{
if (!ftrackData.Online)
return new WeatherData();
string param = string.Format("lat={0}&lon={1}&APPID={2}", AppDelegate.Self.Latitude, AppDelegate.Self.Longitude, AppDelegate.Self.WeatherID);
var request = WebRequest.Create("http://api.openweathermap.org/data/2.5/forecast?" + param) as HttpWebRequest;
request.Method = "GET";
request.Accept = "application/json";
request.ContentType = "application/json";
string responseContent;
try
{
using (var response = request.GetResponse() as HttpWebResponse)
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
responseContent = reader.ReadToEnd();
}
}
var deserial = Deserialize<WeatherData>(responseContent);
return deserial;
}
catch (WebException ex)
{
Console.WriteLine("Deserialiser failed : {0}--{1}", ex.StackTrace, ex.Message);
return null;
}
}
}
(the data is coming from openweathermap)
I've moved this over to my PCL and come up with the following
public WeatherData GetWeather
{
get
{
var param = string.Format("lat={0}&lon={1}&APPID={2}", App.Self.Latitude, App.Self.Longitude, App.Self.WeatherID);
var request = WebRequest.Create("http://api.openweathermap.org/data/2.5/forecast?" + param) as HttpWebRequest;
request.Method = "GET";
request.Accept = "application/json";
request.ContentType = "application/json";
var Weather = new WeatherData();
string responseContent;
try
{
var asyncResult = request.BeginGetResponse(new AsyncCallback(s =>
{
var response = (s.AsyncState as WebRequest).EndGetResponse(s);
using (var reader = new StreamReader(response.GetResponseStream()))
{
responseContent = reader.ReadToEnd();
}
Weather = Deserialize<WeatherData>(responseContent);
}), request);
return Weather;
}
catch (WebException ex)
{
Debug.WriteLine("Deserialiser failed : {0}--{1}", ex.StackTrace, ex.Message);
return Weather;
}
}
}
The code builds without an issue, but is not awaiting before returning the weather data.
I've tried adding .AsyncWaitHandle.WaitOne() to the end of the BeginGetResponse but the Weather object is still returned before the call completes.
The return can't be added into the anonymous callback as the callback returns void.
I've also tried adding
if (asyncResult.IsCompleted)
return Weather;
but this will no compile as not all paths return a value.
How can get the return not to return until Weather has been filled from within the anonymous call back?

call HttpPost method from Client in C# code

I am new to MVC and C#, so sorry if this question seems too basic.
For a HttpPost Controller like below, how do to call this method directly from a client-side program written in C#, without a browser (NOT from a UI form in a browser with a submit button)? I am using .NET 4 and MVC 4.
I am sure the answer is somehwere on the web, but haven't found one so far. Any help is appreciated!
[HttpPost]
public Boolean PostDataToDB(int n, string s)
{
//validate and write to database
return false;
}
For example with this code in the server side:
[HttpPost]
public Boolean PostDataToDB(int n, string s)
{
//validate and write to database
return false;
}
You can use different approches:
With WebClient:
using (var wb = new WebClient())
{
var data = new NameValueCollection();
data["n"] = "42";
data["s"] = "string value";
var response = wb.UploadValues("http://www.example.org/receiver.aspx", "POST", data);
}
With HttpRequest:
var request = (HttpWebRequest)WebRequest.Create("http://www.example.org/receiver.aspx");
var postData = "n=42&s=string value";
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
With HttpClient:
using (var client = new HttpClient())
{
var values = new List<KeyValuePair<string, string>>();
values.Add(new KeyValuePair<string, string>("n", "42"));
values.Add(new KeyValuePair<string, string>("s", "string value"));
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("http://www.example.org/receiver.aspx", content);
var responseString = await response.Content.ReadAsStringAsync();
}
With WebRequest
WebRequest request = WebRequest.Create ("http://www.example.org/receiver.aspx");
request.Method = "POST";
string postData = "n=42&s=string value";
byte[] byteArray = Encoding.UTF8.GetBytes (postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream ();
dataStream.Write (byteArray, 0, byteArray.Length);
dataStream.Close ();
//Response
WebResponse response = request.GetResponse ();
Console.WriteLine (((HttpWebResponse)response).StatusDescription);
dataStream = response.GetResponseStream ();
StreamReader reader = new StreamReader (dataStream);
string responseFromServer = reader.ReadToEnd ();
Console.WriteLine (responseFromServer);
reader.Close ();
dataStream.Close ();
response.Close ();
see msdn
You can use
First of all you should return valid resutl:
[HttpPost]
public ActionResult PostDataToDB(int n, string s)
{
//validate and write to database
return Json(false);
}
After it you can use HttpClient class from Web Api client libraries NuGet package:
public async bool CallMethod()
{
var rootUrl = "http:...";
bool result;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_rootUrl);
var response= await client.PostAsJsonAsync(methodUrl, new {n = 10, s = "some string"});
result = await response.Content.ReadAsAsync<bool>();
}
return result;
}
You can also use WebClient class:
[HttpPost]
public Boolean PostDataToDB(int n, string s)
{
//validate and write to database
return false;
}
public async bool CallMethod()
{
var rootUrl = "http:...";
bool result;
using (var client = new WebClient())
{
var col = new NameValueCollection();
col.Add("n", "1");
col.Add("s", "2");
var res = await client.UploadValuesAsync(address, col);
string res = Encoding.UTF8.GetString(res);
result = bool.Parse(res);
}
return result;
}
If you decide to use HttpClient implementation. Do not create and dispose of HttpClient for each call to the API. Instead, re-use a single instance of HttpClient. You can achieve that declaring the instance static or implementing a singleton pattern.
Reference: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
How to implement singleton (good starting point, read the comments on that post): https://codereview.stackexchange.com/questions/149805/implementation-of-a-singleton-httpclient-with-generic-methods
Hopefully below code will help you
[ActionName("Check")]
public async System.Threading.Tasks.Task<bool> CheckPost(HttpRequestMessage request)
{
string body = await request.Content.ReadAsStringAsync();
return true;
}

WP8 HttpWebRequest Post Not Working

I have a Windows Phone Application and I I am trying to post data in JSON format to a WCF application. Although the connection is made, the server returns with a custom message with
This is the C# code:
ReportSightingRequest.Instance.Source = Source.IPhone;
var jsonData = JsonConvert.SerializeObject(ReportSightingRequest.Instance);
var uri = new Uri("urlGoesHere", UriKind.Absolute);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = jsonData.Length;
string received;
using (var response = (HttpWebResponse)(await Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null)))
{
using (var responseStream = response.GetResponseStream())
{
using (var sr = new StreamReader(responseStream))
{
received = await sr.ReadToEndAsync();
}
}
}
This is the WCF Interface:
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[Description("Description.")]
Response.Response ReportSighting(ReportSightingRequest sighting);
This is the implementation:
public Response ReportSighting(ReportSightingRequest sightingRequest)
{
var response = new Response();
if (sightingRequest == null || sightingRequest.TypeId == null)
{
response.Status = ResponseStatus.InvalidArguments;
response.Message = "Request is null or no type has been supplied.";
return response;
}
...
}
When I call the ReportSighting method form the phone, I get a "Request is null or no type has been supplied" message. The strange thing is that I AM sending a TypeId and the sightingRequest object on the WP8 side is definitely not null when i'm sending it. When I put a breakpoint on the jsonData, it has everything in it. The ReportSightingRequest object too is exactly the same as the ReportSightingRequest in the WCF application.
It almost feels like that the object isn't being serialized. That's the only thing I can think of.
Does anyone have any ideas/suggestions?
Update
I've noticed that i'm actually not sending over the object. Shawn Kendrot's Answer seems to make sense but when I integrate his code, it returns with a Not Found error.
Update
The following code works in a Console App:
var jsonData = "a hard coded JSON string here";
var uri = new Uri("a url goes here", UriKind.Absolute);
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
webRequest.Method = "POST";
webRequest.ContentType = "application/json; charset=utf-8";
webRequest.ContentLength = jsonData.Length;
webRequest.BeginGetRequestStream(ar =>
{
try
{
using (var os = webRequest.EndGetRequestStream(ar))
{
var postData = Encoding.UTF8.GetBytes(jsonData);
os.Write(postData, 0, postData.Length);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
webRequest.BeginGetResponse(
ar2 =>
{
try
{
using (var response = webRequest.EndGetResponse(ar2))
using (var reader = new StreamReader(response.GetResponseStream()))
{
var received = reader.ReadToEnd();
//Console.WriteLine(received);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}, null);
}, null);
Update
I have changed my code in WP8 to match that of Shawn Kendrot's solution. The problem which I am facing here is that I get a Not Found error message:
webRequest.BeginGetRequestStream(ar =>
{
try
{
using (var os = webRequest.EndGetRequestStream(ar))
{
var postData = Encoding.UTF8.GetBytes(jsonData);
os.Write(postData, 0, postData.Length);
}
}
catch (Exception ex)
{
MessageBox.Show("Unsuccessful");
}
webRequest.BeginGetResponse(
ar2 =>
{
try
{
using (var response = webRequest.EndGetResponse(ar2))
using (var reader = new StreamReader(response.GetResponseStream()))
{
var received = reader.ReadToEnd();
}
}
catch (Exception ex)
{
MessageBox.Show("Unsuccessful");
}
}, null);
}, null);
I get a:
{System.UnauthorizedAccessException: Invalid cross-thread access.
at MS.Internal.XcpImports.CheckThread()
at MS.Internal.XcpImports.MessageBox_ShowCore(String messageBoxText, String caption, UInt32 type)
at System.Windows.MessageBox.ShowCore(String messageBoxText, String caption, MessageBoxButton button)
at System.Windows.MessageBox.Show(String messageBoxText)
at Notify.Logic.WebServices.<>c_DisplayClass2.b_1(IAsyncResult ar2)
at System.Net.Browser.ClientHttpWebRequest.<>c_DisplayClass1d.b_1b(Object state2)}
When I try to do `MessageBox.Show(ex.Message);
Update
I have fixed the issue with the MessageBox.Show error message.
The webRequest.Headers object has the following:
{Content-Type: application/json; charset=utf-8;}
Your sightingRequest is null because you are not sending any data. To send data using a WebRequest, you need to use the BeginGetRequestStream method. This method allows you to package the data.
var webRequest= (HttpWebRequest)WebRequest.Create(uri);
webRequest.Method = "POST";
webRequest.ContentType = "application/json";
webRequest.ContentLength = jsonData.Length;
webRequest.BeginGetRequestStream(ar =>
{
try
{
using (Stream os = webRequest.EndGetRequestStream(ar))
{
var postData = Encoding.UTF8.GetBytes(jsonData);
os.Write(postData, 0, postData.Length);
}
}
catch (Exception ex)
{
// Do something, exit out, etc.
}
webRequest.BeginGetResponse(
ar2 =>
{
try
{
using (var response = webRequest.EndGetResponse(ar2))
using (var reader = new StreamReader(response.GetResponseStream()))
{
string received = reader.ReadToEnd();
}
}
catch (Exception ex)
{
// Do something, exit out, etc.
}
}, null);
}, null);

Categories