At an ACM lecture in 1972, Edsger Dijkstra made a point about the human mind’s limited capacity to contain the logic of a sophisticated computer program from start to finish. Complexity is one of the reasons it’s easier to work with object-oriented code and abstraction, instead of creating something that might be unstructured but functional and syntactically correct. A book that I’ve found useful over the past couple of weeks is Code Complete (Steve McConnell, Microsoft Press), which goes into the best practices for designing and implementing complex software.
Web Services are straightforward to understand when they do something basic and exist in isolation. However, they can also be considerably more complex – the ones I’m developing are actually messengers carrying requests to stored procedures on a SQL server and carrying back the response to the requesting application. They consist of multiple components spanning multiple repositories. While this method of development had the purpose of reducing the complexity of the source code, it increased the complexity of the program’s structure, and I ended up creating a UML representation (using ArgoUML) as a way to visualise it.
Since this Web Service is one of many, the components are called from three separate repositories: Web Service APIs, Web Service Helpers and Data Access.
Web Service API
The API is just a public class that contains a call to method/class GetMyWebServiceResponse(). This function is the Web Service helper, and its return value is declared as the Web Service response.
Web Service Helper
A helper class is the core of the Web Service. A helper can be any program or function that returns a value to the exposed API. An important point is there’s a separation of the logic from the API, and the logic can only be called by the API since it’s an ‘internal static’ method.
- 1. The stored procedure name and parameters are declared as fetchedData.
- 2. fetchedData is passed to myDataItemsResponseBody().
- 3. myDataItemsResponseBody(fetchedData) is passed to myDataItemsResponse().
- 4. Whatever is returned from myDataItemsResponse() is returned to the requesting application/service.
Data Item
The first thing to notice here is the namespace. The classes and methods for constructing the response exist in a different namespace (and repository) to the APIs and helpers.
The properties set the data type as being read-only and write-only when they need to be ( { get; set; }
). One of the potential advantages of using { get; set }
is the accessibility of a variable/property wouldn’t be dependent on whether the class was declared private, e.g.
public int Number {get; protected set;}
Also, think of myDataItem in terms of being a ‘blueprint’ with properties userName and profileCode, rather than as a class with variables. The properties of an instance of myDataItems can be over-ridden in a derived class.
Data Response Body
This section of code takes the data structure defined by myDataItem and forms the body of the Web Service response.
The ‘public class myDataItemResponseBody‘ is derived from a base class called ‘BaseResponseBody‘. This means we have an instance of that base class. This is also referred to as an ‘inherited virtual class’. It is a ‘virtual class’ that can be modified to handle different data types in particular.
You’ll notice that myDataItemResponseBody() was declared twice here, but with different inputs. This is known as ‘overloading’. One reason to do this is if you wanted just one method capable of adapting to the number of inputs during runtime, rather than having more than one method name to deal with.
Here we use this because we know that something’s going to call myDataItemResponseBody(), but we wouldn’t know whether a data row would be passed to it. If there is a data row, the method will use it to populate an array. If there is no data row when the method is called, nothing is returned.
Also notice the method below that, the ‘public override myDataItem
‘. This overrides the base class that was instantiated. The override modifies the instance of the base class that was declared with whatever was declared in the derived class.
Data Response
Forms the entirety of what’s returned from a query. Again this myDataItemResponse is also derived from a base class. The body is returned as an XmlElement, as whatever is returned from the Web Service is an XML formatted response.