WCF RESTful Services Using Interface with Generics - c#

I have an interface similar to this:
[ServiceContract]
public interface IBaseService<T>
{
[OperationContract]
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
List<T> LoadById(string value);
[OperationContract]
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
List<T> Load(string field, string value);
}
These methods are going to be implemented in several services. An example of implementation would be like this:
[ServiceContract]
[ServiceKnownType(typeof(ObjectDTO))]
public interface IObjectService : IBaseService<ObjectDTO>
{
}
My question is, is it possible to setup RESTful services using this architecture using UriTemplates on the OperationContracts in the base service interface? I tried searching around, but didn't see anyone else attempting to setup their RESTful services this way.

This is purely my HO, but I strongly recommend you to try out OpenRasta instead of added-as-an-afterthought-to-a-RPC-based-framework REST support in WCF. This is surely possible in OpenRasta.

Inheritance with web services is something that I've always found very problematic to achieve, as such I strongly advise against it. Instead consider building your web services as stubs and then call into shared logic with similar structure to what you have done.
If you want a way to easily create web services that are configuration-free you should check out servicestack.net. It's an open source web service framework that lets your create REST-full JSON and XML webservices without any endpoint configuration, Service or Operation contracts - using only POCO DataContracts. Here is a live example showing the client and server code needed for creating simple REST web services called by Ajax and Silverlight clients:

Given the way that REST services are consumed I'm not sure that there's any point using generics. You lose all the benefits of strong typing as you switch to what is a dynamic transport.
JSON serialisation is dynamic and not type aware, so why do you need to strongly type your output?
[ServiceContract]
public interface IBaseService
{
[OperationContract]
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
List<object> LoadById(string value);
[OperationContract]
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
List<object> Load(string field, string value);
}
Will produce the same JSON output.
Given that I think your best bet is just to not use generics in REST.

WCF does not allow open generics in its service contracts. It does provide a KnownType and ServiceKnownType attributes that let you "inform" it of your polymorphisms. You can provide a static helper method to the ServiceKnownType attribute that return the collection of known types as well. I've used this to return the types that match my generic configuration.

Related

.asmx Service not working when publish for some services

I have a project that needs to integrate with legacy asmx services that contains business logic that I must use. I had problems making use of the channels so were allowed to add attributes to make the services rest.
Now here is the problem, I have tested all the services with post man locally and all calls work perfectly with rest as well as the old application still working. Hosting the web app on my local IIS also works. My problem is that when I publish to the server I have some services saying that [ScriptService] attribute is not there but they are there. Then other services works. What am I missing with IIS or publishing? Here is some Name changed code sections. Had to change due to NDA
//Working Service locally returns xml
[System.Web.Services.WebService(Namespace = "http://TheService.ServiceContracts/2006/09", Name = "MyWorkingService")]
[System.Web.Script.Services.ScriptService]
public class MyWorkingService : IMyWorkingService
{
[System.ServiceModel.Web.WebInvoke(Method = "POST",
RequestFormat = System.ServiceModel.Web.WebMessageFormat.Json,
ResponseFormat = System.ServiceModel.Web.WebMessageFormat.Json,
UriTemplate = "/PostMethod",
BodyStyle = System.ServiceModel.Web.WebMessageBodyStyle.Wrapped)]
[System.Web.Services.WebMethod]
public string PostMethod(MyPostObjectClass item)
{
//Business logic
}
}
//Failing Service; locally returns json
[System.Web.Services.WebService(Namespace = "http://TheService.ServiceContracts/2006/09", Name = "MyFailingService")]
[System.Web.Script.Services.ScriptService]
public class MyFailingService : IMyFailingService
{
[System.ServiceModel.Web.WebInvoke(Method = "POST",
RequestFormat = System.ServiceModel.Web.WebMessageFormat.Json,
ResponseFormat = System.ServiceModel.Web.WebMessageFormat.Json,
UriTemplate = "/GetDataFromObjectFilters",
BodyStyle = System.ServiceModel.Web.WebMessageBodyStyle.Wrapped)]
[System.Web.Services.WebMethod]
public MyResponseObject GetDataFromObjectFilters(ObjectFilterRequestClass item)
{
//Business logic
}
}
So I looked at my local IIS and the server IIS to try and figure out what is wrong. Matched up the handler mappings, ISAPI filters and the IIS features that is installed on my local to the server. Yet the server kept asking for the script service attribute even if it was on the class.
After a full weekend of no relax time, I ended up creating a new service project to add the services into and then started adding api controllers into the project to run alongside these services. Making use of the same name as the services to make changes less troublesome in the ui application.

Does WCF support Dynamic Parameters?

