WebInvoke Parameter is NULL - json

I have a service where the operation contract looks like the following. I have a WebInvoke attribute and the method is set to POST. I do have a UriTemplate. The actual service method name is SaveUser. I am trying to pass in a User object (a data contract with properties annotated as data member attributes).
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "SaveUser", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json)]
User SaveUser(User user);
The client looks like the following. For simplicity I have excluded the token and authorization etc.:
using (WebClient webClient = new WebClient())
{
try
{
Random r = new Random();
var partitionKey = Guid.NewGuid().ToString();
var rowKey = r.Next(999900, 999999).ToString();
User u = new User()
{
UserId = partitionKey,
FirstName = "First-" + DateTime.Now.Ticks.ToString(),
LastName = "Last-" + DateTime.Now.Ticks.ToString(),
LoginName = rowKey,
Password = "password1",
PayPalEmailAddress = "First" + DateTime.Now.Ticks.ToString() + "#verascend.com",
PhoneNumber = "+1206" + r.Next(1234567, 9999999).ToString()
};
string url = serviceBaseUrl + "/SaveUser";
webClient.Headers["Content-type"] = "application/json; charset=utf-8";
// webClient.Headers[HttpRequestHeader.Authorization] = authToken;
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(User));
using (var memStream = new MemoryStream())
{
ser.WriteObject(memStream, u);
Debug.WriteLine("-------------> "+ByteArrayToString(memStream.ToArray()));
webClient.UploadData(url, "POST", memStream.ToArray());
}
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
string responseText = string.Empty;
using (Stream responseStream = ((HttpWebResponse)ex.Response).GetResponseStream())
{
using (StreamReader streamReader = new StreamReader(responseStream))
{
responseText = streamReader.ReadToEnd();
}
}
throw new Exception(responseText);
}
else
{
throw new Exception(ex.Message.ToString());
}
}
}
Problem: The service method (actual service) is receiving the param (User) as NULL. What am I doing wrong? I tried adding the known type in the service contract but no luck.

Your problem is that you define your operation to have a wrapped request. That means that the parameter, instead of being sent as a "plain" JSON object, must be wrapped in a JSON object, and the member name must correspond to the parameter name (in your case, user). The code below does the wrapping; you can see that with that the parameter now is properly received by the server. Another option would be to change the BodyStyle property to Bare instead of WrappedRequest as you have (in which case you'd need to send the plain object to the service operation).
public class StackOverflow_12452466
{
[ServiceContract]
public interface ITest
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "SaveUser", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json)]
User SaveUser(User user);
}
public class Service : ITest
{
public User SaveUser(User user)
{
Console.WriteLine("User: {0}", user);
return user;
}
}
public class User
{
public string UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string LoginName { get; set; }
public string Password { get; set; }
public string PayPalEmailAddress { get; set; }
public string PhoneNumber { get; set; }
public override string ToString()
{
return string.Format("Id={0},First={1},Last={2},Login={3},Pwd={4},PayPal={5},Phone={6}",
UserId, FirstName, LastName, LoginName, Password, PayPalEmailAddress, PhoneNumber);
}
}
public static void Test()
{
string serviceBaseUrl = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(serviceBaseUrl));
host.AddServiceEndpoint(typeof(ITest), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
host.Open();
Random r = new Random();
User u = new User()
{
UserId = "partitionKey",
FirstName = "First-" + DateTime.Now.Ticks.ToString(),
LastName = "Last-" + DateTime.Now.Ticks.ToString(),
LoginName = "rowKey",
Password = "password1",
PayPalEmailAddress = "First" + DateTime.Now.Ticks.ToString() + "#verascend.com",
PhoneNumber = "+1206" + r.Next(1234567, 9999999).ToString()
};
string url = serviceBaseUrl + "/SaveUser";
WebClient webClient = new WebClient();
webClient.Headers["Content-type"] = "application/json; charset=utf-8";
Func<byte[], string> ByteArrayToString = (b) => Encoding.UTF8.GetString(b);
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(User));
try
{
using (var memStream = new MemoryStream())
{
byte[] wrappingStart = Encoding.UTF8.GetBytes("{\"user\":");
memStream.Write(wrappingStart, 0, wrappingStart.Length);
ser.WriteObject(memStream, u);
byte[] wrappingEnd = Encoding.UTF8.GetBytes("}");
memStream.Write(wrappingEnd, 0, wrappingEnd.Length);
Debug.WriteLine("-------------> " + ByteArrayToString(memStream.ToArray()));
webClient.UploadData(url, "POST", memStream.ToArray());
}
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
string responseText = string.Empty;
using (Stream responseStream = ((HttpWebResponse)ex.Response).GetResponseStream())
{
using (StreamReader streamReader = new StreamReader(responseStream))
{
responseText = streamReader.ReadToEnd();
}
}
throw new Exception(responseText);
}
else
{
throw new Exception(ex.Message.ToString());
}
}
}
}

