Make a single WCF service support both SOAP, REST and WSDL - c#

I'm trying to build a C# service in .NET 3.5 that supports both SOAP - and shows the WSDL - and REST.
The SOAP service and WSDL generation was easy enough to do using the ServiceHost and a BasicHttpBinding classes. Got that working and the client was happy.
Because the SOAP calls all used simple parameters, the client developers requested a REST interface for some of the commands. So I changed the ServiceHost class to a WebServiceHost, added necessary WebInvoke and WebGet attributes, added a WebHttpBinding class, and bingo - REST and SOAP were both working out of one service. Way cool, change one interface and both REST and SOAP got the new stuff.
But one problem - the WSDL no longer gets generated. I couldn't browse to http://server/service?wsdl and get the WSDL file. Checking the MSDN docs, that appears to be behavior for a default WebServiceHost.
Question: can I override this behavior so that the WSDL could be obtained? Doesn't have to the same URL as before - it can change - but I just need to have some URL into service to get the WSDL for those SOAP developers.

When you say "added a WebHttpBinding class", it sounds like you are doing a lot of the configuration in code as opposed to in configuration files.
If this is the case, you could try moving the configuration to the configuration file. Then create 2 endpoints for the contract one REST and one SOAP, with 2 different addresses and bindings.

But one problem - the WSDL no longer
gets generated. I couldn't browse to
http://server/service?wsdl and get the
WSDL file. Checking the MSDN docs,
that appears to be behavior for a
default WebServiceHost.
Yes - that's one of the drawbacks of REST - no more WSDL, no more machine-readable service description. You need to hope the service provider gives you a usable and up to date documentation on what you can do.
There's no WSDL for REST - period. Can't be turned on or anything - it just doesn't exist.
There are some efforts under way to provide something similar - called WADL (Web Application Description Language), but as far as I know, it's still far from an established standard by any means. Also see: Do we need WADL?

Circa, 2007, WSDL v2.0 is supposed to be able to describe RESTful services. I have found that with WCF in .Net v4.0, that the WDSL generated from a purely RESTful service is invalid (WSDL v1.0?).
I created a similar project that exposes both SOAP and RESTful endpoints, and enabled this by, as you did, modifying the interface as such:
// Get all Categories - complex object response
[OperationContract] // categories
[WebGet(BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "GetAllCategories")]
CategoryCollection GetAllCategories(); // SubSonic object
[OperationContract] // categories - respond with a JSON object
[WebGet(ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "GetAllCategories.JSON")]
CategoryCollection GetAllCategoriesJSON(); // SubSonic object
One caveat to this is that all input parameters now must be of type string for all SOAP requests.
Any way of getting around this?

Related

REST WCF Service Returns Method not allowed [duplicate]

In the process of developing my first WCF service and when I try to use it I get "Method not Allowed" with no other explanation.
I've got my interface set up with the ServiceContract and OperationContract:
[OperationContract]
void FileUpload(UploadedFile file);
Along with the actual method:
public void FileUpload(UploadedFile file) {};
To access the Service I enter http://localhost/project/myService.svc/FileUpload
but I get the "Method not Allowed" error
Am I missing something?
If you are using the [WebInvoke(Method="GET")] attribute on the service method, make sure that you spell the method name as "GET" and not "Get" or "get" since it is case sensitive! I had the same error and it took me an hour to figure that one out.
Your browser is sending an HTTP GET request: Make sure you have the WebGet attribute on the operation in the contract:
[ServiceContract]
public interface IUploadService
{
[WebGet()]
[OperationContract]
string TestGetMethod(); // This method takes no arguments, returns a string. Perfect for testing quickly with a browser.
[OperationContract]
void UploadFile(UploadedFile file); // This probably involves an HTTP POST request. Not so easy for a quick browser test.
}
The basic intrinsic types (e.g. byte, int, string, and arrays) will be serialized automatically by WCF. Custom classes, like your UploadedFile, won't be.
So, a silly question (but I have to ask it...): is UploadedFile marked as a [DataContract]? If not, you'll need to make sure that it is, and that each of the members in the class that you want to send are marked with [DataMember].
Unlike remoting, where marking a class with [XmlSerializable] allowed you to serialize the whole class without bothering to mark the members that you wanted serialized, WCF needs you to mark up each member. (I believe this is changing in .NET 3.5 SP1...)
A tremendous resource for WCF development is what we know in our shop as "the fish book": Programming WCF Services by Juval Lowy. Unlike some of the other WCF books around, which are a bit dry and academic, this one takes a practical approach to building WCF services and is actually useful. Thoroughly recommended.
I ran into this exact same issue today. I had installed IIS, but did not have the activate WCF Services Enabled under .net framework 4.6.
It sounds like you're using an incorrect address:
To access the Service I enter http://localhost/project/myService.svc/FileUpload
Assuming you mean this is the address you give your client code then I suspect it should actually be:
http://localhost/project/myService.svc
I've been having this same problem for over a day now - finally figured it out. Thanks to #Sameh for the hint.
Your service is probably working just fine. Testing POST messages using the address bar of a browser won't work. You need to use Fiddler to test a POST message.
Fiddler instructions...
http://www.ehow.com/how_8788176_do-post-using-fiddler.html
Only methods with WebGet can be accessed from browser IE ; you can access other http verbs by just typing address
You can either try Restful service startup kit of codeples or use fiddler to test your other http verbs
you need to add in web.config
<endpoint address="customBinding" binding="customBinding" bindingConfiguration="basicConfig" contract="WcfRest.IService1"/>
<bindings>
<customBinding>
<binding name="basicConfig">
<binaryMessageEncoding/>
<httpTransport transferMode="Streamed" maxReceivedMessageSize="67108864"/>
</binding>
</customBinding>
My case: configuring the service on new server. ASP.NET 4.0 was not installed/registered properly; svc extension was not recognized.