Does WCF support Dynamic Parameters or Anon Objects?
Can it still work without DataContracts?
like this
// The Service
[ServiceContract]
public interface IMath
{
[OperationContract]
string Add(Object param);
}
Yes you can Call a WCF service from a client without having the contract interface..
For More Details check the following link it il helpful for u
http://www.codeproject.com/Articles/328552/Calling-a-WCF-service-from-a-client-without-having

WCF DataContractSerializer and XMLSerializer both in same service. Possible?

WCF. Framework 4.5.1
Existing web service uses DataContractSerializer.
It now needs to provide a contract that takes XMLSerialized data from a third party as an input parameter and return a serialized object.
Apparently I should be able to decorate that contract with [XMLSerializerFormat].
But this breaks the published site.
i.e. You can't even access the site with a web browser to obtain the wsdl.
Is there some extra work needed in the Web.Config?
[OperationContract]
[XmlSerializerFormat]
[WebInvoke(UriTemplate = "", Method = "POST")]
ResponseMessage Update(RequestMessage instance);
The contract is sitting inside an interface with all of the existing contracts
The interface is decorated
[ServiceContract]
public interface IMyService
{
Thanks
Bob
Problem was that the contract was not specifically decorated with xml.
Apparently the default assumption is JSON. Working declaration:
[OperationContract]
[XmlSerializerFormat]
[WebInvoke(UriTemplate = "Update", Method = "POST",
ResponseFormat = WebMessageFormat.Xml,
RequestFormat = WebMessageFormat.Xml)]
ResponseMessage Update(RequestMessage instance);
The 'Answer' I put up has exposed some very strange behavior.
With the [XMLSerializer] decoration in place, other contracts can no longer deserialize integers. The integer property leaves the client as say 6 and is deserialized as 0. Comment out the decoration and normal behavior resumes.
I will post a separate question about this.

Passing IEnumerable<int> as parameter to WCF service

I got xml looking like:
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item>1</item>
<item>2</item>
<item>3</item>
</items>
And a wcf service contract:
[ServiceContract(Namespace = "", Name = "MyService", SessionMode = SessionMode.NotAllowed)]
public interface IMyService
{
[OperationContract]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare)]
void DoWork(IEnumerable<int> items);
}
Service binding is basic http.
But when i try to post that xml to wcf method i'm getting error:
Unable to deserialize XML message with root name "items" and root namespace ""
How should wcf method look like to properly work with that xml?
Your service contract does not seem to be setup correctly.
I think you need to implement a "wrapper" class, which defines a type structure that matches your XML.
For example:
[XmlRoot("items")]
public class MyItems
{
[XmlElement("item")]
public List<int> Items { get; set; }
}
I just put together a quick test app and successfully verified the interface using your sample XML (via a soapUI REST client).
Regards,
I think you need to specify a root namespace for default xml deserialization. If this is not an option for you, you might need to change your service interface to accept a stream instead.
Here's more information on the subject: http://www.codeproject.com/Articles/35982/REST-WCF-and-Streams-Getting-Rid-of-those-Names-Sp
To actually answer your question, you could try the following:
<?xml version="1.0" encoding="UTF-8"?>
<items xmlns="http://schemas.datacontract.org/2004/07/"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<item>1</item>
<item>2</item>
<item>3</item>
</items>
Edit: That was not your question. So to actually answer your question:
[OperationContract]
[WebInvoke(BodyStyle =
WebMessageBodyStyle.Bare, Method = "POST", ResponseFormat = WebMessageFormat.Xml,)]
void DoWork(Stream data);
Another alternative could be a custom datacontract (signature: void DoWork(MyCustomDataContract data);) and custom deserialization, example here:
How to use Custom Serialization or Deserialization in WCF to force a new instance on every property of a datacontact ?

UriTemplate prefix for RESTful WCF web service

I have various interfaces (endpoints) in a WCF service host, each for a completely different concern. In a classic soapy web service, I'm able to define a base host address (e.g. http://myhost.com/) and map each interface to a relative URI (IServiceContract -> service/, IMaintenanceContract -> maintenance/) so I can call them by e.g. http://myhost.com/service/mymethod.
Now I'm taking my first steps towards a RESTful WCF service using JSON as message format for CRUD web requests and the only thing I see to address an operation is by using the UriTemplate field from WebInvoke (or WebGet) attribute. Unfortunately, it doesn't seem that I can put this on the interface, just on operation contract methods.
How can I map each interface to a different relative URI?
Yes, you'll put the base url on the [OperationContract] methods. This is OK though, because you can specify any base url you want. Here is a sample interface that gives you this control.
namespace MyHostApi
{
[ServiceContract]
public interface IMyHostApi
{
[OperationContract]
[WebGet(BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "WhateverYouWant/HelloWorld/{name}")]
string HelloWorld(string format, string name);
}
}

Categories