Related

Deserialize json shows null in xamarin forms

Hi I have a Login API which I am using to login though my xamarin.forms app.
I will post my username and password and in return I am getting some data.Now Iam facing some issues at deserialization of json. Iam getting data at my resultJson but I cant deserialize it. Help me.
My Json :
[
{
"Result":true,
"ID":"fc938df0",
"LoginName":"test",
"UserName":"test",
"ConnectionString":"MSSQLSERVER;Initial Catalog=Test1;User ID=db;Password=db#2018",
"UserProfileID":"fc938df0"
}
]
My API Call class which have deserialization of Json.
public T APICallResult<T>()
{
try
{
Device.BeginInvokeOnMainThread(() =>
{
if (loadingIndicator != null)
{
loadingIndicator.IsRunning = true;
loadingIndicator.IsVisible = true;
}
});
var client = new HttpClient { BaseAddress = baseAddress };
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var req = new HttpRequestMessage(HttpMethod.Post, apiurl);
req.Content = new StringContent(postdata, Encoding.UTF8, "application/json");
string stringObtained = "";
Task<string> task = Task.Run(async () => await Threading(client, req));
task.Wait();
stringObtained = task.Result;
var jsonObtained = Regex.Unescape(stringObtained);
int startIndex = jsonObtained.IndexOf('[');
int endIndex = jsonObtained.LastIndexOf(']');
int length = endIndex - startIndex + 1;
var resultJSON = jsonObtained.Substring(startIndex, length);
T resultObject;//Generic type object
try
{
//**Deserializing**
resultObject = JsonConvert.DeserializeObject<T>(resultJSON);//, settings);
removeLoadingAnimation();
return resultObject;
}
catch (Exception e)
{
List<ErrorMessageData> errorMessages = JsonConvert.DeserializeObject<List<ErrorMessageData>>(resultJSON);
errorMessage = errorMessages[0];
removeLoadingAnimation();
return default(T);
}
}
catch (Exception e)
{
errorMessage = new ErrorMessageData();
errorMessage.Flag = false;
errorMessage.Message = e.Message;
removeLoadingAnimation();
return default(T);
}
}
My API call at login class
string postdataForLogin = "{\"userName\":\"" + userName.Text + "\",\"password\":\"" + password.Text + "\",\"RequestURL\":\"" + CommonValues.RequestURL + "\"}";
APICall callForLogin = new APICall("/API/LoginMobile/HomeLogin", postdataForLogin, loadingIndicator);
try
{
List<LoginData> resultObjForLogin = callForLogin.APICallResult <List<LoginData>>();
if (resultObjForLogin != null)
{
LoginData loginData = new LoginData();
loginData = resultObjForLogin[0];
Settings.userID = loginData.UserProfileID;
Settings.connectionString = loginData.ConnectionString;
if (loginData.Result)
{
Device.BeginInvokeOnMainThread(async () =>
{
Navigation.InsertPageBefore(new MainPage(), this);
await Navigation.PopAsync();
});
}
My DataModel
public class LoginData
{
public bool Result { get; set; }
public string ID { get; set; }
public string UserProfileID { get; set; }
public string LoginName { get; set; }
public string UserName { get; set; }
public string ConnectionString { get; set; }
}
Its seems strange, My problem solved after downgrading my xamarin.forms from latest version to pre release 4.0.0.169046- pre5. I think its a xamarin forms bug

Xamarin JSON Deserialize

I created a HTTPWebRequest to check if the username and password of the user is correct. If the username and password of the user is correct it will return a JSON Array with the ContactID of the user. I tried to deserialize the JSON but I failed to get the actual data. I want to get the Contact id and send the data to a variable of the next page.
The output of the JSON when the username and password is correct:
[{"ContactID":"1"}]
My code:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Input;
using TBSMobileApplication.Data;
using TBSMobileApplication.View;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace TBSMobileApplication.ViewModel
{
public class LoginPageViewModel : INotifyPropertyChanged
{
void OnProperyChanged(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
public string username;
public string password;
public string Username
{
get { return username; }
set
{
username = value;
OnProperyChanged(nameof(Username));
}
}
public string Password
{
get { return password; }
set
{
password = value;
OnProperyChanged(nameof(Password));
}
}
public ICommand LoginCommand { get; set; }
public LoginPageViewModel()
{
LoginCommand = new Command(OnLogin);
}
public void OnLogin()
{
if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password))
{
MessagingCenter.Send(this, "Login Alert", Username);
}
else
{
var current = Connectivity.NetworkAccess;
if (current == NetworkAccess.Internet)
{
var link = "http://192.168.1.25:7777/TBS/test.php?User=" + Username + "&Password=" + Password;
var request = HttpWebRequest.Create(string.Format(#link));
request.ContentType = "application/json";
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
{
Console.Out.WriteLine("Error fetching data. Server returned status code: {0}", response.StatusCode);
}
else
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var content = reader.ReadToEnd();
if (content.Equals("[]") || string.IsNullOrWhiteSpace(content) || string.IsNullOrEmpty(content))
{
MessagingCenter.Send(this, "Http", Username);
}
else
{
var usr = JsonConvert.DeserializeObject(content);
App.Current.MainPage.Navigation.PushAsync(new DatabaseSyncPage(), true);
}
}
}
}
}
else
{
MessagingCenter.Send(this, "Not Connected", Username);
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
Modify your code else block like below
if (content.Equals("[]") || string.IsNullOrWhiteSpace(content) || string.IsNullOrEmpty(content))
{
MessagingCenter.Send(this, "Http", Username);
}
else
{
var response = JsonConvert.DeserializeObject<List<LoggedInUser>>(content);
var contactId=response[0].ContactID;
//response have your ContactID value. Try to debug & see.
App.Current.MainPage.Navigation.PushAsync(new DatabaseSyncPage(), true);
}
Create one another public class to deserialize your response
public class LoggedInUser
{
public string ContactID { get; set; }
}
If you have more than 1 record in result(as you asked this in comment below)
you can get them using loops
for (int i = 0; i < response.Count; i++)
{
var item = response[i];
var contactId = item.ContactId;
}
Hope it help you.
JSON Response object is not looking standard format for output result. Whatever for JSON deserialization you should create separate class as per below code.
public class RootObject
{
public string ContactID { get; set; }
}
Public Void ServiceRequest()
{
var content = reader.ReadToEnd();
if(!String.IsNullOrEmpty(content)
{
var response = JsonConvert.DeserializeObject<RootObject>(content);
}
}
I hope it will be useful.

Unable to deserialize json array using wcf service

I'm trying to DeSerialize data in json array using wcf service in the project.
The data is fetched and can be noticed in the debugging but i'm unable to deserialize, or something else that I'm mistaken. Below is the code that I've tried to deserialize.
Note:- I've separately run the wcf application and its returning json array in correct format with the actual result.
HotelServiceClient.cs
public class HotelServiceClient
{
private string BASE_URL = "http://localhost:50540/ServiceHotel.svc/";
public List<HotelInfo> findall()
{
try
{
var webClient = new WebClient();
var json = webClient.DownloadString(BASE_URL + "findall");
var javaScriptJson = new JavaScriptSerializer();
return javaScriptJson.Deserialize<List<HotelInfo>>(json);
}
catch
{
return null;
}
}
HotelInfo.cs
public class HotelInfo
{
private int _hotelid;
private string _hotelname;
private string _hoteldesc;
private string _hotelprice;
private byte[] _hotelpicture;
[Key]
[Display(Name = "Id")]
public int Hotelid
{
get
{
return _hotelid;
}
set
{
_hotelid = value;
}
}
[Display(Name = "Name")]
public string Hotelname
{
get
{
return _hotelname;
}
set
{
_hotelname = value;
}
}
[Display(Name = "description")]
public string Hoteldesc
{
get
{
return _hoteldesc;
}
set
{
_hoteldesc = value;
}
}
[Display(Name = "price")]
public string Hotelprice
{
get
{
return _hotelprice;
}
set
{
_hotelprice = value;
}
}
[Display(Name = "picture")]
public byte[] Hotelpicture
{
get
{
return _hotelpicture;
}
set
{
_hotelpicture = value;
}
}
}
WebService
Hotel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace CRUDwithHotels
{
public class Hotel
{
public int Id { get; set; }
public string Name { get; set; }
public string description { get; set; }
public string price { get; set; }
public byte[] picture { get; set; }
}
}
IServiceHotel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace CRUDwithHotels
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IServiceHotel" in both code and config file together.
[ServiceContract]
public interface IServiceHotel
{
[OperationContract]
[WebInvoke(Method ="GET", UriTemplate ="findall", ResponseFormat =WebMessageFormat.Json)]
List<Hotel> findall();
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "find/{id}", ResponseFormat = WebMessageFormat.Json)]
Hotel find(string id);
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "create", ResponseFormat = WebMessageFormat.Json, RequestFormat =WebMessageFormat.Json)]
bool create(Hotel hotel);
[OperationContract]
[WebInvoke(Method = "PUT", UriTemplate = "edit", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
bool edit(Hotel hotel);
[OperationContract]
[WebInvoke(Method = "DELETE", UriTemplate = "delete", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
bool delete(Hotel hotel);
}
}
ServiceHotel.svc.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace CRUDwithHotels
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "ServiceHotel" in code, svc and config file together.
// NOTE: In order to launch WCF Test Client for testing this service, please select ServiceHotel.svc or ServiceHotel.svc.cs at the Solution Explorer and start debugging.
public class ServiceHotel : IServiceHotel
{
public bool create(Hotel hotel)
{
using (ModelMyDemo hie = new ModelMyDemo())
{
try
{
HotelInfoEntities info = new HotelInfoEntities();
info.Hotelname = hotel.Name;
info.Hoteldesc = hotel.description;
info.Hotelprice = hotel.price;
info.Hotelpicture = hotel.picture;
hie.HotelInfoEntities.Add(info);
hie.SaveChanges();
return true;
}
catch
{
return false;
}
};
}
public bool delete(Hotel hotel)
{
using (ModelMyDemo hie = new ModelMyDemo())
{
try
{
int id = Convert.ToInt16(hotel.Id);
HotelInfoEntities info = hie.HotelInfoEntities.Single(p => p.Hotelid == id);
hie.HotelInfoEntities.Remove(info);
hie.SaveChanges();
return true;
}
catch
{
return false;
}
};
}
public bool edit(Hotel hotel)
{
using (ModelMyDemo hie = new ModelMyDemo())
{
try
{
int id = Convert.ToInt16(hotel.Id);
HotelInfoEntities info = hie.HotelInfoEntities.Single(p => p.Hotelid == id);
info.Hotelname = hotel.Name;
info.Hoteldesc = hotel.description;
info.Hotelprice = hotel.price;
info.Hotelpicture = hotel.picture;
hie.SaveChanges();
return true;
}
catch
{
return false;
}
};
}
public Hotel find(string id)
{
int hid = Convert.ToInt16(id);
using (ModelMyDemo hie = new ModelMyDemo())
{
return hie.HotelInfoEntities.Where(pe => pe.Hotelid == hid).Select(pe => new Hotel
{
Id = pe.Hotelid,
Name = pe.Hotelname,
description = pe.Hoteldesc,
price = pe.Hotelprice,
picture = pe.Hotelpicture
}).First();
};
}
public List<Hotel> findall()
{
//var imagesrc = string.Format("data:image/jpeg;base64,{0}", base64);
using (ModelMyDemo hie = new ModelMyDemo())
{
return hie.HotelInfoEntities.Select(pe => new Hotel
{
Id = pe.Hotelid,
Name = pe.Hotelname,
description = pe.Hoteldesc,
price = pe.Hotelprice,
picture = pe.Hotelpicture
// picture = pe.Hotelpicture
}).ToList();
};
}
}
}
at first we need an object in order to deserilize the the result in it.
public class RootObject
{
public int Id { get; set; }
public string Name { get; set; }
public string description { get; set; }
public List<byte> picture { get; set; }
}
now all we need is to deserilize the json result in to the object. but your json is twice serilized so you need to deserilized it twice like this:
public RootObject findall()
{
try
{
var webClient = new WebClient();
var json = webClient.DownloadString(BASE_URL + "findall");
return JsonConvert.DeserializeObject<RootObject[]>(json);
}
catch
{
return null;
}
}

Asp.net Web Method Returns JSON

I need to create a WebMethod that returns my member database values on JSON. I try something like that but it actually failed.
[WebMethod(EnableSession = false)]
public static UYELER handleAjaxRequest(string mailX, string passwordX)
{
DataSet dsX = ReadSql("select top 3 * from fuyeler ");
for (int i = 0; i < dsX.Tables[0].Rows.Count; i++)
{
mailX = dsX.Tables[0].Rows[i]["stMail"].ToString();
passwordX = dsX.Tables[0].Rows[i]["stPass"].ToString();
}
return new UYELER
{
mail = mailX,
password = passwordX,
};
}
public class UYELER
{
public int ID { get; set; }
public string mail { get; set; }
public string password { get; set; }
}
Readsql is my quick sql connection class.
You can return Json from an Asp.Net method by clearing the normal output in Page_Load and returning your own output. See this StackOverflow answer...
To convert a C# object to JSON you can use a library such as Json.NET.
Method 1:
Add this to your Application_Start in Global.asax page:
protected void Application_Start()
{
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.UseDataContractJsonSerializer = true;
//....
}
Method 2
You can alse decorate your method with ResponseFormat set JSON
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
[WebMethod(EnableSession = false)]
public static UYELER handleAjaxRequest(string mailX, string passwordX)
{
DataSet dsX = ReadSql("select top 3 * from fuyeler ");
for (int i = 0; i < dsX.Tables[0].Rows.Count; i++)
{
mailX = dsX.Tables[0].Rows[i]["stMail"].ToString();
passwordX = dsX.Tables[0].Rows[i]["stPass"].ToString();
}
return new UYELER
{
mail = mailX,
password = passwordX,
};
}

Sending data by JSON

I want to send JSON from desktop application to the server with mvc wepApi.
this is my desktop application code ,that convert data to the JSON and send it.
private void btnAddUserType_Click(object sender, EventArgs e)
{
UserType userType = new UserType();
userType.UserTypeName = txtUserTypeName.Text;
string json = JsonConvert.SerializeObject(userType);
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create("http://localhost:3852/api/default1");
httpWebRequest.ContentType = "text/json";
httpWebRequest.Method = "POST";
var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream());
streamWriter.Write(json);
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
var streamReader = new StreamReader(httpResponse.GetResponseStream());
var responseText = streamReader.ReadToEnd();
}
and this is my web api
// POST api/default1
public void Post([FromBody]string value)
{
UserTypeRepository bl = new UserTypeRepository();
DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(UserType));
MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(value));
UserType u = new UserType();
u = (UserType)js.ReadObject(stream);
bl.Add(u);
}
but when post api is calling the Value is null.
why?
using(var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
streamWriter.Write(json);
You are not flushing nor closing the stream, so basically the data never gets to the api.
My code:
Program.cs - Console App
class Program
{
static void Main(string[] args)
{
var user = new UserModel {Id = 4, FirstName = "Michael", LastName = "Angelo"};
var json = JsonConvert.SerializeObject(user);
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create("http://localhost:56506/api/Values/");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using(var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
streamWriter.Write(json);
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
var streamReader = new StreamReader(httpResponse.GetResponseStream());
var responseText = streamReader.ReadToEnd();
Console.WriteLine(responseText);
Console.ReadKey();
}
}
UserModel.cs - some data class
public class UserModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Id { get; set; }
}
ValuesController.cs - WebApi controller from template
public class ValuesController : ApiController
{
// GET api/values
public UserModel[] Get()
{
return UserProvider.Instance.Get(); // returns some test data
}
// GET api/values/5
public UserModel Get(int id)
{
return new UserModel{Id=1,FirstName="John",LastName="Smith"};
}
// POST api/values
public void Post([FromBody]UserModel value)
{
if (value == null) // BREAKPOINT HERE, just to see what's in value
{
var x = value;
}
}
}
WebApiConfig.cs - default config with added line about Json, but IT WORKS WITHOUT IT -it's so that I can test GET easily in browser etc. ;)
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Result: