Is there way to convert just some service methods in a WCF to webMethods? Or add webmethods to an existing WCF? [duplicate] - wcf

Background
I have created ASMX web services in the past and have been able to access the service from the web browser and Ajax GET requests using the address convention: MyService.asmx/MyMethod?Param=xxx
I just got started using WCF and created a new web service in my ASP.NET project. It creates a file with the .svc extension such as MyService.svc.
Current Situation
I am able to consume the service using the WcfTestClient that comes with VS2008. I am also able to create my own WCF Client by either adding a service reference in another project or using the svcutil.exe commandline to generate the proxy and config file.
The Problem
When I try to use the service from a browser using MyService.svc/MyMethod?MyParam=xxx, I get a blank page without any errors.
What I have tried
I have already added a basicHttpBinding to the web.config and made it HttpGetEnabled in the behavior configuration. I also added the [WebGet(UriTemplate = "MyMethod?MyParam={MyParam}")] attribute to my operation contract.
I have already followed the information in this other stack overflow question:
REST / SOAP EndPoints for a WCF Service
However, I either get a blank page or an HTTP 404 Error after following those steps. There's nothing special about the code. I am just taking in a string as a parameter and returning "Hello xxx". This is a basic "Hello WCF World" proof-of-concept type thing.
UPDATE - Here's the relevant code
[ServiceContract]
public interface IMyService
{
[WebGet(UriTemplate = "MyMethod/MyParam={MyParam}")]
[OperationContract]
string MyMethod(string MyParam);
}
Web.Config - system.serviceModel Section
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MyServiceBehavior" name="MyService">
<endpoint address=""
binding="wsHttpBinding" contract="IMyService" />
<endpoint address="MyService.svc"
binding="basicHttpBinding" contract="IMyService" />
<endpoint address="mex"
binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>

Looking at your web.config serviceModel section, I can see that you need to add a webHttpBinding and associate an endPointBehavior that includes webHttpGet.
Your operation contract is correct. Here's how your system.serviceModel config section should look in order for you to be able to consume the service from a GET HTTP request.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="WebBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MyServiceBehavior" name="MyService">
<endpoint address="ws" binding="wsHttpBinding" contract="IMyService"/>
<endpoint address="" behaviorConfiguration="WebBehavior"
binding="webHttpBinding"
contract="IMyService">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
Be sure to assign a different address to your wsHttpBinding endpoint, otherwise you will get an error saying that you have two endpoints listening on the same URI.
Another option is to leave the address blank in the wsHttpBinding, but assign a different address to the webHttpBinding service. However, that will change your GET address as well.
For example, if you assign the address as "asmx", you would call your service with the address "MyService.svc/asmx/MyMethod?MyParam=xxxx".

The normal WCF requests are always SOAP requests - you won't be able to get this going with just your browser, you'll need the WCF Testclient for that.
There is an add-on for WCF called the WCF REST Starter Kit (which will also be included in WCF 4.0 with .NET 4.0), which allows you to use GET/POST/PUT/DELETE HTTP commands to query WCF services and such. You need to write your services specifically for REST, though - you can't have SOAP and REST on the same service call.
Marc

As marc_s says, the REST Starter Kit can help, but you should also be aware that .NET 3.5 has support for REST services directly in it. It's not quite as complete as what you can do with the starter kit, but it is useful.
The way it works is that you put a [WebGet] attribute on your operations to indicate where in the URL the various parameters should come from:
[WebGet(UriTemplate = "helloworld/{name}")]
string Helloworld(string name);
See this portal for tons of information.
Note, you can have the same service exposed as both SOAP and REST if you specify multiple endpoints/bindings in the configuration.

Related

Converting WCF SOAP Service Library to REST Service library for MVC

Problem Statement:
We have built MVC 4 application using WCF Service library (not WCF Service Application with svc file). All of the MVC CRUD operations we are doing through WCF SOAP Service library.Everything is working fine.Now suddenly client has changed requirement and asking us to convert WCF SOAP to REST.
I went through many URL's for converting WCF SOAP to REST.In all the URL's they have mentioned converting WCF SOAP Service Application to WCF REST not the WCF SOAP Service library to WCF REST.
My question is can we convert WCF Service library in SOAP to REST.??Is Conversion is same for both WCF Service library and WCF Service Application.??If possible does it impact too much,in changing the existing code??
It would be great if anyone can suggest the better way of converting WCF SOAP to REST in MVC with some URL's and explanation.
Not sure if it helps, but i have done WCF library which is exposed to Soap and REST at the same time. REST exposes XML/JSON and return type depends on input request.
It can be configured via config file, mine looked like this:
<behaviors>
<serviceBehaviors>
<behavior name="BehaviourService">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="BehaviourEndPoint"></behavior>
<behavior name="BehaviourWebHttp">
<webHttp defaultBodyStyle="Wrapped" faultExceptionEnabled="True" automaticFormatSelectionEnabled="True"/>
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="NameSpace.MyClass" behaviorConfiguration="BehaviourService" >
<!--SoapUI-->
<endpoint name="Name" address ="soap" binding="basicHttpBinding" contract="NameSpace.IMyClass"></endpoint>
<!--Rest-->
<endpoint name="Name" address="" binding="webHttpBinding" behaviorConfiguration="BehaviourWebHttp" contract="NameSpace.IMyClass" ></endpoint>
<!--MEX-->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:89/MyAddress"/>
</baseAddresses>
</host>
</service>
</services>
And service like:
[ServiceContract(Namespace = "http://www.mycompany.com", Name = "MyName")]
[DataContractFormat]
public interface IMyClass
{
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "MyMethod", Method = "POST")]
bool MyMethod();
}

