2 Names the Same in WCF Not possible? - wcf

I'm trying to create a RESTful WCF service. I get a runtime error saying you can't have 2 of the same method names in your service class:
[OperationContract, WebGet]
...
string Get();
[OperationContract, WebGet]
...
string Get(int id);
Why in the world can't you! they are both different signatures. If I'm to get this to work like REST like I want, which is to be able to overload stuff like this, then that would suck and WCF is not for me.
Has anyone been able to have 2 of the same method names in your so-called attempt to make WCF restful?

you can override service method by using OperationContract name property with define separate routes.Your service interface should look like
[OperationContract(Name = "GetemployeeName")]
string Get(string param);
[OperationContract(Name = "GetemployeeAge")]
bool Get(long sysID);

Related

Calling a Web Service using WCF channel Factory.Is it possible?

In the project I am working on I need to call webservices (asmx).I would like to call them using wcf and using the channelfactory(No adding service Reference).
Some might have an interface(contract)many dont.
Is there an end to end example how to do it?
var service=ChannelFactory<?>... How do I get the webserviceContract.
Surely this must be a common scenario to be able to call a webservice (asmx)
Thanks for your time
To expand upon my comment, you should be able to create an interface that has methods that match the web service methods in the asmx service. For example:
Web Service Methods
string GetMessage()
void SendMessage(string message)
int AddNumbers(int x, int y)
Service Contract
[ServiceContract]
public interface IServiceName
{
[OperationContract]
string GetMessage();
[OperationContract]
void SendMessage(string message);
[OperationContract]
int AddNumbers(int x, int y)
}
ChannelFactory
ChannelFactory<IServiceName> serviceFactory =
new ChannelFactory<IServiceName>(new BasicHttpBinding(),
"http://www.services.com/Service.asmx");
Not 100% sure this will work, but it would be easy to try out. Also, you'd probably want to set the namespace on the service contract ([ServiceContract(Namespace = "somenamespace")]) to match the legacy asmx service, otherwise the messages might not get processed.

What does my WCF service expect the request data to look like?

I've got a WCF-hosted service right now which is self-hosted and defined like this:
[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json, Method = "PUT", UriTemplate = "/device")]
void updateDeviceLevel(ZDevice device);
The ZDevice class looks like this:
public class ZDevice {
public bool? newPowerState { get; set; }
public int nodeId {get; set;}
}
I have a simple Mac client which consumes the service by using an http post. It posts {"newLevel":27,"nodeId":6} to the \devices url and .NET magically stuffs the values into a ZDevice object for me. All is well here.
Now however, I need to add some basic security to the mix. I've done this by adding a new parameter and some "RequestWrapping" to the method call:
[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json, BodyStyle=WebMessageBodyStyle.WrappedRequest, Method = "PUT", UriTemplate = "/device")]
void updateDeviceLevel(string password, ZDevice device);
What I'm trying to do now is figure out what syntax the server is expecting from the consuming clients. I'd hoped that posting in {"password":"somepwd", "newLevel":27,"nodeId":6} would work, but .NET is no longer able to "deserialize" that into the ZDevice object like it did before.
Anyone got some suggestions for me?
Thanks
It should look like this:
{"password":"somepwd", "device": {"newLevel":27,"nodeId":6}}
Each property on the JSON object has a value; and in the case of device it's just a new object.
Note that in your ZDevice class you called it newPowerState, but in JSON you are calling it newLevel. In your class it's also a bool, but in JSON you are assigning it an int. Something isn't matching up.
Based on your C#, I'd expect it to look like this:
{"password":"somepwd", "device": {"newPowerState":true,"nodeId":6}}
The property names in your JSON object should match the parameter / property names in C#.

Can Wcf service contract also be used by others(nhibernate asp.net)

