The most notable restriction is that there are no database changes; the first release will use the same database as the current site, and for the most part, I'm keeping it as a read-only feed. This clearly restricts what can be done in the first release quite a bit, but it also means that we'll be able to test the new site using the same user accounts and forum DB as V4. Going forward we'll start to establish new database parts and run them alongside the V4 parts, gradually migrating things over.
GDNet V5 is built around the Windows Communication Foundation, better known as WCF. WCF is a .NET-based framework for providing and consuming services (such as those of the web variety), and it's a really, really nice one at that. The best way to explain how it works is probably to show it off.
V5 is broken down into discrete services; each service handles some group of related functionality for the site. Each service is in turn a service contract - basically just an interface - and an implementation of that contract. Here's part of the service contract for the 'discussion' service:
[ServiceContract] interface IDiscussionService { [OperationContract] [WebGet(UriTemplate="", BodyStyle=WebMessageBodyStyle.Bare)] Stream GetDiscussionOverviewPage(); [OperationContract] [WebGet(UriTemplate = "activeTopics", BodyStyle = WebMessageBodyStyle.Bare)] Stream GetActiveTopicsPage(); [OperationContract] [WebGet(UriTemplate = "activeTopics.json", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)] GDNet.Discussion.TopicHeader[] GetActiveTopicsJson(); [OperationContract] [WebGet(UriTemplate = "{id}", BodyStyle = WebMessageBodyStyle.Bare)] Stream GetThread(string id); }
As I said, it's an interface - quite literally. One of the lovely things about this approach is that the client code can just work with an object that supports IDiscussionService - whether that be an actual DiscussionService object, or some kind of WCF proxy that forwards the calls to the service running elsewhere. More about that another time [grin]
Each method is tagged with [OperationContract], indicating that the method is part of what the service exposes. They're also all tagged with the [WebGet] attribute, which does some magic for us: when the service is exposed over HTTP, [WebGet] (and its relative [WebInvoke]) works with the framework to direct service calls based on the URI. For example, if the service is mounted at https://www.gamedev.net/discuss/, then https://www.gamedev.net/discuss/activeTopics.json will route to the GetActiveTopicsJson() method on that interface. This lets me build a lovely RESTful API for the site.
While we're looking at GetActiveTopicsJson(), it's worth mentioning also that the framework takes care of returning results in XML or JSON format if necessary. I just return an array of TopicHeader items, and the framework packs them as JSON for consumption by the javascript on the client side. Things like RSS are similarly simple - I just return an Rss20FeedFormatter or Atom10FeedFormatter and it takes care of writing things out in the appropriate format.<br><br>The other methods you see in that interface all return Stream objects. Stream is what you use if you're going to handle the entire output yourself, and you don't want the framework adding any of its wrappers. In this case, my methods are all taking care of producing the XHTML output that should be sent to the browser themselves, so they return Streams to tell WCF not to interfere.<br><br>Exactly <i>how</i> they produce their XHTML is a topic for the next post.<div> </div>