I am having problems calling my WCF service via jquery / JSON.
So far I have done the following:
In VS 2010, start a new "WCF Service Application" project. Visual Studio then auto generates a sample service called IService / Service, which has the function
string GetData(int value);
Inside IService.cs I add the WebGet attribute, as follows:
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
string GetData(int value);
Inside my web.config I have
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="WcfService1.Service1"
behaviorConfiguration="ServiceBehavior">
<endpoint contract="WcfService1.IService1"
binding="webHttpBinding"
behaviorConfiguration="AjaxBehavior" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
<behavior name="ServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="AjaxBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
I build and run the service, and on opening
http://localhost:58403/Service1.svc/GetData?value=1
in my web browser it prints out (as expected)
{"d":"You entered: 1"}
5, I create a new asp.net web application project. Inside default.aspx, I add
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
var request = $.ajax({
type: "GET",
url: "http://localhost:58403/Service1.svc/GetData",
data: { value: "1" }
});
request.done(function (msg) {
alert(msg);
});
request.fail(function (jqXHR, textStatus) {
alert("Request failed: " + textStatus);
});
});
</script>
6, I build and run that, but instead of hitting the done callback, it hits the error callback and alerts "Request failed: error"
If I set a breakpoint in the service code, I can see that the GetData function is being hit and appears to return successfully. I can also see in the firebug net console that the web service call is returning a status code of "200 OK", but the error handler callback is being hit instead of the success callback. Does anyone know what I am doing wrong?
Well, I managed to solve this on my own. In case anyone is reading this and is curious, I changed the WCF service and web application so that they now both run via IIS instead of Visual Studio's web server.
So I now have
http://localhost/WcfService1/Service1.svc/GetData?value=1
http://localhost/WebApplication1/
I believe it was not working previously due to cross domain requests. Even though it was same domain, just different port numbers, I believe this still counts as cross domain?
Related
I have developed a REST service that used to run localy on my PC and had no issues!!I have hosted my wcf on a windows server 2008-r2 IIS 7.5, in order to call my service from an IP. I am using the get method with a JSON and all works fine, but when i try the post( with chrome plugin) i get 405 error and 500 error. I checked the MIME-TYPES and added json for IIS. Any solution or suggestiong how to resolve this error would be very useful.
I will post my webconfig and ISERVICE files as well.
My webConfig file is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<compilation targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="RestService.RestServiceImpl" behaviorConfiguration="ServiceBehaviour">
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="" binding="webHttpBinding" contract="RestService.IRestServiceImpl" behaviorConfiguration="Services.webHttpBehavior">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true" />
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
<behavior name="Services.webHttpBehavior">
<webHttp defaultOutgoingResponseFormat="Json" />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<diagnostics>
<messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" />
</diagnostics>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<!-- <staticContent>
<mimeMap fileExtension=".json" mimeType="application/json"/>
</staticContent>-->
</system.webServer>
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
<listeners>
<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="C:\wcflog3.txt" />
</listeners>
</source>
</sources>
</system.diagnostics>
</configuration>
My Service Implementtion is as followes:
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "xml/{str}")]
string XMLData(string str);
[OperationContract]
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Json,
UriTemplate = "jsoncheckifexists")]
bool CheckIfExists(RestService.RestServiceImpl.UrlObject data);
The GET is working just fine, I try the POST calling the function CheckIfExists:
public bool CheckIfExists(UrlObject urlObject)
{
string link= urlObject.url;
//Standard logon to CRM procedure(Framework)
if abc=true
return true;
else false;
}
My wcf reset service has only 2 contracts, one is working always and the other did not work.
Service Code:
Public Class BasicServ
Implements IBasicServ
Public Function DoWork() Implements IBasicServ.DoWork
Return "Working"
End Function
Function Authorize(ByVal id As String, ByVal pw As String) Implements IBasicServ.Authorize
Dim c As New List(Of Guid)
For i = 0 To 10
c.Add(Guid.NewGuid)
Next
Return c
'Return Guid.NewGuid
End Function
End Class
Contract File code:
<ServiceContract()>
Public Interface IBasicServ
<OperationContract()>
<WebGet(UriTemplate:="test/", BodyStyle:=WebMessageBodyStyle.Wrapped, RequestFormat:=WebMessageFormat.Json, ResponseFormat:=WebMessageFormat.Json)>
Function DoWork()
<OperationContract()>
<WebGet(UriTemplate:="Authorize/{id}/{pw}", BodyStyle:=WebMessageBodyStyle.Wrapped, RequestFormat:=WebMessageFormat.Json, ResponseFormat:=WebMessageFormat.Json)>
Function Authorize(ByVal id As String, ByVal pw As String)
End Interface
Web Config File:
<?xml version="1.0"?>
<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="messagelistener"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="d:\logs\myMessages.svclog"></add>
</listeners>
</source>
</sources>
<trace autoflush="true"/>
</system.diagnostics>
<system.web>
<compilation debug="true" strict="false" explicit="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true"
logMessagesAtServiceLevel="false"
logMessagesAtTransportLevel="false"
logMalformedMessages="true"
maxMessagesToLog="5000"
maxSizeOfMessageToLog="2000">
</messageLogging>
</diagnostics>
<services>
<service behaviorConfiguration="ServBehav" name="AssistantWcf.BasicServ">
<endpoint address="auth" behaviorConfiguration="EndBehav" binding="webHttpBinding" name="endpointname" contract="AssistantWcf.IBasicServ" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="EndBehav">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServBehav">
<!-- To avoid disclosing metadata information, set the value below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpGetBinding="webHttpBinding" httpGetBindingConfiguration="" />
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
While debugging/testing, I found that, if I return only 1 GUID in Authoriza method, it is working, but when I am sending a list of GUID, it is not working, and the SVClog file is not getting created. Could you please help me understand WCF REST service better. Thank you.
From above comments and few experiments, the solution for the question is that a return type is not compulsory if it is string, but if anything else, return type must be specified. Better if return type is provided always.
WCF Rest POST is always getting null string. I have spend more than a week time to explore but no luck so far...
My Service Code:
[ServiceContract]
public interface ISaveSurvey
{
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "/SSS")]
bool InsertSiteSurveyInfo(string jsonString);
}
Web Config:
<compilation debug="false" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="Honeywell.HBS.SiteSurvey.SaveSurvey" behaviorConfiguration="SaveSurvey">
<endpoint address="" binding="webHttpBinding" contract="Honeywell.HBS.SiteSurvey.ISaveSurvey" behaviorConfiguration="wcfRestBehavior"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="SaveSurvey">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="wcfRestBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<!-- Customizations for REST service -->
<webHttpBinding>
<binding name="ApiExportBinding" maxReceivedMessageSize="10485760"
maxBufferPoolSize="10485760" maxBufferSize="10485760">
<readerQuotas maxDepth="32" maxStringContentLength="10485760"
maxArrayLength="10485760" maxBytesPerRead="10485760" />
<security mode="None" />
</binding>
</webHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
Client Code:
<script type="text/javascript" language="javascript">
function testRest() {
$.ajax({
type: "POST",
dataType: "json",
url: "http://ie22ltjpsd4bs/SSTest/SaveSurvey.svc/SSS",
contentType: "application/json",
data: "{\"siteInformation\":{\"siteName\":\"Malar\",\"siteNumber\":\"123344555\",\"siteContactPerson\":\"test\",\"siteAddress\":\"test\",\"siteCity\":\"test\",\"sitePostalZipCode\":\"test\",\"siteTelephone\":1234576788,\"siteContractNumber\":\"asdfasdf\",\"siteHoneywellBranch\":\"asdfasdf\",\"siteFieldSiteLeader\":\"asdfasdf\",\"siteTeamLead\":\"asdfasdf\",\"siteTechnician\":\"asdfasdf\",\"equipments\":[{\"equipmentID\":\"BRANCH TOOL INVENTORY\",\"equipSiteContactTelephone\":12345678,\"equipDescription\":\"asdfasdf\",\"equipLocation\":\"asdfasdf\",\"equipSupervisionOrFrontEnd\":\"asdfasdf\",\"equipNumberOfStations\":12,\"equipMakeOrTypePC\":\"asdfasdf\",\"equipWindowsVersion\":\"asdfasdf\",\"equipManufacturer\":\"A C MOTOR\",\"equipManufacturerDateOrAge\":\"1979-12-31T18:30:00.000Z\",\"equipProductNameOrVersion\":\"asdfasdf\",\"equipGraphicSoftwareIncl\":\"No\",\"equipExistingSaveBackup\":\"Yes\",\"equipBackupSaveFormat\":\"\",\"equipLocalAccess\":\"asdfasdf\",\"equipPassword\":\"asdfasdfasdf\",\"equipRemoteAccess\":\"Modem\",\"equipAccessInfo\":\"asdfasdf\",\"equipSystemArchitecture\":\"Yes\",\"equipArchivedInAdept\":\"Yes\",\"equipOtherInformation\":\"asdfasdf\",\"controllersInformation\":[{\"controllerName\":\"asdfasdf\",\"controllerQuantity\":\"121\",\"controllerManufacturer\":\"asdfasdf\",\"controllerSoftwareProgram\":\"Yes\",\"controllerProductNameOrVersion\":\"asdfasdf\",\"controllerTypeOfProgram\":\"Interpreted\",\"controllerExistingSaveBackup\":\"Yes\",\"controllerBackUpSaveFormat\":\"\",\"controllerLocalAccess\":\"asdf\",\"controllerPassword\":\"asdf\",\"controllerRemoteAccess\":\"Modem\",\"controllerAccessInfo\":\"asdf\",\"controllerControlDrawings\":\"Yes\",\"controllerOperatingSequence\":\"Yes\",\"controllerOtherInformation\":\"asdfasddf\"}]}]}}",
success: function(result)
{
alert("Sucess");
},
failure: function(result)
{
alert("Failure");
}
});
}
function (result) {
}
</script>
Button Click:
<asp:Button ID="Button1" runat="server" onclick="Button1_Click" OnClientClick="testRest()" Text="Button" />
I attached the w3wp process and try to debug the service and the json string is always getting null. But I used fiddler to intercept the request the json string is getting posted bu the service implementation code always getting null..
That's planned behavior. Your service doesn't know how to map the data you pass.
If you are going to pass your json stuff as a string you should wrap it like this:
data: JSON.stringify({ jsonString: "your_data" })
I've been working in .NET for a while now, but I'm new to WCF. I'm trying to create my very first WCF service using JSON. I thought I would start really, really simple and then build from there. But I have somehow managed to screw up even the most simple of services. Here's what I've got so far.
Web.Config:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="MarathonInfo.MarathonInfoService">
<endpoint address="http://localhost:10298/MarathonInfoService.svc" binding="webHttpBinding" contract="MarathonInfo.IMarathonInfo" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="false" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Then, in the service file:
namespace MarathonInfo
{
public class MarathonInfoService : IMarathonInfo
{
public String GetData()
{
return "Hello World";
}
}
}
And in the interface:
namespace MarathonInfo
{
[ServiceContract]
public interface IMarathonInfo
{
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "/GetData", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
String GetData();
}
}
So, when I go to this url:
http://localhost:10298/MarathonInfoService.svc/GetData
I get this error:
The message with To
'http://localhost:10298/MarathonInfoService.svc/GetData' cannot be
processed at the receiver, due to an AddressFilter mismatch at the
EndpointDispatcher. Check that the sender and receiver's
EndpointAddresses agree.
I am able to execute the service just fine through Visual Studio in debug mode. But in the browser, I only get that error.
What am I doing wrong?
Thanks!
Casey
If you want to create a WCF WebHTTP Endpoint (i.e., one which returns JSON, and uses the [WebGet] / [WebInvoke] attributes), the endpoint needs to have the <webHttp/> behavior associated with it.
<system.serviceModel>
<services>
<service name="MarathonInfo.MarathonInfoService">
<endpoint address="http://localhost:10298/MarathonInfoService.svc"
binding="webHttpBinding"
contract="MarathonInfo.IMarathonInfo"
behaviorConfiguration="Web"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="Web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="false" />
</system.serviceModel>
Does anyone know, or better yet have an example, of a WCF service that will accept a form post encoded multipart/form-data ie. a file upload from a web page?
I have come up empty on google.
Ta, Ant
So, here goes...
Create your service contract which an operation which accepts a stream for its only parameter, decorate with WebInvoke as below
[ServiceContract]
public interface IService1 {
[OperationContract]
[WebInvoke(
Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "/Upload")]
void Upload(Stream data);
}
Create the class...
public class Service1 : IService1 {
public void Upload(Stream data) {
// Get header info from WebOperationContext.Current.IncomingRequest.Headers
// open and decode the multipart data, save to the desired place
}
And the config, to accept streamed data, and the maximum size
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="WebConfiguration"
maxBufferSize="65536"
maxReceivedMessageSize="2000000000"
transferMode="Streamed">
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="WebBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="Sandbox.WCFUpload.Web.Service1Behavior">
<serviceMetadata httpGetEnabled="true" httpGetUrl="" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Sandbox.WCFUpload.Web.Service1" behaviorConfiguration="Sandbox.WCFUpload.Web.Service1Behavior">
<endpoint
address=""
binding="webHttpBinding"
behaviorConfiguration="WebBehavior"
bindingConfiguration="WebConfiguration"
contract="Sandbox.WCFUpload.Web.IService1" />
</service>
</services>
</system.serviceModel>
Also in the System.Web increase the amount of data allowed in System.Web
<system.web>
<otherStuff>...</otherStuff>
<httpRuntime maxRequestLength="2000000"/>
</system.web>
This is just the basics, but allows for the addition of a Progress method to show an ajax progress bar and you may want to add some security.
I don't exactly know what you're trying to accomplish here, but there's no built-in support in "classic" SOAP-based WCF to capture and handle form post data. You'll have to do that yourself.
On the other hand, if you're talking about REST-based WCF with the webHttpBinding, you could certainly have a service methods that is decorated with the [WebInvoke()] attribute which would be called with a HTTP POST method.
[WebInvoke(Method="POST", UriTemplate="....")]
public string PostHandler(int value)
The URI template would define the URI to use where the HTTP POST should go. You'd have to hook that up to your ASP.NET form (or whatever you're using to actually do the post).
For a great introduction to REST style WCF, check out Aaron Skonnard's screen cast series on the WCF REST Starter Kit and how to use it.
Marc