Why does this simple web service refuse to return JSON to the client?
Here is my client code:
var params = { };
$.ajax({
url: "/Services/SessionServices.asmx/HelloWorld",
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
timeout: 10000,
data: JSON.stringify(params),
success: function (response) {
console.log(response);
}
});
And the service:
namespace myproject.frontend.Services
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[ScriptService]
public class SessionServices : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string HelloWorld()
{
return "Hello World";
}
}
}
web.config:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
</configuration>
And the response:
<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://tempuri.org/">Hello World</string>
No matter what I do, the response always comes back as XML. How do I get the web service to return Json?
EDIT:
Here is the Fiddler HTTP trace:
REQUEST
-------
POST http://myproject.local/Services/SessionServices.asmx/HelloWorld HTTP/1.1
Host: myproject.local
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0.1
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/json; charset=utf-8
X-Requested-With: XMLHttpRequest
Referer: http://myproject.local/Pages/Test.aspx
Content-Length: 2
Cookie: ASP.NET_SessionId=5tvpx1ph1uiie2o1c5wzx0bz
Pragma: no-cache
Cache-Control: no-cache
{}
RESPONSE
-------
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: text/xml; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Tue, 19 Jun 2012 16:33:40 GMT
Content-Length: 96
<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://tempuri.org/">Hello World</string>
I have lost count of how many articles I have read now trying to fix this. The instructions are either incomplete or do not solve my issue for some reason.
Some of the more relevant ones include (all without success):
ASP.NET web service erroneously returns XML instead of JSON
asmx web service returning xml instead of json in .net 4.0
http://williamsportwebdeveloper.com/cgi/wp/?p=494
http://encosia.com/using-jquery-to-consume-aspnet-json-web-services/
http://forums.asp.net/t/1054378.aspx
http://jqueryplugins.info/2012/02/asp-net-web-service-returning-xml-instead-of-json/
Plus several other general articles.
Finally figured it out.
The app code is correct as posted. The problem is with the configuration. The correct web.config is:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.webServer>
<handlers>
<add name="ScriptHandlerFactory"
verb="*" path="*.asmx"
type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
resourceType="Unspecified" />
</handlers>
</system.webServer>
</configuration>
According to the docs, registering the handler should be unnecessary from .NET 4 upwards as it has been moved to the machine.config. For whatever reason, this isn't working for me. But adding the registration to the web.config for my app resolved the problem.
A lot of the articles on this problem instruct to add the handler to the <system.web> section. This does NOT work and causes a whole load of other problems. I tried adding the handler to both sections and this generates a set of other migration errors which completely misdirected my troubleshooting.
In case it helps anyone else, if I had ther same problem again, here is the checklist I would review:
Did you specify type: "POST" in the ajax request?
Did you specify contentType: "application/json; charset=utf-8" in the ajax request?
Did you specify dataType: "json"in the ajax request?
Does your .asmx web service include the [ScriptService] attribute?
Does your web method include the [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
attribute? (My code works even without this attribute, but a lot of articles say that it is required)
Have you added the ScriptHandlerFactory to the web.config file in <system.webServer><handlers>?
Have you removed all handlers from the the web.config file in in <system.web><httpHandlers>?
Hope this helps anyone with the same problem. and thanks to posters for suggestions.
No success with above solution, here how I resolved it.
put this line into your webservice and rather return type just write the string in response context
this.Context.Response.ContentType = "application/json; charset=utf-8";
this.Context.Response.Write(serial.Serialize(city));
If you want to stay remain with Framework 3.5, you need to make change in code as follows.
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[ScriptService]
public class WebService : System.Web.Services.WebService
{
public WebService()
{
}
[WebMethod]
public void HelloWorld() // It's IMP to keep return type void.
{
string strResult = "Hello World";
object objResultD = new { d = strResult }; // To make result similarly like ASP.Net Web Service in JSON form. You can skip if it's not needed in this form.
System.Web.Script.Serialization.JavaScriptSerializer ser = new System.Web.Script.Serialization.JavaScriptSerializer();
string strResponse = ser.Serialize(objResultD);
string strCallback = Context.Request.QueryString["callback"]; // Get callback method name. e.g. jQuery17019982320107502116_1378635607531
strResponse = strCallback + "(" + strResponse + ")"; // e.g. jQuery17019982320107502116_1378635607531(....)
Context.Response.Clear();
Context.Response.ContentType = "application/json";
Context.Response.AddHeader("content-length", strResponse.Length.ToString());
Context.Response.Flush();
Context.Response.Write(strResponse);
}
}
There is much easier way to return a pure string from web service. I call it CROW function (makes it easy to remember).
[WebMethod]
public void Test()
{
Context.Response.Output.Write("and that's how it's done");
}
As you can see, return type is "void", but CROW function will still return the value you want.
I have a .asmx web service (.NET 4.0) with a method that returns a string. The string is a serialized List like you see in many of the examples. This will return json that is not wrapped in XML. No changes to web.config or need for 3rd party DLLs.
var tmsd = new List<TmsData>();
foreach (DataRow dr in dt.Rows)
{
m_firstname = dr["FirstName"].ToString();
m_lastname = dr["LastName"].ToString();
tmsd.Add(new TmsData() { FirstName = m_firstname, LastName = m_lastname} );
}
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
string m_json = serializer.Serialize(tmsd);
return m_json;
The client part that uses the service looks like this:
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8",
dataType: 'json',
url: 'http://localhost:54253/TmsWebService.asmx/GetTombstoneDataJson',
data: "{'ObjectNumber':'105.1996'}",
success: function (data) {
alert(data.d);
},
error: function (a) {
alert(a.responseText);
}
});
Hope this helps, it appears that you still have to send some JSON object in the request, even if the Method you are calling has no parameters.
var params = {};
return $http({
method: 'POST',
async: false,
url: 'service.asmx/ParameterlessMethod',
data: JSON.stringify(params),
contentType: 'application/json; charset=utf-8',
dataType: 'json'
}).then(function (response) {
var robj = JSON.parse(response.data.d);
return robj;
});
For me it works with this code I got from this post:
How can I return json from my WCF rest service (.NET 4), using Json.Net, without it being a string, wrapped in quotes?
[WebInvoke(UriTemplate = "HelloWorld", Method = "GET"), OperationContract]
public Message HelloWorld()
{
string jsonResponse = //Get JSON string here
return WebOperationContext.Current.CreateTextResponse(jsonResponse, "application/json; charset=utf-8", Encoding.UTF8);
}
I have tried all of the above steps ( even the answer), but i was not successful, my system configuration is Windows Server 2012 R2, IIS 8. The following step solved my problem.
Changed the app pool, that has managed pipeline = classic.
I know that is really old question but i came to same problem today and I've been searching everywhere to find the answer but with no result. After long research I have found the way to make this work. To return JSON from service you have provide data in request in the correct format, use JSON.stringify() to parse the data before request and don't forget about contentType: "application/json; charset=utf-8", using this should provide expected result.
response = await client.GetAsync(RequestUrl, HttpCompletionOption.ResponseContentRead);
if (response.IsSuccessStatusCode)
{
_data = await response.Content.ReadAsStringAsync();
try
{
XmlDocument _doc = new XmlDocument();
_doc.LoadXml(_data);
return Request.CreateResponse(HttpStatusCode.OK, JObject.Parse(_doc.InnerText));
}
catch (Exception jex)
{
return Request.CreateResponse(HttpStatusCode.BadRequest, jex.Message);
}
}
else
return Task.FromResult<HttpResponseMessage>(Request.CreateResponse(HttpStatusCode.NotFound)).Result;
Related
It looks like ServiceStack doesn't like me using a DateTime property as an argument in my request. I'm getting a "Bad Request" message... no other helpful detail in the exception. The inner exception shows html code (truncated), and just says "Type definitions should start with a "{" expecting serialized type 'ErrorResponse'..."
In my client:
private DateTime _selectedReportDate;
public DateTime SelectedReportDate
{
get { return _selectedReportDate; }
set { SetProperty(ref _selectedReportDate, value); }
}
....
var txResults = await ServiceClient.Instance.GetAsync(new PaymentSummaries()
{
Date = SelectedReportDate
});
Service Model:
[Route("/report/paymentsummaries/{Date}", "GET")]
public class PaymentSummaries : IReturn<List<PaymentSummary>>
{
public DateTime Date { get; set; }
}
Service Interface:
[Authenticate]
public class PaymentSummariesService : Service
{
public List<PaymentSummary> Get(PaymentSummaries request)
{
var results = Db.SqlList<Data.OrmLite.SpResponse.ReconcilePaymentSummaryRecord>("EXEC [Report].[ReconcilePaymentsSummary] #date", new { date = request.Date });
return results.ConvertAll(x => x.ConvertTo<PaymentSummary>());
}
}
I'm getting a "Bad Request" error.
When I change:
Date = SelectedReportDate
to
Date = new DateTime()
in the client code, it does work, and hits the Service Interface code for some reason.
Update
Here's the request header:
GET
http://devservicestack:44345/report/paymentsummaries/2016-11-30T13%3A09%3A15.6795974-05%3A00
HTTP/1.1 Accept-Encoding: gzip,deflate Accept: application/json
User-Agent: ServiceStack .NET Client 4.54 Host: devservicestack:44345
Cookie: ss-id=F4Bt4aMonhyFQcfqmSmR; ss-pid=K6aJMA17Xw31qIVy1z8V;
ss-opt=temp
The response header tells me:
[HttpException (0x80004005): A potentially dangerous Request.Path
value was detected from the client (:).]
System.Web.HttpRequest.ValidateInputIfRequiredByConfig() +9827624
System.Web.PipelineStepManager.ValidateHelper(HttpContext context) +53
When hosting ServiceStack in ASP.Net (as opposed to self-hosting), ASP.Net utilizes XSS security checks. to get around this, I can allow specific characters:
<system.web>
<httpRuntime targetFramework="4.6.2" requestPathInvalidCharacters="<,>,*,%,&,\,?" />
</system.web>
(omitted ":" in requestPathInvalidCharacters)
or:
<system.web>
<httpRuntime targetFramework="4.6.2" requestValidationMode="2.0" requestPathInvalidCharacters="" />
</system.web>
to disable request validation for the entire application.
I swear this has happened so many times to me that I actually hate CORS.
I have just split my application in two so that one handles just the API side of things and the other handles the client side stuff.
I have done this before, so I knew that I needed to make sure CORS was enabled and allowed all, so I set this up in WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
// Enable CORS
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
// Web API configuration and services
var formatters = config.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var serializerSettings = jsonFormatter.SerializerSettings;
// Remove XML formatting
formatters.Remove(config.Formatters.XmlFormatter);
jsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
// Configure our JSON output
serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
serializerSettings.Formatting = Formatting.Indented;
serializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
serializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None;
// Configure the API route
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
As you can see, my first line Enables the CORS, so it should work.
If I open my client application and query the API, it does indeed work (without the EnableCors I get the expected CORS error.
The problem is my /token is still getting a CORS error. Now I am aware that /token endpoint is not part of the WebAPI, so I created my own OAuthProvider (which I must point out is being used in other places just fine) and that looks like this:
public class OAuthProvider<TUser> : OAuthAuthorizationServerProvider
where TUser : class, IUser
{
private readonly string publicClientId;
private readonly UserService<TUser> userService;
public OAuthProvider(string publicClientId, UserService<TUser> userService)
{
if (publicClientId == null)
throw new ArgumentNullException("publicClientId");
if (userService == null)
throw new ArgumentNullException("userService");
this.publicClientId = publicClientId;
this.userService = userService;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
var user = await this.userService.FindByUserNameAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
var oAuthIdentity = this.userService.CreateIdentity(user, context.Options.AuthenticationType);
var cookiesIdentity = this.userService.CreateIdentity(user, CookieAuthenticationDefaults.AuthenticationType);
var properties = CreateProperties(user.UserName);
var ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
context.AdditionalResponseParameters.Add(property.Key, property.Value);
return Task.FromResult<object>(null);
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// Resource owner password credentials does not provide a client ID.
if (context.ClientId == null)
{
context.Validated();
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
{
if (context.ClientId == this.publicClientId)
{
var redirectUri = new Uri(context.RedirectUri);
var expectedRootUri = new Uri(context.Request.Uri, redirectUri.PathAndQuery);
if (expectedRootUri.AbsoluteUri == redirectUri.AbsoluteUri)
context.Validated();
}
return Task.FromResult<object>(null);
}
public static AuthenticationProperties CreateProperties(string userName)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName }
};
return new AuthenticationProperties(data);
}
}
As you can see, In the GrantResourceOwnerCredentials method I enable CORS access to everything again. This should work for all requests to /token but it doesn't.
When I try to login from my client application I get a CORS error.
Chrome shows this:
XMLHttpRequest cannot load http://localhost:62605/token. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:50098' is therefore not allowed access. The response had HTTP status code 400.
and Firefox shows this:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:62605/token. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:62605/token. (Reason: CORS request failed).
For testing purposes, I decided to use fiddler to see if I could see anything else that might give me a clue as to what is happening. When I try to login, FIddler shows a response code as 400 and if I look at the raw response I can see the error:
{"error":"unsupported_grant_type"}
which is strange, because the data I am sending has not changed and was working fine before the split.
I decided to use the Composer on fiddler and replicated what I expect the POST request to look like.
When I Execute it, it works fine and I get a response code of 200.
Does anyone have any idea why this might be happening?
Update 1
Just for reference, the request from my client app looks like this:
OPTIONS http://localhost:62605/token HTTP/1.1
Host: localhost:62605
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: POST
Origin: http://localhost:50098
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36
Access-Control-Request-Headers: accept, authorization, content-type
Accept: */*
Referer: http://localhost:50098/account/signin
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
from the composer, it looks like this:
POST http://localhost:62605/token HTTP/1.1
User-Agent: Fiddler
Content-Type: 'application/x-www-form-urlencoded'
Host: localhost:62605
Content-Length: 67
grant_type=password&userName=foo&password=bar
Inside of
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
Get rid of this:
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
Currently you are doing the CORS thing twice. Once with .EnableCors and also again by writing the header in your token endpoint.
For what it's worth, in my OWIN startup class I have this at the very top:
app.UseCors(CorsOptions.AllowAll);
I also do NOT have it in my WebAPI register method, as I'm letting the OWIN startup handle it.
Since OAuthAuthorizationServer runs as an Owin middleware you must use the appropriate package Microsoft.Owin.Cors to enable CORS that works with any middleware in the pipeline. Keep in mind that WebApi & Mvc are just middleware themselves in regards to the owin pipeline.
So remove config.EnableCors(new EnableCorsAttribute("*", "*", "*")); from your WebApiConfig and add the following to your startup class.
Note app.UseCors it must precede the app.UseOAuthAuthorizationServer
app.UseCors(CorsOptions.AllowAll)
#r3plica
I had this problem, and it is like Bill said.
Put the line "app.UseCors" at the very top in Configuration method()
(before ConfigureOAuth(app) is enough)
Example:
public void Configuration(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
HttpConfiguration config = new HttpConfiguration();
ConfigureWebApi(config);
ConfigureOAuth(app);
app.UseWebApi(config);
}
We ran into a similar situation and ended up specifying some CORS data in the system.webServer node of the web.config in order to pass the preflight check. Your situation is slightly different than ours but maybe that would help you as well.
Here's what we added:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Credentials" value="true" />
<add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS" />
</customHeaders>
</httpProtocol>
It turns out that there was no issue with CORS at all. I had an interceptor class that was modifying the headers incorrectly. I suggest for future reference, anyone else having these issues, if you have your CORS set up either in WebConfig.cs or your Startup class or even the web.config then you need to check that nothing is modifying your headers. If it is, disable it and test again.
I would like to send a POST asynchronously from client side (JavaScript) to server side (ASP.Net) with 2 parameters: numeric and long formated string.
I understand the long formated string must have encodeURIComponent() on it befor passing it.
My trouble is I want to embed the long encoded string in body request and later open it from C# on server side.
Please, can you help me? I'm messing too much with ajax, xhr, Request.QueryString[], Request.Form[], ....
First, create an HTTPHandler:
using System.Web;
public class HelloWorldHandler : IHttpHandler
{
public HelloWorldHandler()
{
}
public void ProcessRequest(HttpContext context)
{
HttpRequest Request = context.Request;
HttpResponse Response = context.Response;
//access the post params here as so:
string id= Request.Params["ID"];
string longString = Request.Params["LongString"];
}
public bool IsReusable
{
// To enable pooling, return true here.
// This keeps the handler in memory.
get { return false; }
}
}
Then register it:
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="*.ashx"
type="HelloWorldHandler"/>
</httpHandlers>
</system.web>
</configuration>
Now call it - using jQuery Ajax:
$.ajax({
type : "POST",
url : "HelloWorldHandler.ashx",
data : {id: "1" , LongString: "Say Hello"},
success : function(data){
//handle success
}
});
NOTE Totally untested code but it should be very close to what you need.
I just tested and it works out of the box. This is how I called it:
<script language="javascript" type="text/javascript">
function ajax() {
$.ajax({
type: "POST",
url: "HelloWorldHandler.ashx",
data: { id: "1", LongString: "Say Hello" },
success: function (data) {
//handle success
}
});
}
</script>
<input type="button" id="da" onclick="ajax();" value="Click" />
I realize there are tonnes of similar questions already up here but I cannot figure this one out.
I have a Web Service (C#, .net 3.5). The essential Code you need to know of is as follows:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class WSMember : System.Web.Services.WebService {
public WSMember () {
}
[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public string GetMember(string IdMember)
{
//Ignore the parameter for now... I will be looking up a database with it...
//For now just return a minimal object:
Member m = new Member();
m.Surname = "Smith";
m.FirstName = "John";
return new JavaScriptSerializer().Serialize(m);
}
Also, in web.config, I made the following addition (which I just saw on some other post... is this normal/safe?)
<webServices>
<protocols>
<add name="HttpGet" />
<add name="HttpPost" />
</protocols>
</webServices>
Then in Default.aspx, I the two key references...
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" src="jquery.json-2.2.min.js" ></script>
jquery.json-2.2.min.js was downloaded from google code
And Here is the Javascript:
<script type="text/javascript">
$(document).ready(function() {
$("#button1").click(function(event) {
var myData = { IdMember: "2" };
var encoded = $.toJSON(myData);
alert(encoded);
$.ajax({
type: "POST",
url: "WSMember.asmx/GetMember",
data: encoded,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
alert("worked" + msg.d);
//$("#sidebar").append(msg);
},
error: function(msg) {
alert(msg.d);
//$("#sidebar").append(msg);
}
});
});
});
</script>
When I execute it, the encoded json appears in the message box as expected... i.e. with double quotes:
{ "IdMember":"2" }
However, it always fails. Even for the most basic Hello World with no data being passed in, it fails. I keep getting "undefined" for the message data.
If I just use alert(msg), it displays [object XMLHttpRequest]
Does anyone know where my data is getting lost??
And another question... is there anything fundamentally wrong with what I'm doing?
Thanks a lot.
EDIT:
thanks for the reply guys. I have tried the following so...
UseHttpGet = true is now changed to false. (Again - I saw it somewhere so I tried it... but I knew it couldn't be right :-/ )
Let's say the web service now returns a string. I build the string as follows (seems a bit crazy... serializing it did the exact same thing... )
StringBuilder sb = new StringBuilder();
sb.Append("{");
sb.Append("\"Surname\":");
sb.Append("\"");
sb.Append(m.Surname);
sb.Append("\"");
sb.Append(",\"FirstName\":");
sb.Append("\"");
sb.Append(m.FirstName);
sb.Append("\"");
sb.Append("}");
return sb.ToString();
This code returns something like:
{"Surname":"Smith","FirstName":"John"}
I still get the exact same error...
I have also tried something like returning the object "Member",so the code becomes:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public Member GetMember(string IdMember)
{
Member m = new Member();
m.Surname = "Smith";
m.FirstName = "John";
return m;
}
This too throws the same error.
Sorry to be a pain... I've read both of those links, and others. Just can't see why this any different.
Is there any extra config setting I need to be aware of possibly??
Thanks a lot for replies.
UPDATE:
Problem is fixed. The key mistakes in the above code are:
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
should be
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
Also, on the form, when using a button to call the javascript, I was incorrectly setting the input type...
<input id="button1" type="submit" value="Just a test" />
when it should say:
<input id="button1" type="button" value="Just a test" />
Many thanks to all who helped.
It seems to me that your main problem that you try to manually use JavaScriptSerializer().Serialize instead of returning an object. The response from the web service will be double JSON encoded.
You are right! There are a lot of a close questions. Look at here Can I return JSON from an .asmx Web Service if the ContentType is not JSON? and Can't get jQuery Ajax to parse JSON webservice result and you will (I hope) find the answer.
UPDATED: Sorry, but you have a small error somewhere what you didn't posted. To close the problem I created a small project with an old version of Visual Studio (VS2008) which has practically exactly your code and which work. I placed it on http://www.ok-soft-gmbh.com/jQuery/WSMember.zip. You can download it, compile and verify that it works. Then you can compare your code with my and find your error.
Best regards
If you are doing a post to your data, why are you defining UseHttpGet = true? Shouldn't that be false to match the response type from your request? Also, putting a breakpoint in the ws call to see exactly what the serializer returns would help too... I don't think it should return a JSON object if the return value is a string.
HTH.
Yes, definitely do not manually serialize the object. If you return a Member type, the framework will handle the JSON serialization for you.
When you're seeing the [object XMLHttpRequest] alert, that sounds like it's getting into the error handler in your $.ajax() call, where the response passes in its XHR object as the first parameter. You're probably getting a 500 error on the server.
Here's an example of decoding the ASP.NET AJAX error response in jQuery. Most simply, change your error handler to this:
error: function(xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
alert(err.Message);
}
That will give you some insight into what the specific error is.
If you are returning any complex object (relational objects with foreign keys), you have 2 options:
Use a DTO object
Write your own specific serialization converter
i have bad english, but this is a solution
----- WSMember.asmx ------
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class WSMember : System.Web.Services.WebService {
public WSMember () {
}
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string GetMember(int IdMember)
{
Member m = new Member();//Get Member from DB, exam Linq to Sql
m.Surname = "Smith";
m.FirstName = "John";
return string.Format("{{ \"Surname\":\"{0}\",\"FirstName\":\"{1}\" }}",m.Surname,m.FirstName);
}
}
---- Default.aspx ----
Just a test
<script type="text/javascript">
$("#button1").click(function (event) {
event.preventDefault();
$.ajax({
type: "POST",
url: "WSMember.asmx/GetMember",
data: "{IdMember: 2 }",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
if (msg.hasOwnProperty('d')) {
msg = msg.d;
}
var json = JSON.parse(msg);
console.log(json.Surname);
console.log(json.FirstName);
},
error: function (xhr, status, error) {
//console.log(xhr);
//console.log(status);
//console.log(error);
}
});
});
</script>
I'm trying to call web service function via GET method using jQuery, but having a problem. This is a web service code:
[WebService(Namespace = "http://something.com/samples")]
[ScriptService]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class TestWebService : System.Web.Services.WebService {
[WebMethod]
public string Test2()
{
string result = null;
try
{
result = "{'result':'success', 'datetime':'" + DateTime.Now.ToString() + "'";
}
catch (Exception ex)
{
result = "Something wrong happened";
}
return result;
}
}
That's the way I call the function:
$.ajax({ type: "GET",
url: "http://localhost/testwebsite/TestWebService.asmx/Test2",
data: "{}",
contentType: "application/json",
dataType: "json",
error: function (xhr, status, error) {
alert(xhr.responseText);
},
success: function (msg) {
alert('Call was successful!');
}
});
Method is called successfully, but result string gets covered by XML tags, like this:
<string>
{'result':'success', 'datetime':'4/26/2010 12:11:18 PM'
</string>
And I get an error because of this (error handler is called). Does anybody know what can be done about this?
Enable ASP.NET ASMX web service for HTTP POST / GET requests
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public string Test2()
{
[...]
}
Rule for json:
You can only access data from the same domain!
The only exception is when using jsonp (which is quite complicated to implement since there is no jsonp serializer in the .NET framework).
If your are using a standard web service (and not WCF) you can find guidance howto implement this here.
Make sure to add this to your ajax options:
contentType: "application/json; charset=utf-8"
Your overall request should look like this to get json back instead of XML:
$.ajax({ type: "GET",
url: "http://localhost/testwebsite/TestWebService.asmx/Test2",
data: "{}",
contentType: "application/json",
dataType: "json",
contentType: "application/json; charset=utf-8".
error: function (xhr, status, error) {
alert(xhr.responseText);
},
success: function (msg) {
alert('Call was successful!');
}
});
ScottGu has a full breakdown on what's required here, but it looks like the missing contentType in your case (that one drove me nuts for a while too).
You might try setting the ResponseFormat on your methods. See http://williamsportwebdeveloper.com/cgi/wp/?p=494 to see how they did it for JSON. It probably just defaults to XML.
You need to decorate the method with the ScriptMethodAttribute:
[WebService(Namespace = "http://something.com/samples")]
[ScriptService]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class TestWebService : System.Web.Services.WebService {
[WebMethod]
[ScriptMethod]
public string Test2()
{
[...]
}
}
This will ensure that the method returns JSON by default (the default value of ResponseFormat is Json).
Did you try WebInvokeAttribute, it has members that define Request & Response formats where you can set to WebMessageFormat.Json.
Something like:
[WebInvoke(UriTemplate = "ServiceName", RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare,
Method = "POST")]
You can use http handler instead of
web service.
You can parse xml response with
javascript on the client.