1

I am rather new to WCF (or rest, or Json for that matter) and I'd like to have some expert opinions on which methods to define.

Some short introduction to give an idea of what the webservice should expose: I am building domotica software (software that can control a ZWave network) which has different interfaces (a GUI application, a web server for configuration, and tablets/phones to control the network).

The webservice is the central application that : - has a controller that can interact with ZWave devices - exposes a WCF Json service so that clients can query and control on the ZWave network

The easy methods on the WCF interface:

    [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, UriTemplate = "getnodes")]
    public List<Node> GetNodes()
    {
        // ... retrieve all nodes from ZWave Controller
    }

    [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, UriTemplate = "getnode/{id}")]
    public Node GetNode(uint id)
    {
        // ... retrieve specific node
    }

What I was wondering, is how "specific" the API should be in terms of POST/PUT methods. Clients need to interact with nodes, like set the name, set the room where the node resides in, switch a node on/off, set a dim amount, etc, etc.

I defined one method as follows:

    [WebInvoke(Method = "PUT", RequestFormat = WebMessageFormat.Json, UriTemplate = "setnodename")]
    public void SetNodeName(NodeNewName nodeNewName)
    {
        // .. sets the name of the node, as specified in the passed object          
    }

This works, however this does cause a lot of different methods AND specific classes (as I specified a short list above of the functionality which would demand for specic methods and classes for each of them).

Is that the way to go? Or should I have one method UpdateNode and a more generic class as parameter which only specifies the properties that need to be updated? Or is there some kind of a guideline that would help me define a solid design for my webservice?

I googled a lot on this topic, and I read some articles about WCF design guidelines, but not really something where they cover this part. (or I am not the best googler on this specific topic, which would make sense as I am new on WCF/REST/Json/etc).

Hope somebody can understand what I am looking for and can help me on my way.

Much appreciated!

  • What was your decision process for choosing WCF? Also, do all nodes have a common set of base properties and some nodes have specialized properties? – Kasey Speakman Oct 19 '15 at 14:41
  • @KaseySpeakman, WCF mostly for its ease of use, instantiate just a ServiceHost and define the interface and "voila". I didn't want to bother with IIS or other webservers, so it seemed like a good fit (plus I feel safe with C#.NET). For the nodes bit, the answer is yes. Stuff like names, manufacturer, type, location is default. Whether a node can be switched on/off, dimmed, measured, etc depends on the type of node (and thus are specialized properties). .PS: if WCF wasn't a smart move, please feel free to elaborate – Haxx Oct 19 '15 at 17:58
  • WCF is fine, but is historically conflated with a number of other concepts from SOA and WS-* standards. I haven't used it in a while, so not sure how it is nowadays (still has XML endpoint configuration?). I've been using WebAPI or Nancy, self-hosted on TopShelf or even MVC for IIS-based (all mentioned are .NET libraries). – Kasey Speakman Oct 19 '15 at 18:24
  • @KaseySpeakman, thanks for the insights. I think XML endpoint configuration is still possible, but no longer mandatory. I haven't got any experience with how it was in .NET 3.5 (although from what I read on the internet it seemed much more complicated). I will keep going forward with what I got, maybe somebody can share some nice guidelines. Otherwise I guess I'll find my own :). Thanks for the pointers too, will look at them for sure! – Haxx Oct 19 '15 at 18:29
  • I think graphQL more or less solves this problem these days, to anyone browsing in 2018 – information_interchange May 10 '18 at 17:14
2

This is a tough question to answer definitively, because this space is still relatively young. When it all settles down, then we will know what the answer should have been. :)

Since the kinds of objects and their specific properties are potentially unbounded (depends on what comes to market), I would be tempted to treat each node as essentially a data bucket. The far extreme of this would be something like:

public void SetNodeProperty(string name, string value)

public void SetNodeProperties(Dictionary<string, string> properties)

This really only works if you have no nested object properties (instead of node.Temperature.Minimum, you would need to do node.MinTemperature) and your property values are convertible from strings.

If you have some core data like Name, Room, etc. You can base your object around that, and use tricks to communicate the extra properties back to the server. JsonExtensionData is one way of doing that where any extra properties which are not direct properties on the class are put into a Dictionary<string, object> upon deserialization so you can access them.

public class Node
{
    public string Name {get;set;}
    ...
    [JsonExtensionData]
    public Dictionary<string, object> ExtraData {get;set;}
}

// API
public void UpdateNode(Node node)

Another way would be to take advantage of polymorphism in your API (here is the WCF version) so that anything which implements INode will be deserialized to the proper concrete type on the server (provided the client can give you a type hint when they send the JSON data).

// something like this required for WCF polymorphic parameters
[ServiceKnownType("GetKnownTypesOfINode", typeof(MyHelperClass))]
public void UpdateNode(INode node)
// node could deserialize as ThermostatNode, LightSourceNode, etc.
//   but will be cast as INode
// client has to send $type property for JSON.NET to deserialize properly
//   the value for $type usually takes the form:
//   'My.Namespace.SubNamespace.Class, My.Assembly'

Thirdly, you could deal with the JSON in a purely dynamic way. JSON.NET allows you to deserialize to a dynamic or ExpandoObject to interrogate the posted JSON body. This supports nested properties unlike the string dictionary. I'm pretty sure WCF does not support this since a central theme is providing an interface as a data contract. However, even in Web API, I would likely read the request body manually to avoid having to make a custom model binder or filter or whatever.

  • This was really helpful! thanks a lot for the lengthy answer! As I am still building my own little world of home automation (in my free time, which is getting rather sparse :)), I will have to figure out which approach helps me most, but you really linked some very specific different approaches, and that really is useful as I am new to a lot of what I am diving into :). Much appreciated! – Haxx Oct 23 '15 at 20:15
0

I think you should go with the specific methods as much as possible.

By defining in the service interface what is and isn't possible you enable the client to have compile time checks and type safety. (assuming they follow the interface definition!)

If you go for a more fluid, query/update syntax with your own generic objects or language you make it easier for the client to make mistakes, ie, I don't know, attempt to "dim the water tap".

This will produce a runtime error, which you are going to have to transmit back to the client and the client will have to decode and act on. Much harder all round.

  • Errors could occur anyway (update temperature beyond max, for instance). They should be detected if possible, and the client should be able to handle errors (probably just display) when they happen. – Kasey Speakman Oct 23 '15 at 22:24
  • The idea is to turn as many of these as possible into compile time errors and to document the remaining runtime errors as possible exception types of the method – Ewan Oct 24 '15 at 8:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.