News Blog - For August 2008
-
Release 0.4
I have posted the fourth release to CodePlex. This release contains new support for the Atom Threading Extensions. This means that BlogSvc supports threaded comments. The website was also updated with new annotation controls using special jQuery support. As part of this release we have created/updated the following documentation.
There is a known issue with this release where media uploads fail with a 404 not found. It has been fixed in latest source code.
Looking forward to the next release, we will focus on testing, documentation, and installation. There will be some great new features on the website such as:
- Rating entries (jQuery Stars)
- Approval system (comment moderation)
- New pages for browsing by category, date, or person (author or contributor).
-
BlogSvc Now Supports Comments
The WCF annotation support in BlogSvc has been updated with the standardized Atom Threading Extensions. The website has also been updated with a very unique method of creating new comments. Lets just say, classic forms + jquery + ajax + rest = awesome. Most of the new code is in the Annotate.ascx. And most of that code is javascript/jquery code.
Currently, BlogSvc only supports anonymous comments. I do plan to support OpenID. In the meantime, all commentators are required to supply an email and website. Commentators can use html in their comments. I am using some anti-xss code to sanitize the html.
Thanks to jquery there is some pretty validation going on. I must say, I really like jquery. However, there are some quarks when working with jquery and calling a service that returns xml with a custom content-type such as application/xml+atom. However, I found workarounds to get things working.
Finally, BlogSvc does support threading comments. However, the website does not yet support annotating an annotation. It should be very easy to add using jquery.
I've also added some technical information to the Documentation.
Feel free to leave a comment to test things out.
-
Refactor Session
I have rearranged the solution during a large refactor session. Any non-domain specific logic has been moved into a new services project. The provider pattern has been replaced with a repository. The repositories and services all have interfaces to support future extensibility. I've already leveraged the authenticate interface to support multiple authentication schemes.
-
From Urn to Tag URIs
I'm migrating the usage of the urn scheme for IDs to the tag scheme. Only registered types are allowed to use the urn scheme. The tag scheme actually fits in very close to how I was using the urn scheme so the migration should be pretty painless. I've posted a new entry about URIs and URLs in BlogSvc that give plenty of examples of how BlogService will ID and locate resources.
-
BlogSvc AtomPub Release 0.3
I've uploaded a new release to CodePlex. This is the first release containing solid AtomPub support. Also, the website has been improved. This release contains the following new/improved features:
- Object model usage improvements (such as ToString)
- FileAtomPubProvider configuration extensions including file and folder paths
- Administrator support added to AppService
- WSSE authentication that supports anonymous and token expiration
- Roles added based on AppService
- Saving of AppService and AppCategories documents
- Add category (fixed, unfixed) to internal or external categories
- ETag support for caching and improved Live Writer performance
- HEAD request supported on entry and media resources
- New website, with new controls
- Load RSS feed using Syndication support in .NET 3.5
This release has been tested on both IIS 6 and IIS 7 integrated. The next release may leave IIS 6 support behind in favor of IIS 7 integrated mode. This would improve the URI formats throughout the system. However, the ID's would remain unchanged as they were designed to support many URL schemes.
BlogSvc creates IDs that are made up of 3 to 4 parts:
urn:{workspace*}.{domain}:{collection},{entryPath}
The workspace is optional unless there are multiple workspaces on the same site. The domain typically matches the domain of where the site is being hosted. The collection signifies the collection in the workspace. The entry path is a comma separated listing of the entry location in an optional thread.
Examples Blog Collection urn:blogsvc.net:blog About Entry in Info Collection urn:blogsvc.net:info,About Blog Post on Multi-user Site urn:kristin.jvance.com:blog,2008-08-08-AnotherPost Comment to Blog Post urn:blogsvc.net:blog,2008-08-08-MyBlogPost,1 Response to a Comment urn:blogsvc.net:blog,2008-08-08-MyBlogPost,1,1 See the release page for more details.
-
New Website
BlogSvc just got a new website. There are plenty of tweaks that still need to be done. This site can be used as an example of using BlogSvc directly through the provider API. With the strongly typed Atom and AtomPub objects, it is very simple to program against. And if you prefer to work directly with the Xml then that is also available. Also, live writer support is fully functional with WSSE authentication.
-
Ape Results 8/7
APP Service doc: http://atomsite.net/blog.svc/service
Summary: 0 errors, 6 warnings.
-
TESTING: Service
document and collections.
-
✓ Retrieval of Service Document: it exists and is served properly.
-
Found these
collections:
-
'FrontPage Blog' accepts application/atom+xml;type=entry
-
'Image Store' accepts image/png, image/jpeg, image/gif
-
-
Will use collection
'FrontPage Blog' for entry creation.
-
✓ Page 1 of Entry collection: it exists and is served properly.
-
✓ Entry collection has correct app:edited value order.
-
TESTING: Entry-posting
basics.
-
Now in the Entries
feed:
-
Test Multi-pic Post
-
BlogSvc Preview Release 0.2
-
-
✓ Posting of new entry to the Entries collection reported success, Location: http://atomsite.net/blog.svc/www/blog/2008-08-07-Ape-64739
-
Examining the new entry
as returned in the POST response
-
✓ Returned entry is consistent with posted entry.
-
✓ Provided categories included in Returned entry.
-
✓ Server preserved foreign markup in Returned entry.
-
✓ Retrieval of newly created entry: it exists and is served properly.
-
Examining the new entry
as retrieved using Location header in POST response:
-
? Client-provided slug 'ape-64739' not used in server-generated URI.
-
✓ Retrieved entry is consistent with posted entry.
-
✓ Provided categories included in Retrieved entry.
-
✓ Server preserved foreign markup in Retrieved entry.
-
Examining the new entry
as it appears in the collection feed:
-
✓ Entry from collection feed is consistent with posted entry.
-
✓ Provided categories included in Entry from collection feed.
-
✓ Server preserved foreign markup in Entry from collection feed.
-
✓ Update of new entry reported success.
-
✓ Title of new entry successfully updated.
-
✓ Entry deletion reported success.
-
✓ Entry not found in feed after deletion.
-
TESTING: Collection
re-ordering after PUT.
-
✓ Page 1 of Entries with multi-post: it exists and is served properly.
-
✓ Entries with multi-post has correct app:edited value order.
-
✓ Entries correctly ordered after multi-post.
-
✓ Page 1 of Entries post-update: it exists and is served properly.
-
✓ Entries post-update has correct app:edited value order.
-
✓ Entry deletion reported success.
-
✓ Entry deletion reported success.
-
✓ Entry deletion reported success.
-
✓ Entries correctly ordered after update of multi-post.
-
TESTING: Content
sanitization
-
✓ Retrieval of unclean XHTML entry: it exists and is served properly.
-
? Published entry retains xhtml:script element.
-
? Published entry retains 'background' attribute.
-
? Published entry retains 'style' attribute.
-
? Published entry retains dangerous hyperlink: 'javascript:evil'.
-
✓ Entry deletion reported success.
-
Will use collection
'Image Store' for media creation.
-
TESTING: Posting to
media collection.
-
✓ Post of image file reported success, media link location: http://atomsite.net/blog.svc/www/media/2008-08-07-Apix-70783
-
✓ Retrieval of media link entry: it exists and is served properly.
-
? Client-provided slug 'apix-70783' not used in Media Resource URI.
-
✓ Retrieval of media resource: it exists and is served properly.
-
✓ Media resource was apparently stored and retrieved properly.
-
✓ Entry deletion reported success.
-
✓ Media link entry no longer in feed.
-
✓ Media resource no longer fetchable.
-
TESTING: Media
collection re-ordering after PUT.
-
✓ Page 1 of Pictures from multi-post: it exists and is served properly.
-
✓ Pictures from multi-post has correct app:edited value order.
-
✓ Fetch image to get ETag: it exists and is served properly.
-
✓ Update one of newly posted pictures went OK.
-
✓ Page 1 of MLEs post-update: it exists and is served properly.
-
✓ MLEs post-update has correct app:edited value order.
-
✓ Entry deletion reported success.
-
✓ Entry deletion reported success.
-
✓ Entry deletion reported success.
-
✓ Entries correctly ordered after update of multi-post.
-
-
Test Multi-pic Post
Test update
-
BlogSvc Preview Release 0.2
I've put a new release up on codeplex. This release includes an implementation of Atom Publishing Protocol on WCF 3.5. In the words of Tim Bray:
An Atompub implementation lets you create, retrieve, update, and delete (CRUD) Web Resources. ... Atompub starts with a Service Document, which contains one or more named Workspaces, which contain Collections, which are what you actually POST to in order to start up the CRUD process. So the idea is simple; have a collection that when you POST to it, creates a new publication.
The object model is based off of the Atom Syndication Format and the AtomPub specs. All of the objects are based off of Xml or the new XElement. This means that each object has an Xml property that points to the underlying xml. The object's propeties have getters and setters which access the xml as strongly typed values.
Atom Syndication Format Atom Publishing Protocol AtomCategory AppCategories AtomContent AppCollection AtomEntry* AppControl AtomFeed AppService AtomGenerator AppWorkspace AtomLink* AtomPerson Atom Threading Extension AtomSource ThreadInReplyTo AtomText * Extended The objects listed above all support extensions and furthermore, it is very easy to add strongly typed access to those extensions. Note: .NET 3.5 already contains objects that are close to the Atom objects above and .NET 3.5 SP1 will have objects for AtomPub. See System.ServiceModel.Syndication namepace. In a future blog post, I will explain why I decided to go with the above object model over what is provided in the framework.
This release should work in IIS6 or IIS7 with .NET 3.5. Also the SVC handler must support all verbs. Since AtomPub is RESTful, you'll need PUT and DELETE to go along with the usual GET and POST verbs.
The WCF service is built using the new Web Programming Model available in 3.5. However, it is designed to support normal web services as well (more on this in a future post). A neat WCF feature with this release is the support of media entries allowing a user to post images to a collection. I found the trick to supporting raw data on Carlos' blog. However, there is a catch. Anytime you want to accept unknown content types and known content types, you must only deal with Stream objects. For example, although CreateEntry will always return an AtomEntry document you must specify a Stream because the input could be an AtomEntry or say a JPG image.
[ServiceContract] public interface IAtomPub { [WebGet(BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "{workspaceName}/{collectionName}/{entryName}/media")] Stream RetrieveMedia(string workspaceName, string collectionName, string entryName); [WebInvoke(BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "{workspaceName}/{collectionName}")] Stream CreateEntry(string workspaceName, string collectionName, Stream stream); [WebGet(UriTemplate = "{workspaceName}/{collectionName}/{entryName}")] Stream RetrieveEntry(string workspaceName, string collectionName, string entryName); [WebInvoke(BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "{workspaceName}/{collectionName}/{entryName}", Method = "PUT")] Stream UpdateEntry(string workspaceName, string collectionName, string entryName, Stream stream); [WebInvoke(UriTemplate = "{workspaceName}/{collectionName}/{entryName}", Method = "DELETE")] void DeleteEntry(string workspaceName, string collectionName, string entryName); [WebGet(UriTemplate = "service")] AppService RetrieveService(); [WebGet(UriTemplate = "{workspaceName}/{collectionName}/category?scheme={scheme}")] AppCategories RetrieveCategories(string workspaceName, string collectionName, string scheme); [WebGet(UriTemplate = "{workspaceName}/{collectionName}")] AtomFeed RetrieveFeed(string workspaceName, string collectionName); }You can direct it to a strongly typed implementation by checking the content type.
public Stream CreateEntry(string workspaceName, string collectionName, Stream stream) { string contentType = WebOperationContext.Current.IncomingRequest.ContentType; AtomEntry entry; if (contentType == Atom.ContentType || contentType == Atom.ContentTypeEntry) { entry = new AtomEntry(); XmlReader reader = new XmlTextReader(stream); entry.Xml = XElement.Load(reader); entry = CreateEntry(workspaceName, collectionName, entry); } else entry = CreateMedia(workspaceName, collectionName, stream); return GetStream(entry); }Please see the release page for more details.
In the next post, I will discuss workspace, collection, entry names, id's, links, etc.