How to publish WSDL for WCF 4.0 service with REST/SOAP endpoints

I'm creating a WCF4 service with REST and SOAP endpoints to be hosted in IIS 7.5.
I have used the WCF4 REST template as an example.
However I have a few questions regarding my setup so far.
Here's my webconfig
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<behaviors>
<endpointBehaviors>
<behavior name="REST">
<webHttp helpEnabled="true"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="MEXGET">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MEXGET" name="Project.WebService.VehicleService">
<endpoint
address=""
behaviorConfiguration="REST"
binding="webHttpBinding"
contract="Project.WebService.IVehicleService" />
<endpoint
address="soap"
binding="basicHttpBinding"
contract="Project.WebService.IVehicleService" />
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
I have removed the standardEndpoints section and added endpoints of my own.
There are no .svc files as I've set the routes in the global.asax as shown below
private void RegisterRoutes()
{
RouteTable.Routes.Add(new ServiceRoute("VehicleService", new WebServiceHostFactory(), typeof(VehicleService)));
}
The help pages can be accessed via http://localhost:1313/ServiceTest/VehicleService/help
I've also used the WCF Test Client to access http://localhost:1313/ServiceTest/VehicleService/mex
which shows the metadata for the SOAP endpoint
But how do I retrieve the WSDL of the service?
With an svc file I can find the wsdl at http://localhost:1313/ServiceTest/VehicleService.svc?wsdl However I do not have a .svc file.
And neither can I find the WSDL at http://localhost:1313/ServiceTest/VehicleService?wsdl or http://localhost:1313/ServiceTest/VehicleService/soap?wsdl
Do I need to add a .svc file if I want to publish WSDL for the SOAP endpoint?
I have managed to get the WSDL working at http://localhost:1313/ServiceTest/VehicleService?wsdl.
The solution was using new ServiceHostFactory instead of new WebServiceHostFactory in the global.asax.
With WebServiceHostFactory you lose the WSDL functionality.
A similar question can be found here:
ServiceRoute + WebServiceHostFactory kills WSDL generation? How to create extensionless WCF service with ?wsdl
You should be able to get the WSDL by using the mex URL directly from the browser:
http://localhost:1313/ServiceTest/VehicleService/mex
The WcfTestClient is almost certainly doing that to retrieve the WSDL so it can generate the proxy to the service.

WCF 3.5 running SOAP and REST services side by side in IIS

I know that similar question was asked here :
Running SOAP and RESTful on the same URL
Hosting WCF soap and rest endpoints side by side
but didn't find an answer to my problem.
I have two custom servicehostfactories that enables Dependency Injection :
public class StructureMapSoapServiceHostFactory : ServiceHostFactory
public class StructureMapRestServiceHostFactory : WebServiceHost2Factory
The implementation details are not important here.
Then I definied two endpoints in web.config
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="mexGet">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="jsonBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<mexHttpBinding>
<binding name="mexHttpBinding" />
</mexHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="mexGet" name="ServiceImplementation.ServiceCategory">
<endpoint address="rest"
binding="webHttpBinding"
contract="Contracts.ServiceContracts.Mobile.IServiceCategory"
behaviorConfiguration ="jsonBehavior"/>
<endpoint address="soap"
binding="basicHttpBinding"
contract="Contracts.ServiceContracts.Mobile.IServiceCategory" />
<endpoint name="mexHttpBinding"
address="mex"
binding="mexHttpBinding" bindingConfiguration="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
Then I created two .svc files for each custom host factories :
ServiceCategoryRest.svc
ServiceCategorySoap.svc
I don't like it. What I would like to do is to have URL in that style :
REST : http://server:port/rest/categories/{id} which mapps to the implementation of my ServiceCategory.GetCategory(int id)
SOAP : http://server:port/soap/GetCategory?id=someId
My questions are. Do i need different svc files to activate host services ? If I need there two .svc files, how can I achieve the URI above ? I'm afraid that I should configure IIS rewriting or something but would like to avoid that.
Thanks in advance for your help.
Thomas
You can achieve what you're looking for with service routes - part of ASP.NET routing, available from ASP.NET 3.5 SP1 on up.
Check out these resources:
RESTful WCF Services with No svc file and no config
Drop the Soap: WCF, REST, and Pretty URIs in .NET 4
making a WCF REST stand-alone service exe from scratch – part 1 of 4, creating the minimal bare service
Using Routes to Compose WCF WebHttp Services
In .NET 3.5 SP1, you need to add some extra infrastructure to your web.config (web routing module etc.) - while in .NET 4, this is all already built in.
After few searches I found out that in fact I don't need two different .svc files and two different ServiceHostFactories.
I kept only the StructureMapRestServiceHostFactory : WebServiceHost2Factory and ServiceCategoryRest.svc which handles well requests in REST mode and call in RPC-SOAP mode.
So if you want to run side by side the REST and the SOAP you can do it only with WebServiceHost2Factory.
If then you want to get rid of the .svc part from the URL, please read the Rick Strahl post west-wind.com/weblog/posts/570695.aspx.

