.Net Webservice will not accept parameters for XML call
For some reason, my webservice doesn't like the data I am sending. I keep getting the following error:
System.InvalidOperationException: Request format is invalid: text/xml; charset=utf-8.
at System.Web.Services.Protocols.HttpServerProtocol.ReadParameters () at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest ()
Any ideas?
Here's my code:
$.ajax({
type: "POST",
url: "/wsCheckout.asmx/loginUser",
data: "userName=" + userName + "&pw=" + pw,
contentType: "text/xml; charset=utf-8",
dataType: "xml",
cache: false,
beforeSend: function(n){ showLoading(); },
complete: function(n){ hideLoading(); },
success: function(r) {
if( checkResponse(r) == true ){
closeBox(aspxIdPrefix + "login");
hideBox(aspxIdPrefix + "login");
openBox("#shippingAddress");
}
} // end success
}); //end AJAX
[WebMethod(EnableSession = true)]
[System.Web.Script.Services.ScriptMethod(ResponseFormat = System.Web.Script.Services.ResponseFormat.Xml)]
public DataTable loginUser(string userName, string pw)
{
......
}
a source to share
The data parameter passes the parameters as querystring (GET), not post, and the content type is application / json. Here's the complete syntax.
$.ajax({
type: "POST",
url: "/wsCheckout.asmx/loginUser",
data: "{userName:'" + userName + "',pw:'" + pw+"'}",
contentType: "application/json; charset=utf-8",
dataType: "xml",
cache: false,
beforeSend: function(n){ showLoading(); },
complete: function(n){ hideLoading(); },
success: function(r) {
if( checkResponse(r) == true ){
closeBox(aspxIdPrefix + "login");
hideBox(aspxIdPrefix + "login");
openBox("#shippingAddress");
}
} // end success
});
a source to share
You are not actually sending XML data to your web service. For now, given your code snippet, your HTML form submission is encoded:
field1=value1&field2=value2&field3=value3
You probably need to change your data as xml, according to:
'<data><userName>' + userName + '</userName><pw>' + pw + '</pw></data>'
To do the latter, you also need to change the signature of the web service to take one line, which is later deserialized:
[XmlRoot("data")]
public class UserRequestData
{
public string userName { get; set; }
public string pw { get; set; }
}
[WebMethod(EnableSession = true)]
[System.Web.Script.Services.ScriptMethod(ResponseFormat = System.Web.Script.Services.ResponseFormat.Xml)]
public DataTable loginUser(string xmlUserRequest)
{
XmlSerializer serializer = new XmlSerializer(typeof(UserRequestData));
StringReader reader = new StringReader(xmlUserRequest);
UserRequestData data = serializer.Deserialize(reader);
string userNme = data.UserName;
string pw = data.Pw;
......
}
It's probably also important to note that the attribute you decorated with your service is:
[System.Web.Script.Services.ScriptMethod(ResponseFormat = System.Web.Script.Services.ResponseFormat.Xml)]
Refers to the return value of a service method, not the input. Decorating with this, your ANSWER will be formatted with xml. This does not affect the entry of your services.
Hope it helps.
a source to share
If you want to return serialized .Net objects via JSON, there are several things you need to do. Assuming you are using jQuery ajax calls, it should just work (after making the changes to your service mentioned below), given that jQuery adds a callback parameter for you. If you are not using jQuery, just add the callback param, pointing to whatever js function you would like to call successful.
- Decorate your work contract, set ResponseFormat.WebMessageForm.Json (for example
[WebGet(BodyStyle = WebMessageBodyStyle.WrappedRequest,ResponseFormat = WebMessageFormat.Json,RequestFormat = WebMessageFormat.Json)]
) -
create a class that inherits from Stream (see below):
public class JSONCallbackStream : Stream
{private stream _stream;
private string _callbackFunction = string.Empty; public JSONCallbackStream(Stream stream) { _stream = stream; } public override bool CanRead { get { return _stream.CanRead; } } public override bool CanSeek { get { return _stream.CanSeek; } } public override bool CanWrite { get { return _stream.CanWrite; } } public override long Length { get { return _stream.Length; } } public override long Position { get { return _stream.Position; } set { _stream.Position = value; } } public string CallbackFunction { get { return _callbackFunction; } set { _callbackFunction = value; } } public override void Flush() { _stream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { return _stream.Read(buffer, offset, count); } public override long Seek(long offset, SeekOrigin origin) { return _stream.Seek(offset, origin); } public override void SetLength(long value) { _stream.SetLength(value); } public override void Write(byte[] buffer, int offset, int count) { if (CallbackFunction != string.Empty) { // This MUST be a one-time write to the underlying stream - any more than 1 write means // that the stream will be truncated/an exception could be thrown string content = CallbackFunction + "(" + Encoding.UTF8.GetString(buffer) + ");"; byte[] contentBytes = Encoding.UTF8.GetBytes(content); _stream.Write(contentBytes, 0, Encoding.UTF8.GetMaxCharCount(contentBytes.Length)); } else { _stream.Write(buffer, offset, count); } }
}
-
create a class that inherits from IHttpModule and make sure you have entries in your web.config file for this under system.web -> httpModules (as well as system.webServer -> if on IIS 7), see the class below:
public class JSONCallback : IHttpModule
{public void Dispose () {}
//looks for a callback parameter, if found it wraps the return in the callback string public void Init(HttpApplication app) { app.BeginRequest += delegate { HttpContext ctx = HttpContext.Current; if ((ctx.Request.RequestType.ToUpper() == "GET")) { string[] parameters = ctx.Request.QueryString.GetValues("callback"); if (parameters != null && parameters.Length == 1) { JSONCallbackStream _captureStream = new JSONCallbackStream(ctx.Response.Filter); _captureStream.CallbackFunction = parameters[0]; ctx.Response.Filter = _captureStream; } } }; }
}
a source to share