c#: How to consume webservice methods whose address is unknown at compile-time

I am consuming a webservice from a Java server. The webservice provides me with some methods that need. Up till now I have been using the method where I added the reference of the webservice in the project explorer, typed the address of the webservice and compiled it. But now I need it to pick up the address of the service at runtime from an xml file or something! is that possible?
There is Url property in generated proxy object that you can set at runtime. Covered in Creating the Web Service Proxy article on MSDN.
Sample from the article (shows how to also set credentials, you may also need to set Proxy):
var rs = new ReportExecutionService();
rs.Url = "http://<Server Name>/reportserver/reportexecution2005.asmx?wsdl";
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
Note that above answer is for case when you don't know exact Url of server till runtime, but you have WSDL/sample server available at design time and able to generate proxy via add web service in VS (or manually).
Alternatively you can call service via other classes implementing "HTTP GET" like HttpClient and configure anything you want, but will need to do your own parsing of results.

Can I generate a service reference automatically for a REST WCF service?

The ONLY argument I can see for SOAP WCF over REST (json) wcf is the fact that once my service is created I can add a a reference in visual studio and I get a load of strongly typed classes ready for me and a client class that I can call all my webmethod through. It even sets up the web.config as far as I remember.
However when I expose a REST (json) service I still get a WSDL. So Im wondering is there still a way to build my references automatically?
Not using WCF tools. Unlike with SOAP (which has an established protocol for describing services - WSDL), REST doesn't. WADL is one such protocol, but it isn't too widespread and WCF does not support it. You still get a WSDL, because WCF will describe everything it can from the service. However, the WSDL won't have a <wsdl:port> element, which would describe the REST endpoint, which is why you get the WSDL, but cannot generate a reference to it.
The post at http://blogs.msdn.com/b/carlosfigueira/archive/2012/03/26/mixing-add-service-reference-and-wcf-web-http-a-k-a-rest-endpoint-does-not-work.aspx has a lot more info on this issue.
Very old question, newer answer.
today using openapi (swagger) I can achieve this by using swagger inspector doing samples i can document my rest services as well as create a spec yml/json file allowing for validations and acceptance criteria as well as automated clients for java,python,c#,ruby,javascript and others I'm sure
I would like top elaborate:
Although it is true you cannot get a WSDL add service reference with a JSON REST WCF service, what I do is create two met data hooks:
is the operations returning JSON
is a single XML op returning a class wrapper which includes all the service classes I allow, I call it Discover:
i.e.
public class Discover
{
public Manager Manager {get;}
public Employee Emp {get;}
....
}
[OperationContract]
public Discover DiscoverDTOs()
You can, indirectly. While the client generated by Visual Studio won't work, that client implements an interface, also generated, that you can use like this:
WebChannelFactory<IService> factory = new WebChannelFactory<IService>(new Uri(endpointAddress));
IService proxy = factory.CreateChannel();
int result = proxy.Operation(1, 2, 3);
WebChannelFactory has another overload which accepts a WebHttpBinding, you can configure based on the service configuration, or you can make this configuration manually in your app.config file.

