I am going nuts here. I've looked at the following entries and none of them are correcting the aberrant behavior I am seeing:
I've also looked at, and confirmed my setup: http://www.asp.net/AJAX/documentation/live/ConfiguringASPNETAJAX.aspx
Here is my code (ASMX code behind):
namespace RivWorks.Web.Services
{
/// <summary>
/// Summary description for Negotiate
/// </summary>
[WebService(Namespace = "http://rivworks.com/webservices/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[ScriptService]
public class Negotiate : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public RivWorks.Data.Objects.rivProduct GetSetup(string jsonInput)
{
// Deserialize the input and get all the data we need...
// TODO: This is a quick hack just to work with this for now...
char[] tokens = { '(', '{', '}', ')', ',', '"' };
string[] inputs = jsonInput.Split(tokens);
string inputRef = "";
string inputDate = "";
string inputProductID = "";
for (int i = 0; i < inputs.Length; i++)
{
if (inputs[i].Equals("ref", StringComparison.CurrentCultureIgnoreCase))
inputRef = inputs[i+2];
if (inputs[i].Equals("dt", StringComparison.CurrentCultureIgnoreCase))
inputDate = inputs[i+2];
if (inputs[i].Equals("productid", StringComparison.CurrentCultureIgnoreCase))
inputProductID = inputs[i+2];
}
Guid pid = new Guid(inputProductID);
RivWorks.Data.Objects.rivProduct product = RivWorks.Data.rivProducts.GetProductById(pid);
return product;
}
}
When I run this from my localhost instance I am getting this result set:
<ResultSet>
<uiType>modal</uiType>
<width>775</width>
<height>600</height>
<swfSource>
http://localhost.rivworks.com/flash/negotiationPlayer.swf
</swfSource>
<buttonConfig>
http://cdn1.rivworks.com/Element/Misc/734972de-40ae-45f3-9610-5331ddd6e8f8/apple-logo-2.jpg
</buttonConfig>
</ResultSet>
What am I missing???
NOTE: I am using the 3.5 framework (or at least I thought I was as everything in my web.config is marked for 3.5.0.0)
UPDATE: I am browsing to the service and using the input box on that page. You can try here: http://dev.rivworks.com/services/Negotiate.asmx?op=GetSetup. We are also trying to access it from a JS based web app running on another site (the main purpose of this particular service). I do not have the code for that here. (Sorry, the test form is only available from localhost.)
UPDATE: I added the following test page (JsonTest.htm) to try to see what was going back and forth. All I get is a 500 error! I even tried attaching to the process and break into my service. THe 500 error is thrown before the ASP pipeline ever gets into my code.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Untitled Page</title>
<script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.js" type="text/javascript"></script>
<script language="javascript" type="text/javascript">
function sendReq() {
alert("Before AJAX call");
$.ajax(
{
type: "POST"
, url: "http://kab.rivworks.com/Services/Negotiate.asmx/GetSetup"
, data: "{ \"ref\":\"http://www.rivworks.com/page.htm\", \"dt\":\"Mon Dec 14 2009 10:45:25 GMT-0700 (MST)\", \"productId\":\"5fea7947-251d-4779-85b7-36796edfe7a3\" }"
, contentType: "application/json; charset=utf-8"
, dataType: "json"
, success: GetMessagesBack
, error: Failure
}
);
alert("After AJAX call");
}
function GetMessagesBack(data, textStatus) {
alert(textStatus + "\n" + data);
}
function Failure(XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus + "\n" + errorThrown + "\n" + XMLHttpRequest);
}
</script>
</head>
<body>
<div id="test">Bleh</div>
<a href="javascript:sendReq()">Test it</a>
</body>
</html>
Why is this so painfully hard?!?! :)
UPDATE: Working through a WCF service. Here is my setup: Interface:
namespace RivWorks.Web.Services
{
[ServiceContract(Name = "Negotiater", Namespace = "http://www.rivworks.com/services")]
public interface INegotiaterJSON
{
//[WebMethod]
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[ScriptMethod(UseHttpGet = false, ResponseFormat = ResponseFormat.Json)]
ResultSet GetSetup(string jsonInput);
}
}
Class:
namespace RivWorks.Web.Services
{
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Negotiater : INegotiaterJSON
{
public ResultSet GetSetup(string jsonInput)
{
//code removed for brevity - see ASMX code above if you are really interested.
return resultSet;
}
}
[DataContract()]
public class ResultSet
{
[DataMember]
public string uiType = "modal";
[DataMember]
public int width = 775;
[DataMember]
public int height = 600;
[DataMember]
public string swfSource = "";
[DataMember]
public string buttonConfig = "";
}
}
web.config
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name ="soapBinding">
<security mode="None" />
</binding>
</basicHttpBinding>
<webHttpBinding>
<binding name="webBinding">
<security mode="None" />
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="poxBehavior">
<webHttp/>
</behavior>
<behavior name="jsonBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="defaultBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="RivWorks.Web.Services.Negotiater" behaviorConfiguration="defaultBehavior">
<endpoint address="json"
binding="webHttpBinding"
bindingConfiguration="webBinding"
behaviorConfiguration="jsonBehavior"
contract="RivWorks.Web.Services.INegotiaterJSON" />
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
<baseAddressPrefixFilters>
<add prefix="http://dev.rivworks.com" />
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
</system.serviceModel>
simple test page
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Untitled Page</title>
<script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.js" type="text/javascript"></script>
<script language="javascript" type="text/javascript">
function sendReq() {
alert("Before AJAX call");
$.ajax(
{
type: "POST"
, url: "http://dev.rivworks.com/Services/Negotiater.svc/GetSetup"
, data: "{ \"ref\":\"http://www.rivworks.com/page.htm\", \"dt\":\"Mon Dec 14 2009 10:45:25 GMT-0700 (MST)\", \"productId\":\"5fea7947-251d-4779-85b7-36796edfe7a3\" }"
, contentType: "application/json; charset=utf-8"
, dataType: "json"
, success: GetMessagesBack
, error: Failure
}
);
alert("After AJAX call");
}
function GetMessagesBack(data, textStatus) {
alert(textStatus + "\n" + data);
}
function Failure(XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus + "\n" + errorThrown + "\n" + XMLHttpRequest);
}
</script>
</head>
<body>
<div id="test">Bleh</div>
<!--<button onclick="javascript:sendReq()">TEST IT</button>-->
<a href="javascript:sendReq()">Test it</a>
</body>
</html>
And now I am getting this error: IIS specified authentication schemes 'IntegratedWindowsAuthentication, Anonymous', but the binding only supports specification of exactly one authentication scheme. Valid authentication schemes are Digest, Negotiate, NTLM, Basic, or Anonymous. Change the IIS settings so that only a single authentication scheme is used.
How do I handle this? <state emotion='wrung out' physical='beat up' />
For example you can use below code (if you are using jquery) instead of changing somethings in WebService: $. ajax({ type: "POST", url: '/ServiceName. asmx/WebMethodName', date: {}, contentType: "application/json; charset=utf-8", success: function (data) { // Some code; } });
ASMX provides the ability to build web services that send messages using the Simple Object Access Protocol (SOAP). SOAP is a platform-independent and language-independent protocol for building and accessing web services.
Asmx files, as far as I've ever seen, are always SOAP based services, and can't be RESTful.
Why don't you migrate your ASMX webservice to WCF?
The WCF API in .NET Framework 3.5 supports JSON web services natively.
In addition Microsoft declared ASMX as "legacy technology", and suggests "Web services and XML Web service clients should now be created using Windows Communication Foundation (WCF)". (Source).
You may want to check out these links to get started:
In addition, you may also want to read through the following example which I "extracted" from a self-hosted WCF project of mine. Self-hosted WCF services do not require IIS, but can be served from any managed .NET application. This example is being hosted in a very simple C# Console Application:
IContract.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace MyFirstWCF
{
[ServiceContract]
public interface IContract
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json, UriTemplate = "/CustomerName/{CustomerID}")]
string GET_CustomerName(string CustomerID);
}
}
Service.cs
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Syndication;
using System.ServiceModel.Web;
namespace MyFirstWCF
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.NotAllowed)]
public class Service : IContract
{
public string GET_CustomerName(string CustomerID)
{
return "Customer Name: " + CustomerID;
}
}
}
WCFHost.cs (Console Application)
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Description;
using System.Threading;
using System.Text;
namespace MyFirstWCF
{
class Program
{
private static WebServiceHost M_HostWeb = null;
static void Main(string[] args)
{
M_HostWeb = new WebServiceHost(typeof(MyFirstWCF.Service));
M_HostWeb.Open();
Console.WriteLine("HOST OPEN");
Console.ReadKey();
M_HostWeb.Close();
}
}
}
app.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="MyFirstWCF.Service">
<endpoint address="http://127.0.0.1:8000/api"
binding="webHttpBinding"
contract="MyFirstWCF.IContract" />
</service>
</services>
</system.serviceModel>
</configuration>
The above example is very basic. If you build a request with Fiddler to http://127.0.0.1:8000/api/CustomerName/1000
it will simply return "Customer Name: 1000"
.
Make sure to set the content-type: application/json
in the request header. To return more complex data structures, you will have to use Data Contracts. These are constructed as follows:
[DataContract]
public class POSITION
{
[DataMember]
public int AssetID { get; set; }
[DataMember]
public decimal Latitude { get; set; }
[DataMember]
public decimal Longitude { get; set; }
}
You need to add .NET References to System.RuntimeSerialization
, System.ServiceModel
and System.ServiceModel.Web
for this example project to compile.
What's the "Content-Type" set to on the request to the method?
From what I've done with the ASP.NET, if it's set to text/xml
, you'll get back XML; but if it's set to application/json
, you'll get JSON back.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With