My requirement is to be able to call a simple WCF service from both Jquery Ajax and also by adding a service reference.
This is easily done in asmx services and I am really struggling to see how WCF can be "better" and "more powerful" when this simple task is proving so difficult and convoluted.
I have followed various tutorials such as:
http://www.codeproject.com/Articles/132809/Calling-WCF-Services-using-jQuery
http://www.codeproject.com/Articles/540169/CallingplusWCFplusServicespluswithplusjQuery-e2-80
http://blog.thomaslebrun.net/2011/11/jquery-calling-a-wcf-service-from-jquery/#.UihK6saa5No
However I always end up with a solution where I can call by ServiceReference but not Jquery or vice-versa.
For the following simple service, can anyone please provide me with the:
Necessary attributes to decorate the service and interface with
Web.config ServiceModel sections with all bindings/endpoints/behaviours/etc
to facilitate calling the WCF service from both Jquery (ajax) and by adding a service reference in a .net project?
Or should I just go back to good old simple (but apparently less powerful) amsx?
I have used webhttpbinding for the WCF service to be called from javascript.
Web.config:
<system.serviceModel>
<services>
<service name="WCF.TestWCF" behaviorConfiguration="TestWCFBehaviour">
<endpoint address="" binding="webHttpBinding" contract="WCF.ITestWCF" behaviorConfiguration="TestWCFEndPointBehaviour"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="TestWCFBehaviour">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="TestWCFEndPointBehaviour">
<enableWebScript/>
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
service:
namespace WCF{
[ServiceContract(Namespace = "Saranya")]
public interface ITestWCF
{
[OperationContract]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Xml)]
String HelloWorld();
}}
namespace WCF{
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
public class TestWCF:ITestWCF
{
public String HelloWorld()
{
return "Hello World!!";
}
}
Using Jquery:
$.post("http://localhost:26850/Service1.svc/HelloWorld?", null, fnsuccesscallback, "xml");
function fnsuccesscallback(data) {
alert(data.xml);
}
using service reference:
obj = new Saranya.ITestWCF();
obj.HelloWorld(fnsuccesscallback);
function fnsuccesscallback(data) {
alert(data.xml);
}
Related
ILeaveManagement class
[ServiceContract]
public interface ILeaveManagement
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "get")]
List<ServiceReference1.LeaveRequest> GetLeaveDetails();
}
LeaveManagement class
public class LeaveManagement : ILeaveManagement
{
public List<ServiceReference1.LeaveRequest> GetLeaveDetails()
{
try
{
var entities = new ServiceReference1.leaverequest_Entities(new Uri(serviceUrl));
var result = entities.LeaveRequestCollection;
return result.ToList();
}
catch
{
return new List<ServiceReference1.LeaveRequest>();
}
}
}
configuration
<service behaviorConfiguration="DRLExternalList.LeaveManagementBehavior" name="DRLExternalList.LeaveManagement">
<endpoint address="" binding="wsHttpBinding" contract="DRLExternalList.ILeaveManagement"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
<behavior name="DRLExternalList.LeaveManagementBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
I have deployed the project in IIS 7.5. When i run the application , it is saying BadRequest.
I have verrified in fiddler. i saw 400 error.
Please help me on this.
Try using webHttpBinding in your endpoint instead of the wsHttpBinding, or add it as an additional one and change the address. I use a bindingNamespace in my project, but I don't think you need it.
<endpoint address="XMLService"
binding="webHttpBinding"
behaviorConfiguration="restXMLBehavior"
contract="DRLExternalList.ILeaveManagement">
</endpoint>
Add an Endpoint Behavior
<endpointBehaviors>
<!-- Behavior for the REST endpoint -->
<behavior name="restXMLBehavior">
<webHttp helpEnabled="true"/>
</behavior>
</endpointBehaviors>
I also annotate the OperationContract slightly differently, but it shouldn't make all that much of a difference. I'll give it to you just in case...
[WebGet(UriTemplate = "/GetLeaveDetails", ResponseFormat = WebMessageFormat.Xml)]
To call the service, it would look like this using the XMLService endpoint name:
http://myWebHost.com/WebService/MyService.svc/XMLService/GetLeaveDetails
Hosting an wcf service into a website issue : System.ArgumentException: ServiceHost only supports class service types
the above link helped me to solve my issue.
<%# ServiceHost Language="C#" Debug="true" Service="restleave.ProductRESTService" %>
I am creating a simple WCF Restful service. Currently when I browse to: localhost/AzamSharpService.svc it shows me the web services default page where I can examine WSDL.
I want to browse to localhost/AzamSharpService.svc/LatestArticles and get the json from the GetLatestArticles method. Currently, when the browse to the /LatestArticles url it says page not found.
The implementation is shown below:
[ServiceContract]
public interface IAzamSharpService
{
[OperationContract]
[WebGet(BodyStyle = WebMessageBodyStyle.Bare, RequestFormat =WebMessageFormat.Json,ResponseFormat = WebMessageFormat.Json, UriTemplate = "/LatestArticles")]
List<ArticleContract> GetArticles();
}
public class AzamSharpService : IAzamSharpService
{
public List<ArticleContract> GetArticles()
{
var articles = new List<ArticleContract>()
{
new ArticleContract() {Title = "iOS"},
new ArticleContract() { Title="Android"},
new ArticleContract() { Title = "Windows 7"}
};
return articles;
}
}
The configuration is shown below:
<system.serviceModel>
<services>
<service name="AzamSharpNewLook.AzamSharpService">
<endpoint address="AzamSharpService.svc"
binding="webHttpBinding"
contract="AzamSharpNewLook.IAzamSharpService"
behaviorConfiguration="webby"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="webby">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="false" />
</system.serviceModel>
A couple of things to try... set endpoint address to empty string...in the webHttp node try enabling help... and you should be able to navigate to localhost/AzamSharpService.svc/help and get more info. Lastly I would use fiddler and construct a get request to the appropriate address, then just check the response and you should have what you need. Hope this helps...
trying to build a RestFull service with wcf running in the WcfTestClient.exe. The problem is that I get an error:
Failed to add a service. Service metadata may not be accessible.
I added a mex endpoint in the config file but does not solve it:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="MyRest.Service" behaviorConfiguration="ServBehave">
<!--Endpoint for REST-->
<endpoint
address="XMLService"
binding="webHttpBinding"
behaviorConfiguration="restPoxBehavior"
contract="MyRest.IService"/>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServBehave" >
<!-- 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 for the REST endpoint for Help enability-->
<behavior name="restPoxBehavior">
<webHttp helpEnabled="true"/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
IService1.cs
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet(UriTemplate = "/Employees", ResponseFormat = WebMessageFormat.Xml)]
Employee[] GetEmployees();
}
[DataContract]
public class Employee
{
[DataMember]
public int EmpNo { get; set; }
[DataMember]
public string EmpName { get; set; }
[DataMember]
public string DeptName { get; set; }
}
Service1.cs
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class Service1 : IService1
{
public Employee[] GetEmployees()
{
return new Employee[]
{
new Employee() {EmpNo=101,EmpName="Mahesh",DeptName="CTD"},
new Employee() {EmpNo=102,EmpName="Akash",DeptName="HRD"}
};
}
}
With WCF Restful service, do you actually need meta-data to expose service or to work on it? The answer is "NO". It's against the principles of Rest. Meta-data represents the interface(the operations), and for REST interface is fixed(http methods). WcfTestClient is for testing SOAP based Service(as they have to expose their interface through mex bindings).
Testing a RESTFUL service for http get could be vary easy. you just have to invoke it from your browser, using the URL. To test other http methods, you have to build your custom client.
If this seems a big task, then you could also use tools like Fiddler to build request data. An example could be seen here
I came across a page on MSDN explaining transaction in WCF Services here. I tweaked the binding settings and used netTcpBinding. Here is the serviceModel section of my app.config file:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="netTcpBindingConfiguration1" transactionFlow="true">
<security mode="Message" />
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="OrderingService.OrderService">
<clear />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"
listenUriMode="Explicit">
</endpoint>
<endpoint address="net.tcp://localhost:8880/OrderingService"
binding="netTcpBinding" bindingConfiguration="netTcpBindingConfiguration1"
contract="OrderingService.IOrderService" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8888/OrderingService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" />
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
I created a windows application as the client of the service. I used netstat command to see the TCP connections between the client and the service (hosted in a console application). I realized for each operation (which was a button click in my client app that places a new order by invoking the methods of the service's proxy class), a new connection is created and all previous connections still remain ESTABLISHED. Obviously, this is not an ideal condition. I wondered what I did wrong and what setting or configuration would work out this problem by reducing the number of connections to only one. By the way, the service class that implements the service interface has InstanceContextMode set to PerSession. Here are the contract interface and the service class:
[ServiceContract(SessionMode=SessionMode.Required)]
public interface IOrderService
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.NotAllowed)]
List<Customer> GetCustomers();
[OperationContract]
[TransactionFlow(TransactionFlowOption.NotAllowed)]
List<Product> GetProducts();
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
string PlaceOrder(Order order);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
string AdjustInventory(int productId, int quantity);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
string AdjustBalance(int customerId, decimal amount);
}
[ServiceBehavior(TransactionIsolationLevel = IsolationLevel.Serializable,
TransactionTimeout = "00:00:20",
InstanceContextMode = InstanceContextMode.PerSession,
TransactionAutoCompleteOnSessionClose = true)]
public class OrderService : IOrderService
{...}
Here is the code the uses the proxy class in the client app:
using (TransactionScope scope = new TransactionScope())
{
try
{
proxy = new OrderServiceClient("NetTcpBinding_IOrderService");
result = proxy.PlaceOrder(order);
MessageBox.Show(result);
result = proxy.AdjustInventory(product.ProductId, quantity);
MessageBox.Show(result);
result = proxy.AdjustBalance(customer.CustomerId, product.Price * quantity);
MessageBox.Show(result);
proxy.Close();
scope.Complete();
}
catch (Exception exc)
{
MessageBox.Show("Error occurred: " + exc.Message);
}
}
With regards to the TCP connection remaining ESTABLISHED - are you calling .Close() on your instance of the client when you are finished with it?
If you want to use a single connection you should change the instance context mode to 'Single' and reuse the connection you establish in the client to process all your service calls. This suits an architecture where you want to maintain state within your service.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Service : IService
{
}
I found this link very helpful when I was learning about context modes in WCF: CodeProject link
As you are currently using PerSession context mode you should be able to limit it to a single connection by adding a setting for maxConcurrentSessions in your behaviors section. You can do it like this:
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" />
<serviceDebug includeExceptionDetailInFaults="False" />
<serviceThrottling maxConcurrentSessions="1" />
</behavior>
</serviceBehaviors>
This would only be a good idea if you have a single client.
I have a WCF rest webservice. It is working fine. I am wanting to understand the different configuration values available within the endpoint element.
In particular, I'm trying to understand the purpose of the address element. Changing the value doesn't seem to change how I can address the service. For this, I'm running the service from visual studio 2010 and cassini. the port number is set to 888.
with address set to an empty string i get...
http://localhost:888/restDataService.svc/hello will return "hello world".
with address set to "localhost" i get...
http://localhost:888/restDataService.svc/hello will return "hello world".
with address set to "pox" i get...
http://localhost:888/restDataService.svc/hello will return "hello world".
It doesn't matter what value I set into the address field. It doesn't impact the url. My only explanation that I have is that the value is more for non-REST services.
<system.serviceModel>
<services>
<service behaviorConfiguration="MobileService2.DataServiceBehaviour" name="MobileService2.DataService">
<endpoint address="pox" binding="webHttpBinding" contract="MobileService2.IRestDataService" behaviorConfiguration="webHttp">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="webHttp">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="MobileService2.DataServiceBehaviour" >
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
I also have the following service contract
[ServiceContract]
public interface IRestDataService
{
[OperationContract]
[WebGet(UriTemplate = "hello")]
string Hello();
}
And in the .svc
<%# ServiceHost Language="C#" Debug="true"
Service="MobileService2.RestDataService"
Factory="System.ServiceModel.Activation.WebServiceHostFactory"
CodeBehind="RestDataService.svc.cs" %>
And the 'code-behind'
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class RestDataService : IRestDataService
{
public string Hello()
{
return "hello";
}
}
Can you also show service element of your configuration? I think that your configuration is not used or you are accessing other instance of the application (did you configure Cassini to use port 80?) because your second and third test should return HTTP 404 Resource not found.
Correct addresses for your tests are:
http://localhost/restDataService.svc/hello
http://localhost/restDataService.svc/localhost/hello
http://localhost/restDataService.svc/pox/hello
Check that your name in service element is exactly the same as name of service type (including namespaces) as used in ServiceHost directive in .svc markup.