I was wondering about if wcf would be kinda break down if mixed in with IRepository
because 2 different sources are going to be using the same contract:
- 1 being used by WCF
- another by Asp.net Nhibernate
So i wanted to reuse the same contract rather making another replica with one or 2 things out.
Easier understood by an example...
[ServiceContract]
public interface ITutorialService
{
[OperationContract]
void AddTutorial(Tutorial newTutorial);
[OperationContract]
List<Tutorial> GetTutorials();
[OperationContract]
void RemoveTutorial(string id);
Tutorial GetTutorialModel();
Tag GetTagModel();
Video GetVideoModel();
IRepository<Tutorial> GetTutorialRepository();
IRepository<Tag> GetTagRepository();
IRepository<Video> GetVideoRepository();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class TutorialService : ITutorialService
{
private IRepository<Tutorial> _tutorial;
private IRepository<Tag> _tag;
private IRepository<Video> _video;......
in short would the wcf work fine as i didnt add any [OperationContract] to the Irepository ?
Yes it will work. The methods without [OperationContract] won't be WCF operations, but it sounds like that's what you want.
Another approach would be to have two interfaces and have one derive from the other so that you have separation of concerns, but do not have to define the methods twice.

WCF 4: Passing Empty parameters on a GET request

I'm creating an API which will just use a get request to return some search results from the database, I'm trying to make it so that optional parameters can be passed (easy with WCF) but also so that if parameters are specfied in the query string as long as they are empty they will be ignored by the service.
However if you have the a query string with empty parameters it will return a bad request (400) by the server e.g.
Using a end-user point of your choice pass the following querystring
http://www.exampleservice.com/basic/?apiKey=1234&noOfResults=3&maxSalary=&minSalary=&ouId=0&keywords=Web+Developer
Note that maxSalary and minSalary are not passing values
You then have the following WCF service:
[OperationContract]
[WebGet(UriTemplate = "basic/?apiKey={apiKey}&noOfResults={noOfResults}&maxSalary={maxSalary}&minSalary={minSalary}&ouId={ouId}&keywords={keywords}", BodyStyle = WebMessageBodyStyle.Bare)]
public List<SearchResultsDto> BasicSearch(string keywords, string apiKey, int noOfResults, int maxSalary, int minSalary, int ouId)
{
//Do some service stuff
}
This will cause a 400 error, please can someone explain how you pass empty parameters across to a WCF service or is this just not possible?
Currently passing null or an empty parameter is not supported in WCF, the main solution to this problem is to override the querystringconverter which handles the url as it comes through the pipe but before it reaches the operation contract.
An excellent example of implmenting an extension of the querystringconverter is found here:
In the WCF web programming model, how can one write an operation contract with an array of query string parameters (i.e. with the same name)?
HOWEVER
sadly there is a bug in WCF 4 where you cannot override the querystringconverter, this has been addressed by Microsoft and will be fixed in the SP1 release coming this year.
Until then there is no clean way to deal with this situation other than to handle the exception and return a status code of 400 (bad request) - good documentation of the api should handle this in the interim.
Is it just the integers giving you trouble? Maybe you can try making them nullable?
int? MaxSalary
hope this helps
You could send in "-1", and treat that in your business logic as not sent.
It can be handled in multiple ways. Since you are talking about a REST service that can have optional parameters, my suggestion will be do the something like this.
Create a DataObject that will be accepeted as parameter to this method.
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet(RequestFormat=WebMessageFormat.Json)]
RequestObject BasicSearch(RequestObject apiKey);
}
public class Service1 : IService1
{
public RequestObject BasicSearch(RequestObject obj)
{
//Do some service stuff
return obj;
}
}
[DataContract]
public class RequestObject
{
[DataMember]
public string Keywords {get; set;}
[DataMember]
public string ApiKey {get; set;}
[DataMember]
public int NoOfResults { get; set; }
}
Advantages (am going to be short, ping me back for details)
No change in service signature
contract does not change
you will get the flexibility of have
null parameters
you can always extend the number of
parameters without any impact to
existing services
below is the sample input and output from fiddler
note: in the request part i havent passed anything to NumberOfResults intentionally to prove

How to wrap all results of an EndPoint in OperationResult?

I want to wrap each result from one Wcf service in my application in something like
public class OperationResult{
public string Status;
public string Data;
}
even if my contract looks like
[ServiceContract]
internal interface ITest
{
[OperationContract,
WebGet(
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
MyDc EchoDc(MyDc input);
}
From what I've read the potential extensibility points are IServiceBehavior, IEndpointBehavior, IContractBehavior, IOperationBehavior.
Any thoughts where I can hook my wrapping magic ?
Look # my answer here:
How to customize the process employed by WCF when serializing contract method arguments?
There it is mentioned how you can replace an object of one type to another type while it is being returned.
I think thats not possible via extensionpoints on the WCF framework because what you watn to do is to change your contract.
The contract is a c# interface which is used by your client.
You have to write an own proxy class for use by your client where you can map the operation results to whatever you like:
class ServiceProxy : ClientBase<YourServiceInterface>
{
public OperationResult EchoDc(MyDs input)
{
MyDc result = Channel.EchoDc(input);
return new OperationResult( ... // map your operation result here))
}
}