I have created a RESTful web service in C# and have deployed it to IIS. When I access the service HeadOffice.svc, I have the option to view the WSDL (HeadOffice.svc?wsdl). What I would like to do is have the option of viewing the WADL (e.g. HeadOffice.svc?wadl). Is this possible?
I have read around the place that the general opinion is that this is not the best practice. However, I need the WADL for a school assignment, so any help would be much appreciated.
Suppose you already know that WADL is not standard / not supported widely. And when somebody needs WADL, may be then better to use WS*/SOAP service + WSDL. So your task looks like very strange.
Anyway WADL is not supported "out of the box" in any REST implementation from Microsoft, neither WCF 3.5 Rest Starter Kit, neither WCF 4 REST, and ASP.NET WebAPI.
There are no reliable tools for WADL for .NET.
When your goal is to generate C# client code using WADL, believe me, you will spend more time as writing client code by yourself. And there are better solutions for that.
You can use new classes like HttpClient class or RestSharp or similar libraries to easily manually write your client and it will be even faster then googling for reliable WADL solution for .NET
Similar question on stackoverflow: Restful service in .NET with WADL instead of WSDL
UPDATE - Swagger:
For some years swagger has established itself as such format. You can either start writing service definition using swagger's YAML in the Swagger editor or let generate swagger from existing services, for .NET using Swashbuckle library. The second is something we had with WSDL, and swagger editor let's you generate client and server boilerplates. Regardless you are generating your server or client or not fan of it, swagger is actually a very good contract exchange format for REST service, not ideal but good option.
Why Swagger4Wcf
•Manually writing yaml description for swagger and maintain it especially WCF services are boring.
•There is a nuget package called Swagger4WCF that automatically generates yaml description for swagger 2.0 for each interface matching attributes used by WCF (ServiceContract/OperationContract/WebGet/WebInvoke).
2. How Swagger Works in the Background
Swagger4WCF uses NuPack post build pattern to trigger at build time.
https://www.codeproject.com/Tips/1190360/How-to-setup-a-managed-postbuild-without-scripting
At build time, it will detect assemblies present in output directory, open them with mono.cecil (to reflect assemblies) to generate expected yaml description for swagger 2.0.
Swagger4WCF detects WebGet/WebInvoke to provide Verb/Method in serialization style in yaml.
Steps to implement Swagger in your application:
Install SwaggerWcf package
Configure WCF routes
We have to add the route in the Application_Start method inside Global.asax
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.Add(new ServiceRoute("v1/rest", new WebServiceHostFactory(), typeof(BookStore)));
RouteTable.Routes.Add(new ServiceRoute("api-docs", new WebServiceHostFactory(), typeof(SwaggerWcfEndpoint)));
}
Note: Edit Web.config and add the following (if it doesn't exist yet) inside the system.serviceModel block
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
Configure WCF response auto types (optional)
We have to add the following to Web.config. This will allow the WCF service to accept requests and send replies based on the Content-Type headers.
<behavior name="webHttpBehavior">
<webHttp defaultOutgoingResponseFormat="Json" automaticFormatSelectionEnabled="true"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="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>
Decorate WCF services interfaces
For each method, we have to configure the WebInvoke or WebGet attribute, and add a SwaggerWcfPath attribute.
[SwaggerWcfPath("Get book", "Retrieve a book from the store using its id")]
[WebGet(UriTemplate = "/books/{id}", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
Book ReadBook(string id);
Decorate WCF services class
• Add the SwaggerWcf and AspNetCompatibilityRequirements attributes to the class providing the base path for the service.
• For each method, add the SwaggerWcfTag to categorize the method and theSwaggerWcfResponse for each possible response from the service.
[SwaggerWcfTag("Books")]
[SwaggerWcfResponse(HttpStatusCode.OK, "Book found, value in the response body")]
[SwaggerWcfResponse(HttpStatusCode.NoContent, "No books", true)]
public Book[] ReadBooks()
{
}
Decorate data types used in WCF services
[DataContract]
[Description("Book with title, first publish date, author and language")]
[SwaggerWcfDefinition(ExternalDocsUrl = "http://en.wikipedia.org/wiki/Book", ExternalDocsDescription = "Description of a book")]
public class Book
{
[DataMember]
[Description("Book ID")]
public string Id { get; set; }
[DataMember]
[Description("Book Title")]
public string Title { get; set; }
[DataMember]
[Description("Book First Publish Date")]
public int FirstPublished { get; set; }
[DataMember]
[Description("Book Author")]
public Author Author { get; set; }
[DataMember]
[Description("Book Language")]
public Language Language { get; set; }
}
Reference:- https://github.com/abelsilva/swaggerwcf
That's it wcf for Swagger implemented.
Please free if you face any issue.
Thanks,
Abhi
Related
I've looked at a lot of questions on this site that discuss, but don't directly answer this question. I have the following:
In Library.dll:
namespace LibraryNamespace
{
[ServiceContract]
public interface IService
{
[OperationContract]
void Operation();
}
}
In Implementation.dll:
namespace ImplementationNamespace
{
public class ServiceImplementation : IService
{
public void Operation()
{
// Do Something
}
}
}
In app.config:
<service name="ImplementationNamespace.ServiceImplementation">
<endpoint
address="ServiceImplementation"
binding="netTcpBinding"
contract="LibraryNamespace.IService" />
....
</service>
And I keep having a warning with contract="LibraryNamespace.IService". The program runs, but I have a feeling this warning is causing me more problems down the line.
The 'contract' attribute is invalid - The value
'LibraryNamespace.IService' is invalid according to its datatype
'serviceContractType' - The Enumeration constraint has failed.
It works when the ServiceContract and the service implementation are in the same assembly and namespace, but for some reason, it doesn't work here. How can I reference it properly?
I am not sure Why do you want to have the contract and implementation in separate dll? any specific reason? Generally they will be in same assembly and so in config file you can refer them with ease. One way to solve this is creating the service endpoint at runtime like below.
In your hosting project refer both the dll Library.dll and Implementation.dll and have the below code to add the endpoint
using LibraryNamespace;
using ImplementationNamespace;
// Specify a base address for the service
String baseAddress = "http://localhost/ServiceImplementation";
// Create the tcp binding
NetTcpBindings tcp = new NetTcpBindings();
// Define service and Create the endpoint
using(ServiceHost host = new ServiceHost(typeof(ServiceImplementation)))
{
host.AddServiceEndpoint(typeof(IService),tcp, baseAddress);
}
Hi it might be a duplicate but writing here since i was unable to fix the issue from the posts i have seen so far.
I am having DataContracts in my WCF services and on my client I want to consume my services as DataContract objects only, but when i am creating a Service reference my WCF services generating the message contracts for all the methods.
[ServiceContract]
public interface IUserService
{
[OperationContract]
UserVO GetUser(int Id);
}
[DataContract]
public Class UserVO
{
[DataMember]
public int Id{get;set;};
}
I have un-checked the "Always generate message contracts" and checked reuse types in referenced libraries where entities are available(Data Contract).
My reference.cs is having a message contract like
System.ServiceModel.MessageContractAttribute(WrapperName="GetUser", WrapperNamespace="http://tempuri.org/", IsWrapped=true)]
public partial class GetUserRequest {
}
EDIT 1:
my Reference.svcmap has client configuration like this
<ClientOptions>
<GenerateAsynchronousMethods>false</GenerateAsynchronousMethods>
<EnableDataBinding>true</EnableDataBinding>
<ExcludedTypes />
<ImportXmlTypes>false</ImportXmlTypes>
<GenerateInternalTypes>false</GenerateInternalTypes>
<GenerateMessageContracts>false</GenerateMessageContracts>
<NamespaceMappings />
<CollectionMappings>
<CollectionMapping TypeName="System.Collections.Generic.List`1" Category="List" />
</CollectionMappings>
<GenerateSerializableTypes>true</GenerateSerializableTypes>
<Serializer>Auto</Serializer>
<UseSerializerForFaults>true</UseSerializerForFaults>
<ReferenceAllAssemblies>true</ReferenceAllAssemblies>
<ReferencedAssemblies />
<ReferencedDataContractTypes />
<ServiceContractMappings />
EDIT 2:
I am trying to achieve something like below
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IUserService/GetUserDetails", ReplyAction="http://tempuri.org/IUserService/GetUserDetailsResponse")]
[System.ServiceModel.FaultContractAttribute(typeof(UserServiceFaultContract), Action="http://tempuri.org/IUserService/GetUserDetailsUserServiceFaultContractFault", Name="UserServiceFaultContract", Namespace="http://schemas.datacontract.org/2004/07/mynamespace")]
MyEntities.UserVO GetUserDetails(int id);
By default, WCF uses the DataContractSerializer class to serialize data types. If your scenario requires the use of the XmlSerializer, instead, then you can manually switch to the XmlSerializer by applying the XmlSerializerFormatAttribute attribute to your service
The following MSDN article describes the process:
https://msdn.microsoft.com/en-us/library/ms733901(v=vs.110).aspx
Recommend careful consideration of the security notes before switching serialization classes.
Then share the assembly with the client! Put the service interface and all the DataContracts in one assembly. Then the client can use the channel channelfactory "pattern" to connect to the WCF service.
This question is around how to architect WCF services to make it easy to evolve over time.
Its difficult to get the depth of response to this without describing the problem.
Background
I am developing a large system of WCF services and clients.
The server side is "easy" to update as there are only 10 servers in question running this code.
The clients are very difficult to update, despite the high degree of automation, at 300,000+ WCF clients, updates are something that will always take time, and only achieves a high update success rate over a period of two to three weeks.
Data Contracts
[DataContract]
public class MyContract
{
[DataMember]
public int Identity {get; set;}
[DataMember]
public string Name {get; set;}
// More members
}
The DataContract is difficult to initialise and has a standard MyContractFactory class to initialise obtain the appropriate instance for your machine.
public class static MyContractFactory
{
public static MyContract GetMyContract()
{
// Complex implementation
}
}
ServiceContracts
The DataContract is very common across a range of web services.
namespace MyPrefix.WebServicve1
{
[ServiceContract]
public class IMyInterface1
{
[OperationContract]
public void DoSomethingWithMyContract(MyContract data);
}
[ServiceContract]
public class IMyInterface2
{
[OperationContract]
public void DoSomethingDifferentWithMyContract(MyContract data);
}
}
Client
My client is plugin based with plugins running in either separate processes or app domains depending on the level of trust we have in that plugin.
Implementation 1
My initial implementation of this (default WCF) ended up with the DataContract in one assembly, ServiceContract, and implementation in its own assembly.
The clients ended up with a very ugly,
MyWebService1.MyContract
MyWebService2.MyContract
With a copy and paste of the MyContractFactory in nearly every plugin. Whilst the DataContract was the same, the fact that the clients did not include the DataContract assembly meant that it appeared under different namespaces as different objects.
Implementation 2
The clients now include the DataContract assembly, ServiceContracts are in a separate assembly to the service implementation, clients may include some of the ServiceContract assemblies if it will aid with code reuse (no more copy and paste).
Question
With the second implementation I am now facing the difficulty of, how do I update my DataContract and ServiceContracts?
Do I update the same assembly and increment the version number? How do I preserve backwards compatibility whilst all the clients upgrade? Breaking the clients until they update is not acceptable.
Do I create a new assembly with a class that extends MyDataContract, new methods that accept the new type under a new ServiceContract? Does that mean for every minor change to my contracts I need a new assembly? How would I stop it from getting to literally hundreds in a couple of years time?
Some other solution?
Regardless of the solutions I think through, they all seem to have a major downside.
There doesn't seem to be (at least to me) of,
Preserving backwards compatibility until clients update
Keeping the clients trim with no bloat as the software evolves over time
Not significantly polluting my ServiceContract (overloads of the OperationContract need a new "name"). I already have things like the below, and it strikes me a nightmare to maintain over time.
Operation Contract complexity
[OperationContract]
public void DoSomethingWithMyContract(MyContract data);
[OperationContract(Name = "DoSomethingWithMyDataByAdditionalData"]
public void DoSomethingWithMyContract(MyContract data, MyContract2 additionalData);
I am looking for a solution that has worked over a period of time in a large scale environment. Blog entries and the like are very welcome.
Update 1
Looking through the limitations of using "schemaless" changes, different namespaces seems like the only sure method. However, its not quite working as expected, e.g. below
[ServiceContract(
Name = "IServiceContract",
Namespace = "http://myurl/2012/05")]
public interface IServiceContract1
{
// Some operations
}
[ServiceContract(
Name = "IServiceContract",
Namespace = "http://myurl/2012/06")]
public interface IServiceContract2
{
// Some different operations using new DataContracts
}
With the following service
public class MyService : IServiceContract1, IServiceContract2
{
// Implement both operations
}
and the following config
<service behaviorConfiguration="WcfServiceTests.ServiceBehavior"
name="Test.MyService">
<endpoint
address="2012/05"
binding="wsHttpBinding"
contract="Test.IServiceContract1">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint
address="2012/06"
binding="wsHttpBinding"
contract="Test.IServiceContract2">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
Results in two contracts with two different names, I expected that I can point my clients to,
http://myurl.com/MyService.svc/2012/05 for the old version, and http://myurl.com/MyService.svc/2012/06
, but it seems like if I want to preserve the ServiceContract name they have to be two separate services rather than separate endpoint addresses for the same service?
Update 2
I ended up using the method I have described under update 1. Whilst the WSDL looks wrong, the service is indeed backwards compatible under older clients when I've tested this.
Both Microsoft and most of the respected WCF gurus out there will probably say the same thing: versioning should be handled using the contract namespaces.
I don't mean the .NET namespaces of your assemblies - I mean the actual WCF service (and data contract) namespaces - so you should have:
[ServiceContract(Namespace="http://services.yourcompany.com/Service1/V01"]
or something the like - some folks like to version by year/month:
[ServiceContract(Namespace="http://services.yourcompany.com/Service1/2012/05"]
This allows you to have multiple versions of the same service, and as long as clients come calling with an older version (indicated by the service namespace), they'll get the old version (as long as you still expose that).
See:
Best Practices: Data Contract Versioning
Service Versioning
With migration to .NET 4.0, we got rid of a lot of WSE libraries, including the XopDocument class. What is the recommended class to replace XopDocument class, which represents an XOP package that is part of an MTOM-encoded SOAP message
Today I found your question when trying to understand how to add some attachment to SOAP message. In my requirements I have sample SOAP where <inc:Include href="cid:SOMEXML" xmlns:inc="http://www.w3.org/2004/08/xop/include"/> and I have to implement service which can consume such requests. I'm not experienced in WSE, so it's interesting for me for what purpose XopDocument was used there.
I resolved my issue using WCF configurations. I set messageEncoding="Mtom"
<basicHttpBinding>
<binding messageEncoding="Mtom" />
</basicHttpBinding>
and my DataContract has byte[] property.
[DataContract]
public class RootObject
{
[DataMember]
public byte[] SOMEXML { get; set; }
}
In SOAP request it looks like
<xop:Include href="cid:http%3A%2F%2Ftempuri.org%2F1%2F634654497430144369" xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
In general it is what I wanted to find.
Hi I would like to create an API for my website to send and receive data.
For example I need my customers to upload products, single or multiple items. Product feeds can be send daily, weekly or monthly.
Product Name:
Product Color:
Product Weight:
Product Images:
Also I need functionality to send this data to another server. And it should be user friendly.
But I don't have any idea where to start, what technology to use to make it simple and sufficient.
I have background in Asp.Net, C#. It would be great to see an example how to approach it.
Its better you go for the WEB SERVICES (WCF SERVICE) to achieve this easily.
REST via WCF would be the best option. Here is a good article series introducing you to REST with WCF: REST in WCF
There are two distinct pieces of functionality here, and keep in mind that they should essentially be kept separate. Each of them is defined by "who is integrating to whom."
In the first piece, you want to expose a web service API to which clients can connect and send/receive data (the latter of which is on request only). How you want to define this web depends on how you want to expose it to clients, how they want to connect, etc. Common options are:
SOAP Web Service (classic ASP .NET web service)
WCF Service (think of it as a more modern ASP .NET web service)
You can even expose a manual service by defining your own WSDL for clients to consume, or a service that accepts and returns JSON to be more JavaScript-friendly for clients, etc. There are many options. But the above two are your most common choices.
The second piece is where you want to "push" data to another service. This is something that the other service needs to expose and you need to integrate to that. So the design should begin on that side. If you're in charge of that design, just approach it the same way as above. Expose a service there and then, using the same technologies that expose the services, consume them in your application.
The main thing to keep in mind here is to keep the two separate, because trying to expose a web service which at the same time consumes another web service will likely lead to confusion and some non-obvious work-arounds. These are separate concerns and need to keep separated on a logical level, even if the end user doesn't know how separated they are.
Here is a bare minimum WCF Service which returns a product in JSON. To try it out, create a .NET 4.0 Full Profile console application. Run the program, and put this in your browser's address bar: http://localhost:8080/productservice/Product/23
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace WCFServiceExample
{
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
}
[ServiceContract(Namespace = "")]
public interface IProductService
{
[WebGet(UriTemplate = "Product/{id}", ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
Product Product(string id);
}
public class ProductService : IProductService
{
public Product Product(string id)
{
return new Product { Id = id, Name = "A Sample Product" };
}
}
class Program
{
private static ServiceHost servHost;
static void Main(string[] args)
{
StartService();
Console.WriteLine("\n\nPress any key to exit...");
Console.ReadKey();
}
public static void StartService()
{
servHost = new ServiceHost(typeof(ProductService));
servHost.Open();
}
~Program()
{
if (servHost != null)
{
servHost.Close();
}
}
}
}
App.config
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true" logKnownPii="true" logMalformedMessages="true"
logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" />
<endToEndTracing propagateActivity="true" activityTracing="true"
messageFlowTracing="true" />
</diagnostics>
<services>
<service name="WCFServiceExample.ProductService">
<endpoint
address="http://localhost:8080/productservice"
contract="WCFServiceExample.IProductService"
kind="webHttpEndpoint" />
</service>
</services>
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>