WCF XmlSerialization Attribute(POST)

I currently have a WCF service to consume a remote REST service with the following:
[ServiceContract]
[XmlSerializerFormat]
public interface IMyApi
{
[OperationContract]
[WebGet(
ResponseFormat = WebMessage.Xml,
UriTemplate = "RemoteServicePage.jsp")]
MyNewClass Send();
}
The nice part about this is the XmlSerializerFormat attribute. Automatically deserializes a response into the return type of the method(ie, POX response => MyNewClass).
I've been unsuccessful, however, in finding any samples of the reverse. I'd like to post a POX request to a given service. I'm curious if there's a similar way to pass an object to a WCF service which in turn makes the post request to the target.
Any thoughts are greatly appreciated.
UPDATE
Just a clarification of the question:
Is it possible to post an object to a web service via WCF(which handles the serialization)?
UPDATE
I believe Steve touched on what I believe is the right direction below with using the WebInvoke method and attribute RequestFormat to achieve what I'm looking for. I guess I want to point out I'm not hosting a web service that allows for posting, but rather trying to post to an external web service(ie, a remote *.jsp) using WCF.
WCF allows for easy consumption and access of external web services and this is something I'm familiar with. I've never attempted to post a stream or object to an external source however(posting via UriTemplate is straightforward).
I don't understand. Why not just use HttpWebRequest? One of the benefits of doing REST over HTTP is that you get to use standard HTTP libraries. Doing a POST with HttpWebRequest is relatively trivial. Why do you need WCF? If you want to serialize an object into your POST body, then you can do that with either the DataContractSerializer or with the XmlSerializer.
If you really don't like that option, then look at the new Microsoft.Http.HttpClient class that is in the WCF Rest Starter Kit Preview 2. It is a very nice client library and despite its name and packaging, it does not even have a dependency on WCF!
This answer is based on your second update. I only say this because your initial statement of "I currently have a WCF service to consume a remote REST service" makes no sense. You cannot declaratively define a remote interface that you want to consume. The term WebInvoke is not what you are thinking, it is simply a catch all attribute for handing non GET requests. WebGet and WebInvoke both handing incoming requests.
If you want to consume a remote "REST" interface then you need to use HttpWebRequest or the new HttpClient class.
I don't think you understand the meaning of XmlSerializerFormat. It means that the XML Serializer should be used instead of the Data Contract Serializer. Both will serialize to XML.
Use the RequestFormat attribute. For JSON, this would be
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
Good luck

Web Service method signature changed to request/response objects for datatype string[]

I have two websites, both using .Net framework 3.5. One website is hosting a soap web service and the other is referencing this service.
I'm having some unexpected happenings with my web method signatures. I have a simple method in my web service with a signature such as:
[WebMethod]
public string[] HelloWorld()
{
return new[] { "Hello World" };
}
But when I reference this web service using the 'Add Service Reference' feature in VS2008, with configuration set to "Always generate message contracts" (although when i check the 'reuse types in referenced assemblies', i seem to have the same issue), the signature seems to be changed by the auto generated proxy objects to the following:
HelloWorldResponse HelloWorld(HelloWorldRequest request)
I've tried to look this up on the net, but having trouble finding something that will simply explain to me why this is happening, and whether I can/should try to work around it?
I also have this question:
How does one determine whether they should choose the service reference configuration option to "reuse types in referenced assemblies" and "always generated message contracts"?
The message-contracts option might have this effect; the purpose here being to allow fine-grained control over the underlying request. Ultimately, what you are sending (behind the scenes) is a request payload.
The reuse-types option is more typically used with objects (not things like string[]) - and means that if you have a 100% matching Customer (say) class locally, it can re-use that for the web-service rather than generating a proxy type.
Additionally, note that you aren't actually consuming a WCF service ([WebMethod] is the older web-service style). As such you may have better results with a "Web Reference"; when adding the service, hit "Advanced", then "Add Web Reference...". This uses the older UI and wsdl.exe to generate code intended for [WebMethod] (asmx), rather than WCF (svc).
Of course, rather than hosting a [WebMethod], you could (since the server is also 3.5) host a WCF service; this may make things easier.
A final point of WCF; if you really want the same contract at client and server, you can use either assembly or class sharing to use the very same types at both end. This is not supported for [WebMethod], though.

Categories