WCF "Avoid property-like operations" rule - wcf

The Juval Löwy's "Programing WCF Services" book contains a "WCF Coding Standard" appendix with General Design Guidelines for WCF Services.
One of the guidelines is Avoid property-like operations:
//Avoid property-like operations:
[ServiceContract]
interface IMyContract
{
[OperationContract]
string GetName();
[OperationContract]
void SetName(string name);
}
Could anybody explain what's wrong with having the string GetName(); operation? What if a string value is all I need from an operation?

If a string value is what you need and you will not need anything more then it is absolutely correct. Probably the better example of the anti-pattern is:
[ServiceContract]
interface IMyContract
{
[OperationContract]
void SetFirstName(string firstName);
[OperationContract]
void SetLastName(string lastName);
}
And client calling:
proxy.SetFirstName("Test");
proxy.SetLastName("Test");
This is completely wrong. You should have single operation accepting first and last name.
Generally you should avoid chatty interfaces and reduce number of roundtrips between service and client. So if you know that you will need only name let expose only operation returning the name. But if you know that you will in the same client's business operation need also email expose the operation which will return name and email.

Related

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))
}
}

How do I export metadata for a single contract with svcutil.exe?

I have two ServiceContracts implemented as interfaces. I want to export the metadata for only one of them. The trick is that both interfaces are implemented by the same class. Therefore, I don't think that I can use /excludeTypes. Please include example syntax when answering. Thanks!
EDIT: A co-worker recently asked me why this is necessary. The reason why is that the first ServiceContract is for a REST service, which it doesn't make sense to export metadata for. So I get two wsdl and xsd files generated, distinguishable only because the second filename is appended with "1". This makes tooling difficult, and adds more clutter to the output directory.
I've added a bounty to try and generate interest in this question.
I created a Service Contract class implementing 2 Interfaces like you described.
namespace NS
{
[ServiceContract]
public interface IREST
{
[OperationContract]
string WorldHello(string name);
}
[ServiceContract]
public interface IInterface
{
[OperationContract]
string HelloWorld(string name);
}
public class CI2 : IREST, IInterface
{
public string WorldHello(string name)
{
return "World Hello: " + name;
}
public string HelloWorld(string name)
{
return "Hello World: " + name;
}
}
}
when running svcutil normally, I get a wsdl with methods from the 2 interfaces
when I run svcutil with /excludeType:IREST for example, I get only IInterface methods.
svcutil /excludeType:NS.IREST ci2service.exe
are you using the same configuration? In that case /excludeType works.

WCF Additional Proxy Classes

I have a WCF webservice that has the following service contract
[ServiceContract(Namespace = "http://example.org")]
public interface IEquinoxWebservice
{
[OperationContract]
Guid Init();
[OperationContract]
List<Message> Dequeue(Guid instanceId);
[OperationContract]
void Enqueue(Guid instanceId, Message message);
[OperationContract]
void Dispose(string instanceId);
}
Message class is an abstract class that is implemented by a bunch of concrete message classes.
I want to make all the concrete message classes available in the client proxy that is generated. Not just the message class.
Is there any way to make them available as types in the webservice so the standard Visual Studio proxy generator will create them?
You need to specify those types. See Data Contract Known Types.