WCF Multiple Endpoints Under IIS7

I have a simple WCF service that we are developing... We are hosting in IIS7 on WinServer2k8 (though i cant get it to work in IIS7 on Win7 either)
I want multiple endpoints for the same service contract but have the endpoints behave differently. For example I want one endpoint to return data as XML and another to return data in SOAP messages.
Here is my web.config
<system.serviceModel>
<services>
<service name="MemberService">
<endpoint address="soap" binding="basicHttpBinding" contract="IMemberService" />
<endpoint address="xml" binding="webHttpBinding" contract="IMemberService" behaviorConfiguration="xmlBehavior" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="xmlBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
In my service contract i have a method defined as:
[OperationContract]
[WebGet(UriTemplate = "members/{id}")]
Member GetMember(string id);
When I deploy to IIS (on localhost) and make a request (with fiddler) to http://localhost/MemberService.svc/xml/members/memberid I receive a 404 error, also a 404 with http://localhost/MemberService.svc/soap/
However, http://localhost/MemberService.svc/members/memberid works and serializes the data as expected. We want to add the functionality of JSON in the near future as well, we thought it would be another endpoint with a different behavior. My web.config is modeled after a post i found on here
Following this tutorial....
I was able to quickly deploy the webservices. Then using fiddler I could change the content-type of the request to/from "text/xml" and "text/json" and the service would automatically return the data in the correct format.

What is the importance of IMetadataExchange in WCF?

What is the use and importance of IMetadataExchange in WCF?
I have the following app.config file in which I don't use IMetadataExchange endpoint, but I am still able to create my proxy client. I have read that if I don't use IMetadataExchange endpoint, AddServiceReference will not work because my service does not expose the metadata. How is it working without exposing IMetadataExchange endpoint?
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="metaDataBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name ="WCFService.Services" behaviorConfiguration="metaDataBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8090/Services/"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" contract="WCFService.IMathOperations"/>
</service>
</services>
</system.serviceModel>
</configuration>
ArsenMkrt has the formal answer. Put more simply:
If you don't have it, adding a service reference will not work
You should delete it from production servers, so that a hacker cannot add a service reference
To answer your question more specifically, you have this line on your service:
<service name ="WCFService.Services" behaviorConfiguration="metaDataBehavior">
Which points to this configuration
<behavior name="metaDataBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
This may be why it still works, although I thought that you needed to specify the MEX endpoint.
IMetadataExchange Interface Exposes methods used to return metadata about a service.
When programming Windows Communication Foundation (WCF) services, it is useful to publish metadata about the service. For example, metadata can be a Web Services Description Language (WSDL) document that describes all of the methods and data types employed by a service. Returning metadata about an WCF service allows consumers of a service to easily create clients for the service.
The difference is:
<serviceMetadata httpGetEnabled="true"/>
allows you to retrieve metadata using the HTTP protocol.
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
allows you to retrieve metadata using the ws-metadata protocol.
Just <serviceMetadata httpGetEnabled="true"/> works, but not all clients can call you (because they can't retrieve metadata to create a proxy).
The standard is to publish both.
See also ServiceMetadataBehavior Class (MSDN).
Without IMetadataExchange, a WCF service exposes the metadata information to the client, but WCF does not guarantee to expose the metadata because WCF default features to exposing the metadata to the client.
Exposing the metadata is done in a well-standardized way through IMetadataExchange. The IMetadataExchange interface follows the industry standard.