In the first part of this series, I gave you a little introduction to REST/POX in contrast to SOAP and also explained some of the differences in how incoming requests are dispatched. Now I’ll start digging into how we can teach Indigo a RESTish dispatch mechanism that dispatches based on the HTTP method and by matching on the URI against a suffix pattern.
The idea here is that we have a service implementation that takes care of a certain resource namespace. To stick with the example from Part 1, we assume that the resources managed within this (URI) namespace are customers and data related to customers. Mind that this might not be all data of a respective customer, but that some data may very well be residing in completely different namespaces (and on different servers).
As a reminder: When I write “namespaces” I specifically mean that we’re creating hierarchical scopes for data. All customer representations managed by our imaginary service are subordinates of the namespace http://www.example.com/customers, the representation of the customer identified by customer-id 00212332 occupies the namespace http://www.example.com/customers/00212332, all communication (phone) numbers of that customer are subordinates of http://www.example.com/customers/00212332/comm and the home phone number might be identified by http://www.example.com/customers/00212332/comm/home-phone. However, all orders made by that respective customer might be found somewhere completely different; maybe here: http://www.tempuri.org/ordersystem/customer-orders/00212332. The data representation of the customer would contain that link, but the customer service would not manage those resources (the orders), at all.
Purists might (and do) argue that plain HTTP handlers (or “servlets”, in Java terms) representing exactly one resource type are the best way to implement the processing logic for this URI/HTTP centric model, but since I am much more a pragmatist than a purist, I prefer using a infrastructure that maps incoming requests to a programming model that’s easy enough for most programmers to deal with. It turns out that a class with methods that deal with related stuff (a customer and his addresses and phone numbers) is something that most programmers can handle pretty well by now and there’s nothing wrong with co-locating related handlers for data from a given data source on one flat interface, even if the outside representation of that data suggests that the data and its “endpoints” are ordered hierarchically. In the end, the namespace organization is just a smokescreen that we put in front of our implementation. Just to make Mark happy, I’ll show a very HTTP and service-per-object aligned contract model and, later in the next part, also a more readable model for the rest of us to explain how the dispatch works. I’ll start with the model for idealists:
|
[ServiceContract, HttpMethodOperationSelector] interface ICustomerResource { [OperationContract, HttpMethod("GET", UriSuffix = "/customers/?")] Message Get(Message msg); [OperationContract, HttpMethod("PUT", UriSuffix = "/customers/?")] Message Put(Message msg); [OperationContract, HttpMethod("POST", UriSuffix = "/customers/?")] Message Post(Message msg); [OperationContract, HttpMethod("DELETE", UriSuffix = "/customers/?")] Message Delete(Message msg); } |
[ServiceContract, HttpMethodOperationSelector] interface ICommunicationResource { [OperationContract, HttpMethod("GET", UriSuffix = "/customers/?/comm/?")] Message Get(Message msg); [OperationContract, HttpMethod("PUT", UriSuffix = "/customers/?/comm/?")] Message Put(Message msg); [OperationContract, HttpMethod("POST", UriSuffix = "/customers/?/comm/?")] Message Post(Message msg); [OperationContract, HttpMethod("DELETE", UriSuffix = "/customers/?/comm/?")] Message Delete(Message msg); } |
We have two different contracts here, one for the “customers” namespace and one for the “comm” sub-namespace, and the implementation of these two contracts could be sitting on the same implementation class or on two different classes whereby they could be co-located at the exact same root address or sitting on different machines. All of that doesn’t really matter, since the filtering/dispatch logic we’ll use here will figure out the right thing to do, meaning the right handler method to dispatch to. Also mind that there’s a difference to the examples I show in Part 1 in that I am now using messages.
The UriSuffix of the HttpMethodAttribute serves three purposes. First, it is used to construct a regular expression that is used to match incoming messages to the right endpoint using a custom endpoint Filter. Second, the same regular expression is used to figure out which method the message shall be dispatched on at that endpoint using a custom implementation of IDispatchOperation. Third, the regular expression is also used to isolate the URI-embedded parameters and make them easily accessible on a message property. So for the ICommunicationResource.Get() operation above, the handler implementation would start out as follows and would make the values occurring at the two “?” of the suffix available in the UriArgumentsMessageProperty.InUrlArgs collection that is shown further below:
|
Message ICommunicationResource.Get(Message msg) { UriArgumentsMessageProperty uriArgs = UriArgumentsMessageProperty.FromOperationContext(); string customerid = uriArgs.InUrlArgs[0]; string commid = uriArgs.InUrlArgs[1]; ... |
The expressions for UriSuffix support two different wildcards. The “*”wildcard will match any character and the “?” wildcard will match any character except the forward slash. If you would, for instance, want to build an operation that behaves like a web server and might serve up data from a directory and its subdirectories, you’d use something as global as “/*” and any URI would match the respective endpoint/method. If you want to match/extract segments of a namespace path as we do here, you use the “?”.
And so here is the complete and rather straightforward implementation of the HttpMethodAttribute:
|
using System; using System.Collections.Generic; using System.Text; using System.ServiceModel; using System.Text.RegularExpressions;
namespace newtelligence.ServiceModelExtensions { /// <summary> /// The HttpMethodAttribute is used to declare the HTTP method and /// an optional suffix for the REST/POX extensions to dispatch on. In absence of /// this attribute, the dispatch mechanism will attempt to dispatch on the /// name of the operation and try matching by name it to the HTTP method used. /// </summary> [AttributeUsage(AttributeTargets.Method)] public class HttpMethodAttribute : Attribute, IOperationBehavior { /// <summary> /// Initializes a new instance of the <see cref="T:HttpMethodAttribute"/> class. /// </summary> /// <param name="method">The method.</param> public HttpMethodAttribute(string method) { _Method = method; }
private string _Method; /// <summary> /// Gets the HTTP method. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html /// </summary> /// <value>The method.</value> public string Method { get { return _Method; } }
private string _UriSuffix; /// <summary> /// Sets or gets the Uri suffix. The Uri suffix is an expression used /// to match an incoming request against the endpoint and this method. /// The UriSuffix may contain two different wildcards: '*' matches the /// shortest sequence of arbitrary character up to the next concrete character /// in the suffix string. The '?' behaves similarly, but excludes the '/' /// character from matching. /// </summary> /// <value>The URI suffix.</value> public string UriSuffix { set { _UriSuffix = value; _UriSuffixRegex = new Regex( Regex.Escape(_uriSuffix).Replace("\\*", "(.*?)") .Replace("\\?", "([^/]*?)") + "$", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled); } get { return _UriSuffix; } }
private Regex _UriSuffixRegex; /// <summary> /// Gets the regular match expression constructed from /// the UriSuffix. /// </summary> /// <value>The URI suffix regex.</value> public Regex UriSuffixRegex { get { return _UriSuffixRegex; } }
private int _Priority; /// <summary> /// Gets or sets the priority. The priority is used to control the /// order in which the suffix expressions are processed when matching. /// A higher priority causes the expression to be matched earlier. /// </summary> /// <value>The priority.</value> public int Priority { get { return _Priority; } set { _Priority = value; } }
/// <summary> /// Applies the behavior. /// </summary> /// <param name="description">Description.</param> /// <param name="proxy">Proxy.</param> /// <param name="parameters">Parameters.</param> public void ApplyBehavior(OperationDescription description, ProxyOperation proxy, BindingParameterCollection parameters) { // do nothing proxy-side }
/// <summary> /// Applies the behavior. /// </summary> /// <param name="description">Description.</param> /// <param name="dispatch">Dispatch.</param> /// <param name="parameters">Parameters.</param> public void ApplyBehavior(OperationDescription description, DispatchOperation dispatch, BindingParameterCollection parameters) { // We're adding a parameter inspector that parses the Uri parameters into // an UriArgumentsMessageProperty dispatch.ParameterInspectors.Add( new HttpMethodParameterInspector(this)); } } }
|
Of course this attribute is a bit special. You might have noticed that it implements the IOperationBehavior interface with its two method overloads of ApplyBehavior whereby one is for the proxy side of a channel (which we don’t care about in this case) and the other for the dispatcher (service-) side of an implementation. The presence of this interface causes the Indigo runtime to instantiate the attribute and add it to the contract metadata whenever the contract is built using reflection. You could also instantiate the attribute yourself and add it to any existing in-memory Indigo contract’s operation description if you liked. This is a convenient way to get the additional metadata into the contract description because we need it at several places later.
At the dispatch-side we’re also adding an implementation of IParameterInspector, whose job it is to extract the URI-embedded arguments and also parse “key=value” pairs of an optional query string, if one is present.
Parameter inspectors are called immediately before and after a method has been invoked and, as their name implies, are meant to be used to inspect a method’s parameters and/or output. However, their use is not restricted to that. Because the operation context is also available when the inspectors are called, you can also inspect headers, properties or any other context information at this point.
Even though this is largely a convenience feature not central to the dispatcher, I’ll show the class here, because I mentioned the UriArgumentsMessageProperty above. This is where it gets populated and set:
|
using System; using System.Collections.Generic; using System.Text; using System.ServiceModel; using System.ServiceModel.Channels; using System.Text.RegularExpressions; using System.Collections.Specialized;
namespace newtelligence.ServiceModelExtensions { class HttpMethodParameterInspector : IParameterInspector { HttpMethodAttribute _metadata; /// <summary> /// Creates a new instance of HttpMethodParameterInspector /// </summary> public HttpMethodParameterInspector(HttpMethodAttribute metadata) { _metadata = metadata; } #region IParameterInspector Members
public object BeforeCall(string operationName, object[] inputs) { OperationContext opCtx = OperationContext.Current; NameValueCollection queryArguments; StringCollection inUrlArgs = new StringCollection(); Uri toHeader = opCtx.IncomingMessageHeaders.To;
// Parse query strings if (opCtx.IncomingMessageProperties.ContainsKey(HttpRequestMessageProperty.Name)) { HttpRequestMessageProperty rqMsgProp = opCtx.IncomingMessageProperties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty; queryArguments = UriHelper.ParseQueryString(rqMsgProp.QueryString); } else { queryArguments = UriHelper.ParseQueryString(toHeader.Query); }
// Get the in URL arguments from the regex captures Match match = _metadata.UriSuffixRegex.Match(toHeader.AbsolutePath); if (match.Success && match.Groups.Count > 0) { // if we have more than 1 capture group (the first is always the // full match expression), we store the next groups in the // irUrlArgument collection in order of occurrence. for (int i = 1; i < match.Groups.Count; i++) { inUrlArgs.Add(match.Groups[i].Value); } }
opCtx.IncomingMessageProperties.Add( UriArgumentsMessageProperty.Name, new UriArgumentsMessageProperty(queryArguments,inUrlArgs) );
return null; }
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState) { // do nothing }
#endregion } }
|
The query string is parsed using a helper class which splits the query string at each ‘&’ first and then splits the segments at ‘=’ and throws the resulting pairs into a NameValueCollection. That is no big deal and I'll omit the helper here. The UriArgumentsMessageProperty that gets put into the mesage properties is just a class that holds the query arguments and the string collection with the regex matches. It is quite trivial:
|
using System; using System.Collections.Specialized; using System.Collections.Generic; using System.Text; using System.ServiceModel;
namespace newtelligence.ServiceModelExtensions {
/// <summary> /// Message property class holding arguments fro the request URI. /// </summary> public class UriArgumentsMessageProperty { NameValueCollection _queryArguments; StringCollection _inUrlArgs;
/// <summary> /// Creates a new instance of UrlArgumentsMessageProperty /// </summary> internal UriArgumentsMessageProperty(NameValueCollection queryArguments, StringCollection inUrlArgs) { _queryArguments = queryArguments; _inUrlArgs = inUrlArgs; }
/// <summary> /// Gets the query arguments. /// </summary> /// <value>The query arguments.</value> public NameValueCollection QueryArguments { get { return _queryArguments; } }
/// <summary> /// Gets the arguments in the URL. /// </summary> /// <value>The in URL args.</value> public StringCollection InUrlArgs { get { return _inUrlArgs; } }
/// <summary> /// Gets the name of the property. /// </summary> /// <value>The name.</value> public static string Name { get { return "urlArguments"; } }
/// <summary> /// Retrieves the message property from the current operation context. /// </summary> /// <returns></returns> static public UriArgumentsMessageProperty FromOperationContext() { return FromOperationContext(OperationContext.Current); }
/// <summary> /// Retrieves the message property from the operation context. /// </summary> /// <param name="operationContext">operation context</param> /// <returns></returns> static public UriArgumentsMessageProperty FromOperationContext(OperationContext operationContext) { return operationContext.IncomingMessageProperties[Name] as UriArgumentsMessageProperty; } } } |
Ok, fine, and how is that now really used for dispatching? You’ll see that when I explain the SuffixFilter and the HttpMethodOperationSelectorBehavior in the next parts.
(There will also be a downloadable version of the code later, but I am still tweaking some little things and don’t want to keep updating)
Go to Part 3
A not so long time ago in a land far away…
A little bit more than half a year ago I got invited to a meeting at Microsoft in Redmond and discussed with Steve Swartz, Yasser Shohoud and Eugene Osovetsky how to implement POX and REST support for Indigo. You could also say that Steve dragged me into the meeting, since I happened to be on campus anyways and was burning some time in Steve’s office. I am not sure whether I made any good contribution to the cause in the meeting, but at least I witnessed the definition a special capability for the HTTP transport that I am exploiting with a set of Indigo extensions that I’ll present in this series of blog posts. The consensus in the meeting was that the requirements for building POX/REST support into the product weren’t generally clear enough in the sense that when you ask 100 people in the community you get 154 ever-changing opinions about how to write such apps. As a consequence it would not really be possible to define a complete programming model surface that everyone would be happy with, but that a simple set of hooks could be put into the product that people could use to build programming models rather easily.
And so they did, and so I did. This new capability of the HTTP transport first appeared in the September CTP of Indigo/WCF and surfaces to the developer as properties in the Message class Properties collection or the OperationContext.Incoming/OutgoingMessageProperties.
If you are using the Indigo HTTP transport on the server, the transport will always stick a HttpRequestMessageProperty instance into the incoming message properties, which provides access to the HTTP headers, the HTTP method (GET, POST, PUT, etc.) and the full query string. On the client, you can create an instance of this property class yourself and stick it into any outbound message’s properties collection and, with that, control how the transport performs the request. For sending replies from the server, you can put a HttpResponseMessageProperty into the message properties (or, again, into the OperationContext) and set the HTTP status code and description and of course the HTTP reply headers.
And since I have nothing better to do, I wanted to know whether this rather simple control feature for the HTTP transport would indeed be enough to build a POX/REST programming model and application when combined with the rest of the Indigo extensibility features. Executive Summary: Yes.
Now, the “yes” doesn’t mean that the required extensions write themselves in an hour. It’s a bit of work to get there, so it’ll take me a bit of writing (and a few days) to tell the whole story. There are two ways to approach the explanation: “Bottom-up” where I’d start at the wire level and show how to have Indigo send and accept any (and I mean any: 8GB+ video/mpeg files included) stuff that isn’t wrapped in SOAP envelopes or “Top-Down” where I start at the programming model surface and explain the application-level developer experience first. It’s a tough call, but I’ve decided to start with the latter.
REST and POX
In a nutshell – and I am sure that I’ll now get 153 corrections by comments and email from the other 99 people – the core ideas behind REST (representational state transfer) are that it builds on the pervasive HTTP web-architecture, that every item (“resource”) in the whole wide world can/could be identified by a HTTP URL and that HTTP has sufficient built-in methods to manipulate such resources. You can GET a data representation of the item, you can POST a new, related resource representation underneath an existing resource, you can PUT updates to resource representations and you can of course DELETE a resource representation. Every representation of a resource may have links to related resources that you can likewise access using these methods and therefore you get a web of information. REST is an architectural generalization of the HTML/HTTP web and the proponents of REST argue that the web works very obviously very well and that therefore REST is fit for any type of application. Of course, that’s a bit of an exaggeration, because there are plenty of scenarios where request/response isn’t the thing to do, but for a lot of applications REST may just be a good choice. Commonly, the REST architectural style is combined with XML data representations, even though this architectural style is really content-neutral. The place to find a “link” in a resource represented by a JPEG photo could very well be a URL on somewhere an advertising poster in the background behind your mother-in-law wearing a horrible hat at an English horse-racing event.
POX means “plain old XML” and I’ve also heard a definition saying that “POX is REST without the dogma”, but that’s not really correct. POX is not really well defined, but it’s clear that the “plain” is the focus and that means typically that folks who talk about “POX web services” explicitly mean that those services don’t use SOAP. You could see POX as an antonym for SOAP, if you will.
Except for “this isn’t SOAP” the term POX means very little. POX isn’t about architecture, it’s only about content. But REST is about architecture and it is content neutral. So what you commonly find is the combination of REST/POX as an alternative model to SOAP and the WS-* web services stack.
SOAP vs. REST/POX
Indigo is a messaging system that deals with messages that are represented by an envelope with headers and a body: SOAP. Indigo is so soaked with SOAP that you might just be able to wash your hands with a WinFX SDK CD. Still, the fact that Indigo is using an information model that is aligned with SOAP means nothing for what goes on or comes from the wire as I will show you later.
Fundamentally, the reason for why anybody might be using SOAP is that it gives you two places to stick things: A header section for metadata and a body section for payload. The headers are important if you need to communicate addressing, security or other information independent from a transport and across multiple communication hops. HTTP does have an extensible headers model, but other messaging transport options don’t. So to make things consistent across all sorts of transports and to provide an abstraction away from the transport specifics, all metadata needed to establish communication is stuck into an envelope alongside the payload. If you look at SOAP and WS-Addressing combined, you can find that the information content is really not much more than that of an IP packet (yes, IP=Internet Protocol). SOAP/WS-Addressing provide an abstraction for routing packages over any sort of transport just as much as IP provided an abstraction over Ethernet, Token Ring, ArcNet and so forth The problematically-named WS-ReliableMessaging is the TCP equivalent, by the way.
But: If you’ve decided that HTTP is all you need and REST/POX is the way to go for your application, you are apparently happy with a request/response model, you don’t need routing or reliable delivery, transport/app-protocol level security is sufficient, and you don’t need to have an abstraction of the HTTP headers and HTTP methods. In that case, the features that SOAP and the WS-* stack give you could be considered redundant. Let’s assume that’s so and try to eliminate SOAP out of the equation.
Figuring out a programming model
Incoming SOAP messages can be dispatched to handlers, typically methods, in two (and a half) different ways. The first (and a half) and most common option is to dispatch based on the value of the SOAPAction: (SOAP 1.1) HTTP header or the “action” media type parameter (SOAP 1.2). Alternatively, some stacks dispatch on the value of the WS-Addressing wsa:Action header, if present. The second way to dispatch messages it to look at the immediate child element of the soap:Body and to associate that content with a handler. The mapping rules are also spelled out in WS-Addressing. Indigo, like ASP.NET web services, uses the first method of dispatching, because that doesn’t require touching the message content.
Now, if we want to do away with SOAP and only want to kick plain old XML documents or even raw binary data around, we have a bit of a problem. Since there are neither any of the HTTP header hints, nor do we have a WS-Addressing wsa:Action header that Indigo could at, its got no information that it could use to dispatch the incoming request on. Even worse: If the incoming request is just an HTTP GET with no entity-body, at all, there’s really nothing to look at except, well, the HTTP method and the URI.
But let’s take a step back and look at this Indigo service contract (I spare you the WSDL) that makes any REST/POX person cringe and shout “This is RPC!”:
|
[ServiceContract] interface ICustomerInfo { [OperationContract] CustomerInfo GetCustomerInfo(string customerKey); [OperationContract] void UpdateCustomerInfo(CustomerInfo info); [OperationContract] void DeleteCustomerInfo(string customerKey); } |
And, yes, this is very RPC like and I could use this exact contract with Enterprise Services or Remoting. It’s also perfectly fine for SOAP Web Services. The action values that Indigo uses for its dispatcher are, because we don’t specify any overrides in the attributes, derived from the method names combined with the port type name (here implicitly ICustomerInfo) and the contract namespace (here implicitly http://tempouri.org). So for this plain definition the action value for the operation GetCustomerInfo() is http://tempuri.org/ICustomerInfo/GetCustomerInfo. An incoming message with that exact URI as its action identifier is mapped to the operation implementation of the GetCustomerInfo() method.
However, without SOAP this dispatch strategy no longer works. Let’s assume from here on that the only thing that goes onto the wire are plain XML documents and not SOAP envelopes. We only send and receive XML payload with nothing around it. (You’ll get to see the “how to” later in this series).
Also, if you were a REST/POX person, you’d rightfully say that there is redundancy in this contract for two reasons. First, because HTTP is an application protocol (Mark Baker, one of the most visible REST proponents, keeps reminding the public about this) and it already defines methods for “Get”, “Update” (PUT), and “Delete”. With SOAP web services, everything is typically POSTed and so it’s effectively tunneling all sorts of semantics through what’s supposed to be the create semantics of HTTP and that makes purists fundamentally unhappy. Second, the “customerKey” for identifying the object is redundant because identifying the resource you want to modify or query is the job of the URL. (Note that I intentionally leave “Create” (POST) out of this for the moment. We’ll get back to that later.)
A more RESTish and HTTP aligned contract definition could look like this:
|
[ServiceContract] interface ICustomerResource { [OperationContract] CustomerInfo Get(); [OperationContract] void Put(CustomerInfo info); [OperationContract] void Delete(); } |
Now we assume, for a moment, that every customer in the system had its own HTTP service endpoint. If you have a million customers, you have a million endpoints, probably looking like this: http://www.example.com/myapp/customers/00212332. Each of these endpoints has an implementation of the shown interface, representing the resource.
Each of these million services already knows the customer key when a call reaches its endpoint, because each endpoint represents exactly one customer. Therfore we don’t have to pass any parameters to the service for Get or Delete. Get returns the data representation of the service endpoint’s very own, exclusively assigned customer. Following the same logic, the CustomerInfo record that we pass as an argument to Put() (Update) doesn’t need to contain an identifier. This new contract definition would also have sufficient metadata for a dispatcher extension for Indigo that we need to replace the SOAP action dispatcher, because we could map the incoming HTTP method directly to the respective handler by doing a (case-insensitive) string compare to the method name on the interface. HTTP GET maps to Get(), HTTP POST maps to Post(), and so forth.
I think that you probably even could create a million endpoints, but of course such an application would be a complete pig. I haven’t tried and I don’t think you should. So we should find a way to optimize the million endpoints down to one endpoint and from an implementation standpoint it would be rather useful if one service implementation could deal with multiple resource types. That means that we might want to have multiple GET or DELETE methods sitting on the same interface but handling different resources. That aside, “Post” and “Put” are not immediately intuitive names for “Create” and “Update” so that it’d be nice to decouple the application’s operation names from the HTTP method names.
To satisfy all of these requirements, I am adding a little additional metadata to this contract declaration:
|
[ServiceContract] interface IMyApp { [OperationContract, HttpMethod("GET",UriSuffix="/customers/*")] CustomerInfo GetCustomerInfo(); [OperationContract, HttpMethod("PUT", UriSuffix = "/customers/*")] void UpdateCustomerInfo(CustomerInfo info); [OperationContract, HttpMethod("DELETE", UriSuffix = "/customers/*")] void DeleteCustomerInfo(); } |
The HttpMethodAttribute that I have written which I’ll show and explain in more detail in the next post, has a mandatory argument method which is the HTTP method that the operation handles. Along with that I’ll show an Indigo address filter and an Indigo operation selector that plug into the Indigo dispatch engine and perform the mapping for the incoming request to the correct handler based on the comparison of the HTTP method value and the attribute’s method value.
The optional, named attribute property UriSuffix allows narrowing the match to a namespace. If an implementation of this contract were hosted at http://www.example.com/myapp, only HTTP GET requests made on http://www.example.com/myapp/customers/ or any sub-path of that URL (the ‘*’ acts as wildcard) would be dispatched to GetCustomers(). Inside the method it is then very easy (String.LastIndexOf(‘/’)) to parse out the customer identifier from the URL that can be retrieved from the http request message property or the incoming message’s header collection (Indigo maps a set of HTTP transport information items to message headers if you ask it to). So if we were extending this service to also manage a set of phone/fax/mobile numbers for the customer, we could do it this way:
|
[ServiceContract] interface IMyApp { [OperationContract, HttpMethod("POST", UriSuffix = "/customers/*/comm/*")] void CreateCommunicationNumber(CommNoInfo commNoInfo); [OperationContract, HttpMethod("GET", UriSuffix = "/customers/*/comm/*")] CommNoInfo GetCommunicationNumber(); [OperationContract, HttpMethod("PUT", UriSuffix = "/customers/*/comm/*")] void UpdateCommunicationNumber(CommNoInfo info); [OperationContract, HttpMethod("DELETE", UriSuffix = "/customers/*/comm/*")] void DeleteCommunicationNumber(); [OperationContract, HttpMethod("GET",UriSuffix="/customers/*")] CustomerInfo GetCustomerInfo(); [OperationContract, HttpMethod("PUT", UriSuffix = "/customers/*")] void UpdateCustomerInfo(CustomerInfo info); [OperationContract, HttpMethod("DELETE", UriSuffix = "/customers/*")] void DeleteCustomerInfo(); } |
With the support for multiple namespaces we can create a neat, hierarchical external representation of our data whereby each data element has its individual URL. The fun part is that the application-level implementation does not differ greatly from what you would do in a “normal” app. The “magic” sits in the infrastructure. Sticking with our example, the home phone number data bit for a customer might be retrievable or manipulated here: http://www.example.com/myapp/customers/00212332/comm/home-phone.
Mind that for all examples I’ve shown here, I made the implicit suggestion that we’d use XML serialization. That’s really only for illustrative purposes. It turns out that a lot of the REST/POX proponents are also defenders of the pure beauty of angle brackets and therefore I’ll switch to a pure XML message model with the next post, because that is indeed quite a bit more flexible for this particular application style as you’ll see.
Go to Part 2
Back to blogland. Looking back at this year, i have hardly blogged at all. Partly because I wad too busy and partly because I just had better things to do with my free time. Anyways, in the upcoming weeks I'll write about the things that I've been quietly building in the past half year or so and also dig into and publish stuff from my code archive where I still have some gems laying around that should really be published before they get totally useless. I even have a very cool NETFX 2.0 update for this here.
Part of what I am going to blog about and explain in quite some detail is the (code-named) "Clemens TV" project, which I keep working on. As things stand right now, there are so many variables and configuration issues with getting this to work for everyone (or "anyone but myself" for starters) that it doesn't seem feasible from a support perspective to make all of it public in the same way as I did with dasBlog. Instead, I'll publish a framework that allows hooking in all sorts of (self-written) live TV providers into a common (Indigo/WCF) server app. I will publish a provider for public web streams.
However, if you happen to use SnapStream's Beyond TV and have an additional Beyond TV Link license (that's required for the Beyond TV provider for the app), you have at least one software encoding TV card (hardware encoding cards won't work for web streams), and you have a connection with at least 256 KBps upstream, drop me a line to clemensv@newtelligence.com and I'll put you on a short list for those folks who might get the provider for testing (and to keep) once I am happy with it. We'll see where we go from there.
That said, the application is only partially about TV. It's a showcase demonstrating that Indigo is not only about pushing SOAP envelopes around. I am sending RSS, ASX, OPML and multi-gigabyte, restartable MPEG downloads through Indigo channels and all the receiving application sees is a plain old data stream or plain old XML (nicknamed POX). And when I want to record a show I send an HTTP POST to an endpoint to update the episode details and add a recording and when I want to cancel the recording I send an HTTP DELETE to remove the recording job. That smells like REST. I am sure Mark Baker will dig Indigo once he sees my set of ServiceModel extensions 
Anyways, this is just a "heads up" that it's probably worth looking this direction in the upcoming weeks, no matter whether you are checking out Indigo today or are doing stuff with shipping technologies such as Enterprise Services.
Joe McKendrick at ZDNet cites Joel Spolsky and his "Web 2.0" rant.
What is particularly interesting about this new hype-term that this is the first technology term that describes nothing at all about technology. It rather seems to describe that a suffiently large, critical mass of people has grasped a sufficiently broad set of technologies (most of which have been available for the past 4-5 years) for DHTML and XML to actually go mainstream. And clearly contributing to that is (even though everybody seems to complain mostly about IE and its gaps in standards support) that Mozilla seems to have managed to clear the dreaded Netscape 4 garbage off the net.
AJAX is the same buzzword b/s. I am currently building an AJAX app, yay! In order to remember a few things and how they worked, I dug in code dating a few years back that sits in my "OldStuff" directory. Innovation!
And VCs going crazy about this is something that absolutely shocks me.
We have some immediately open positions for employment and freelance work.
Wir haben ab sofort einige offene Stellen im Angestelltenverhältnis und auch für freiberufliche Tätigkeiten.
Bewerbungen an/Applications to jobs@newtelligence.com
(Individuals only. Head hunters, or body shops need not apply)
This project is serious fun. Nothing is better than something that helps a
geek figuring out technology and has an immediate tangible personal benefit. My
“ClemensTV” (quite a humble choice of a code name!) project is one
of these. The screenshot below shows what my Indigo service does to a
completely innocent and unsuspecting Windows Media Player without any
additional client code install/footprint. Worked on first try on my girlfriend
Sabine’s notebook (that’s the benchmark; she doesn’t even
have .NET 1.x on her machine) as well as on a few of my friends’ machines
who I gave nothing but a username/password and an URL.
XHTML with inline AJAX scripts, ASX stream envelopes, ASX play lists, RSS,
OPML, and even raw binary GIFs all served from Indigo endpoints (one per TV
channel and one for the overall channel lineup). With [ServiceContract] and
[OperationContract] and all that jazz (plus, admittedly, some somewhat
significant code, config and attribute “magic”).
The only thing in the Windows Media Player content pane that isn’t
served up through an Indigo channel is the live video stream itself – and
if it were necessary…

Tech details to come… Gotta watch TV 
End of the hibernation mode. Here’s one of the reasons (besides a lot of “actual work”) why I’ve been hiding in the past few months. And it very much feels like the start of a project I started a while ago (7/17/03 was the day I switched) and which is now this:
Since the beginning of the year I’ve been throwing around some ideas to fix a personal “problem” that I have as a frequent business traveler: Access to “my” local cable television (football!) and the recorded content that I have on my home machine. As I blogged already, I bought a Windows Media Center PC along with SnapStream’s BeyondTV product as a personal video recorder and “live streaming” server and got myself a 3072/512 KBps DSL connection.
It turned out that my concrete use case of wanting to access my home machine and content primarily from hotels and elsewhere on the road (and not so much from within my apartment) isn’t well covered by either Windows Media Center Edition or BeyondTV. Both products have options to stream content across the local network in some way. In addition to that BeyondTV has a small built-in web server that lets you access live TV and streams via a HTML interface so that you can actually get at it from anywhere. In fact, there are extensions for Media Center that let you do something similar. But somehow, none of that was really the solution I envisioned. What I wanted is a smart client that works online and offline and can replicate recorded content down to my notebook’s disk. I want to have the TV guide data (electronic program guide) cached on my notebook so I can schedule recordings locally (and replicate them down to the PVR as I get connected) and/or get alerts whenever a show is coming up that is of interest to me. I want a smart client that has a “10 feet” user interface and support for a remote control and the smart client shall look graphically appealing. And lastly, and possibly most importantly, I want a good excuse to stuff as many feature showcases for Indigo and Avalon (yeah, yeah: WCF/WPF, yadda, yadda) into the combined solution.
When I started thinking about how to approach this, I was thinking that the smart client was the thing to focus on. So by now I have acquired what I think is a rather scarily broad set of Avalon development skills (for a server guy, at least). Heck, I even taught myself how to tilt and turn a 3D plane with video on it without having to copy someone else’s XAML! The first UI prototype was sitting right on top of BeyondTV’s API, which is exposed as a set of Web Services, but somewhat feels like a COM API on a longer leash. Since using that API directly is a bit cumbersome, I wrote a wrapper around it to make it a bit more accessible and “service like”. And while that was all cute and started working, it somehow it still didn’t feel like the right thing to do.
What would I do about other sources? NASA TV provides a live web stream that I sometimes look at, not to mention various video webcasts for developers and the like. And what about podcasts? What about internet radio? Couldn’t blogs be integrated into all of that? Wait…. couldn’t my live TV and recording sources be like blogs?
Well, I can program and hence they can. I wrote and I am still writing an Indigo-powered server that wraps BeyondTV (and other sources) to become a “video blog” server. My Avalon-powered smart client for which I have some bits and pieces in place of course won’t be dependent on my video server, but will understand blogs, podcasts, video blogs and whatever else I can find and will integrate it all into a remote control navigable text/radio/video UI.
I’ll drill into and write about the things that I am doing to make it all work in the next few weeks and months and as I proceed. For now, I’ll just tease you a bit and show you a selection of three (incomplete in terms of content and features) XML snippets that the server generates. If you hit the server application root directory, you get an OPML with all the live TV channels that are available (the list below is shortened considerably):
< opml > < head > < title > TV </ title > < dateCreated > Mon, 17 Oct 2005 14:27:04 GMT </ dateCreated >   |