I am having a real difficult time figuring out why I am getting a 400 bad request from my POST method on my client side. My other POST methods work fine for this service and client. Yet this one isnt working? I was hoping a fresh pair of eyes might find the problem?
My Service looks like this:
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, UriTemplate = "/Message")]
void AddMessage(Message message);
//Post Method for Message
[DataContract(Name = "Message")]
public class Message
{
[DataMember(Name = "MessageID")]
public string MessageID { get; set; }
[DataMember(Name = "GroupMessage")]
public string GroupMessage { get; set; }
//DataContracts for Message
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class RawDataService : IReceiveData
{
List<Message> messages = new List<Message>();
int eCount = 0;
public void AddMessage(Message message)
{
message.MessageID = (++eCount).ToString();
messages.Add(message);
}
// add message method, increment MessageID
Client Code to Post which gives the 400 bad request on marked line:
private void button15_Click(object sender, EventArgs e)
{
string uriMessage = "http://localhost:8000/Service/Message";
StringBuilder sb1 = new StringBuilder();
sb1.AppendLine("</Message>");
sb1.AppendLine("<GroupMessage>" + this.textBox22.Text + "</GroupMessage>");
sb1.AppendLine("</Message>");
string GroupMessage = sb1.ToString();
byte[] arr1 = Encoding.UTF8.GetBytes(GroupMessage);
HttpWebRequest req1 = (HttpWebRequest)WebRequest.Create(uriMessage);
req1.Method = "POST";
req1.ContentType = "application/xml";
req1.ContentLength = arr1.Length;
Stream reqStrm1 = req1.GetRequestStream();
reqStrm1.Write(arr1, 0, arr1.Length);
reqStrm1.Close();
HttpWebResponse resp1 = (HttpWebResponse)req1.GetResponse(); //400 bad request?
MessageBox.Show(resp1.StatusDescription);
reqStrm1.Close();
resp1.Close();
}
This might be it.
sb1.AppendLine("</Message>");
sb1.AppendLine("<GroupMessage>" + this.textBox22.Text + "</GroupMessage>");
sb1.AppendLine("</Message>");
The opening Message element is actually a closing element.
Related
I'm developer C# .Net
I Now programming a Wcf restful service for communication mobile with my server. But a problem in send json request using post method with parameter. After send request from client, server display error:
400 Bad Request...
My service contract:
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json, UriTemplate = "login", BodyStyle = WebMessageBodyStyle.WrappedRequest)]
[OperationContract]
string login(string username, string password);
And implement service:
public string login(string username, string password)
{
string str = String.Empty;
if (username == "admin" && password == "admin")
str = "Success";
else
str = "Invalid";
return str;
}
Edit:
My host is:
public void Start()
{
Stop();
//string strAdrHTTP = "http://localhost:" + HttpPort + "/WcfMobileService";
string strAdrHTTP = "http://192.168.1.190:" + HttpPort + "/WcfMobileService";
Uri[] adrbase = { new Uri(strAdrHTTP) };
m_svcHost = new ServiceHost(typeof(TWcfMobileService), adrbase);
WebServiceHost webServiceHost =
new WebServiceHost(typeof(TWcfMobileService), adrbase);
ServiceMetadataBehavior mBehave = new ServiceMetadataBehavior();
m_svcHost.Description.Behaviors.Add(mBehave);
mBehave.HttpsGetEnabled = true;
mBehave.HttpGetEnabled = true;
WebHttpBinding webBinding = new WebHttpBinding();
webServiceHost.AddServiceEndpoint(typeof(IWcfMobileServiceContract), webBinding, "rest");
WebHttpBinding restBinding = new WebHttpBinding();
ServiceEndpoint restSEP =
m_svcHost.AddServiceEndpoint(typeof(IWcfMobileServiceContract),
restBinding, "rest");
restSEP.Behaviors.Add(new WebHttpBehavior());
EndpointAddress myEndpointAdd = new EndpointAddress(new Uri(strAdrHTTP),
EndpointIdentity.CreateDnsIdentity("localhost"));
restSEP.Address = myEndpointAdd;
m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
ServiceDebugBehavior debug = new ServiceDebugBehavior();
debug.IncludeExceptionDetailInFaults = true;
m_svcHost.Open();
}
This is an working example -
[OperationContract]
[WebInvoke(
Method = "POST",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
UriTemplate = "login")]
string login(CompositeType request);
Where -
[DataContract]
public class CompositeType
{
[DataMember]
public string username { get; set; }
[DataMember]
public string password { get; set; }
}
Sample request -
{"request":{"username":"test","password":"test"}}
And it works -
I have the following code:
[DataContract]
public class OptimizationServiceSettings
{
[DataMember]
public bool StealthMode { get; set; }
}
Server:
[WebInvoke(Method = "POST", UriTemplate = "SetSettings", BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
[OperationContract]
public void SetSettings(OptimizationServiceSettings settings)
{
if (settings != null)
{
_stageOptimizer.ServiceSettings = settings;
}
else
{
Trace.TraceError("Attemp to set null OptimizationServiceSettings");
}
}
Client:
private static void SetSettings()
{
OptimizationServiceSettings op = new OptimizationServiceSettings();
op.StealthMode = true;
string jsonInput = ToJson(op);
var client = new WebClient();
client.Headers["Content-type"] = "application/json";
client.Encoding = Encoding.UTF8;
var response = client.UploadString("http://localhost:8080/BlocksOptimizationServices/SetSettings", "POST", jsonInput);
}
private static string ToJson<T>(T data)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, data);
return Encoding.Default.GetString(ms.ToArray());
}
}
For some reason the SetSettings method on the server always gets a null settings object. If I change the settings object type to string it all works. I don't understand what is wrong here. Everything looks like it is correct.
Here is an example of the jsonInput string that I got in SetSettings on the client:
"{\"StealthMode\":\"true\"}"
You specified the requestbody to be wrapped:
[WebInvoke(..., BodyStyle = WebMessageBodyStyle.WrappedRequest, ...]
Hence, the deserialization only succeeds if you wrap the settings-object within a containing object, as #Pankaj suggested.
Instead of doing that, you could try to change the attribute to WebMessageBodyStyle.Bare to avoid the need to wrap the parameter.
I have created the following restfull web service:
Interface
[ServiceContract]
public interface ISIGService
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "GetTicket/")]
Ticket GetTicket(string user, string pwd);
}
Implementation
public class SIGService : ISIGService
{
public Ticket GetTicket(string user, string pwd)
{
return new Ticket()
{
Usuario = "xx",
UsuarioNombre = "xxx",
UsuarioId = "xxx"
};
}
Contract
[DataContract]
public class Ticket
{
[DataMember]
public int UsuarioId { get; set; }
[DataMember]
public string UsuarioNombre { get; set; }
[DataMember]
public string Usuario { get; set; }
}
I need to consume this service, from a web application, and get the typed object Ticket, I have included a service reference for this.
Server side code:
string urlService =
String.Format("http://localhost:22343/SIGService.svc/GetTicket/?user='{0}'&pwd='{1}'",
usuario, password);
var request = (HttpWebRequest)WebRequest.Create(urlService);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string text = reader.ReadToEnd();
I put a text variable just to get something, sort of lost here.
I don't seem to get this object, could you give some pointers on this?
Most likely, you just need to change your URL from
http://localhost:22343/SIGService.svc/GetTicket/?user='{0}'&pwd='{1}'
to using the proper REST syntax (since you're using a REST service):
http://localhost:22343/SIGService.svc/GetTicket/{user}/{pwd}
Sample:
http://localhost:22343/SIGService.svc/GetTicket/daniel/topsecret
No ? or user= or single quotes necessary ....
With this, the value from {0} will be passed into the user parameter, and the value from {1} to the pwd parameter.
For consuming the service, I would recommend you check out the excellent RestSharp library which makes using your REST service a breeze.
Your code would look something like this:
// set up the REST Client
string baseServiceUrl = "http://localhost:22343/SIGService.svc";
RestClient client = new RestClient(baseServiceUrl);
// define the request
RestRequest request = new RestRequest();
request.Method = Method.GET;
request.RequestFormat = DataFormat.Xml;
request.Resource = "GetTicket/{user}/{pwd}";
request.AddParameter("user", "daniel", ParameterType.UrlSegment);
request.AddParameter("pwd", "top$ecret", ParameterType.UrlSegment);
// make the call and have it deserialize the XML result into a Ticket object
var result = client.Execute<Ticket>(request);
if (result.StatusCode == HttpStatusCode.OK)
{
Ticket ticket = result.Data;
}
I have a serializable polymorphic type, and a service contract.
[DataContract]
[KnownType(typeof(SomethingA))]
[KnownType(typeof(SomethingB))]
public class Something
{
[DataMember]
public int Item1 { get; set; }
[DataMember]
public string Item2 { get; set; }
}
[DataContract]
public class SomethingA : Something
{ }
[DataContract]
public class SomethingB : Something
{ }
[ServiceContract]
[ServiceKnownType(typeof(SomethingA))]
[ServiceKnownType(typeof(SomethingB))]
public interface ITesting
{
[OperationContract]
[WebInvoke(
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "use-something",
Method = "POST")]
Something UseSomething();
[OperationContract]
[WebInvoke(
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "use-polymorphic-somethings",
Method = "POST")]
List<Something> UsePolymorphicSomethings();
[OperationContract]
[WebInvoke(
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "throw-web-exception",
Method = "POST")]
void ThrowServerException();
}
...and an implementation of that contract.
using System.Net;
using System.ServiceModel.Web;
public class Testing : ITesting
{
public Something UseSomething()
{
SomethingA a = new SomethingA();
a.Item1 = 2;
a.Item2 = "b";
return a;
}
public List<Something> UsePolymorphicSomethings()
{
List<Something> retVal = new List<Something>();
retVal.Add(new SomethingA { Item1 = 1, Item2 = "1" });
retVal.Add(new SomethingB { Item1 = 1, Item2 = "1" });
return retVal;
}
public void ThrowServerException()
{
try
{
throw new ApplicationException("Bad news.");
}
catch (ApplicationException e)
{
throw new WebFaultException<ApplicationException>(e, HttpStatusCode.InternalServerError);
}
}
}
I have some functional tests in another assembly.
using System.Net;
using System.Net.Http;
using System.Runtime.Serialization.Json;
[TestMethod]
public void UseSomething_WebTest()
{
using (HttpClient http = new HttpClient())
{
http.BaseAddress = TestUtil.TestsBaseAddress;
HttpResponseMessage response = http.PostAsJsonAsync("use-something",
new StringContent(string.Empty)).Result;
string ret1 = response.Content.ReadAsStringAsync().Result;
// Deserializes SomethingA as Something.
Stream stream = response.Content.ReadAsStreamAsync().Result;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Something));
Something ret = (Something)serializer.ReadObject(stream);
// FAILS.
Assert.AreEqual(typeof(SomethingA), ret.GetType());
}
}
[TestMethod]
public void UsePolymorphicSomethings_WebTest()
{
using (HttpClient http = new HttpClient())
{
http.BaseAddress = TestUtil.TestsBaseAddress;
HttpResponseMessage response = http.PostAsJsonAsync("use-polymorphic-somethings",
new StringContent(string.Empty)).Result;
string ret2 = response.Content.ReadAsStringAsync().Result;
// Deserializes SomethingA and SomethingB correctly.
Stream stream = response.Content.ReadAsStreamAsync().Result;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Something>));
List<Something> somethings = (List<Something>)serializer.ReadObject(stream);
// SUCCEEDS.
Assert.AreEqual(typeof(SomethingA), somethings[0].GetType());
Assert.AreEqual(typeof(SomethingB), somethings[1].GetType());
}
}
[TestMethod]
public void ThrowServerException1_WebTest()
{
using (HttpClient http = new HttpClient())
{
http.BaseAddress = TestUtil.TestsBaseAddress;
HttpResponseMessage response = http.PostAsync("throw-web-exception",
new StringContent(string.Empty)).Result;
Assert.AreEqual(HttpStatusCode.InternalServerError, response.StatusCode);
string ret3 = response.Content.ReadAsStringAsync().Result;
// Deserializes ApplicationException as Exception.
Stream stream = response.Content.ReadAsStreamAsync().Result;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Exception));
Exception e = (Exception)serializer.ReadObject(stream);
// FAILS.
Assert.AreEqual(typeof(ApplicationException), e.GetType());
}
}
In UseSomething_WebTest ret1 is:
"{\"Item1\":2,\"Item2\":\"b\"}"
...with no type information embedded unsurprisingly the DataContractJsonSerializer fails to deserialize the correct type of the object that was returned.
In UsePolymorphicSomethings_WebTest ret2 is:
"[{\"__type\":\"SomethingA:#InSite8WebServiceLib\",\"Item1\":1,\"Item2\":\"1\"},{\"__type\":\"SomethingB:#InSite8WebServiceLib\",\"Item1\":1,\"Item2\":\"1\"}]"
...with type information embedded in the form of __type entries which the DataContractJsonSerializer correctly deserializes.
In ThrowServerException1_WebTest ret3 is:
"{\"ClassName\":\"System.ApplicationException\",\"Message\":\"Bad news.\",\"Data\":null,\"InnerException\":null,\"HelpURL\":null,\"StackTraceString\":\" at InSite8WebServiceLib.Testing.ThrowServerException() in d:\\\\SvnSource\\\\Hammersmith\\\\trunk\\\\VisualStudioProjects\\\\InSite8WebService\\\\InSite8WebServiceLib\\\\Testing\\\\Testing.cs:line 74\",\"RemoteStackTraceString\":null,\"RemoteStackIndex\":0,\"ExceptionMethod\":\"8\\u000aThrowServerException\\u000aInSite8WebServiceLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\\u000aInSite8WebServiceLib.Testing\\u000aVoid ThrowServerException()\",\"HResult\":-2146232832,\"Source\":\"InSite8WebServiceLib\",\"WatsonBuckets\":null}"
...with type information embedded in the form of a ClassName entry which the DataContractJsonSerializer fails to deserialize correctly.
So my question is this. Why for a single WCF WebHttp endpoint do several WebInvoke attributed methods return several different formats of JSON only one of which the DataContractJsonSerializer can actually deserialize, and how do I fix it so that it works properly?
You can force the DataContractJsonSerializer to always emit type information by overloading the constructor. Then you set the alwaysEmitTypeInformation argument to True.
Some more information on MSDN
I have a WCF Rest service with a method that takes in multiple parameters:
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json)]
StatusMessage DoSomeWork(short myId, decimal latitude, decimal longitude, string someData);
The JSON data which is serialized on the client side serializes correctly, and this method receives that data. The problem is that the longitudeparameter always comes back as 0, no matter what value the value is when it gets serialized. All the other parameters are deserialized correctly. Any idea as to why this is happening, and a possible fix?
Make sure that the name of the property in the JSON object matches the name of the parameter longitude. The code below shows your exact operation contract, and the longitude is correctly received by the service.
public class StackOverflow_23529686
{
[ServiceContract]
public class Service
{
[OperationContract]
[WebInvoke(
Method = "POST",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
RequestFormat = WebMessageFormat.Json)]
public StatusMessage DoSomeWork(short myId, decimal latitude, decimal longitude, string someData)
{
return new StatusMessage
{
Text = string.Format("id={0}, lat={1}, lon={2}, data={3}", myId, latitude, longitude, someData)
};
}
}
public class StatusMessage
{
public string Text { get; set; }
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
host.Open();
Console.WriteLine("Host opened");
WebClient c = new WebClient();
c.Headers.Add(HttpRequestHeader.ContentType, "application/json");
var json =
"{'someData':'hello','longitude':-56.78,'latitude':12.34,'myId':1}"
.Replace('\'', '\"');
Console.WriteLine(c.UploadString(baseAddress + "/DoSomeWork", json));
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}