News Blog - For January 2009
-
Update to ASP.NET MVC RC1
I've checked in the code to update BlogSvc to ASP.NET MVC RC1 Refresh. There were only minor updates to get things workings and the overall process only took around 10 minutes. However, the readme notes on the configuration are misleading. The release notes tell you to update the pages section to look like:
<pages
validateRequest="false"
pageParserFilterType = " System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35 "
pageBaseType = " System.Web.Mvc.ViewPage, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35 "
userControlBaseType = " System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35 " >
This is not necessaryas you'll notice when creating a new MVC project that three bolded lines are not included. When I added the lines to my config it caused errors on my hosting provider.Update: yes, the readme notes are very misleading. These lines should actually be added to the web.config file in the "Views" directory. I added these lines to web.config file in the themes folder.
-
Routing Updates
I just checked in a large refactor on the routing system to allow for collection plug ins to register their own routes. All routing implements the IRouteRegistrar interface that has a RegisterRoutes method. The BaseRouteRegistrar abstract base class contains some useful implementation and logic that can be reused for plug-in routing.
AtomPubRouteRegistrar the implementation for all the default routes. The default routes will always get registered after plug-in routes. Remember, order is important because routing always takes the first match.
Each collection can plug-in their own routing with a constraint that will ensure the routes are only active for the collection/collections that registered the routes.
Also, I added some extensions on top of UrlHelper that calls the RouteService class which has support for SSL routes and absolute routes. We lost automatic deep routes on threaded annotations. However, there's baked in support for "dated" entries. We are using named routes so that makes it really easy to select which route you want when generating the URL.
-
Business and Data Design
Update: The content of this post is outdated. The classes and interfaces have slightly changed in version 0.9 and onward.
The above diagram shows the major classes and interfaces of AtomSite.
-
Refactor for Extensibility
Update: Some of the content of this post is outdated. The whole plug-in system was greatly revised to support better extensibility scenarios.
One the features we are working towards in 2009 are Collection Plug-ins. The goal is to utilize the extensibility of AtomPub so that it is possible to layer any kind of collection on top of it. This is being done by Google, Microsoft, and many others for providing things such as calendars, contacts, photo galleries, etc.
By using a combination of ASP.NET MVC, dependency injection, and extensibility points, we hope to allow any type of collection to be stored on top of AtomPub. To accomplish that, I'm moving towards a design where all collections are built according to IAtomPubService interface. This interface describes the base functionality needed by any collection. The methods in gray are extensions to the AtomPub standard which I consider a core need for managing any collection. I'm have considered splitting this interface into a couple smaller pieces.
public interface IAtomPubService { AppService GetService(); AppService UpdateService(AppService service); AtomFeed GetCollectionFeed(Id collectionId, int pageIndex); AtomFeed GetFeed(Id collectionId, int pageIndex, int pageSize); AtomFeed GetFeedByAuthor(Id collectionId, string authorName, int pageIndex, int pageSize); AtomFeed GetFeedByContributor(Id collectionId, string contributorName, int pageIndex, int pageSize); AtomFeed GetFeedByPerson(Id collectionId, string personName, int pageIndex, int pageSize); AtomFeed GetFeedByDate(Id collectionId, DateTime startDate, DateTime endDate, int pageIndex, int pageSize); AtomFeed GetFeedByCategory(Id collectionId, string term, Uri scheme, int pageIndex, int pageSize); AtomFeed GetFeedBySearch(Id collectionId, string term, int pageIndex, int pageSize); AppCategories GetCategories(Id collectionId, Uri scheme); AtomEntry GetEntry(Id entryId); Stream GetMedia(Id entryId, out string contentType); AtomEntry CreateEntry(Id collectionId, AtomEntry entry, string slug); AtomEntry CreateMedia(Id collectionId, Stream stream, string slug, string contentType); event EntryEventHandler EntryCreated; AtomEntry UpdateEntry(Id entryId, AtomEntry entry, string slug); AtomEntry UpdateMedia(Id entryId, Stream stream, string contentType); event EntryEventHandler EntryUpdated; void DeleteEntry(Id entryId); void DeleteMedia(Id entryId); event EntryEventHandler EntryDeleted; string GetEntryEtag(Id entryId); string GetMediaEtag(Id entryId, out string contentType); AtomEntry Annotate(Id entryId, AtomEntry entry, string slug); AtomEntry MediaAnnotate(Id entryId, Stream stream, string slug, string contentType); event EntryEventHandler Annotation; AtomFeed GetAnnotations(Id id, bool deep, int pageIndex, int pageSize); }We will provide a base implementation (AtomPubService) to this interface that contains only logic required by the AtomPub standard. Collection plug-ins can either extend this base implementation or create a new collection service from scratch against the IAtomPubService interface. For example, a blog collection may extend the AtomPubService to include blog related methods such as ApproveEntry or SendTrackback.
There are some additional methods that may need to be added to support the core infrastructure. For example, a collection should be responsible for registering routes to the resources within that collection. Also, a collection should be responsible for choosing the repository, authorization, and other services based on user configuration.
Hopefully, through the magic of an IoC framework, controllers and views can be selected dynamically when I install a new collection plug-in. For example, I want to create a collection plug-in that will allow me to create generic web pages. Most of the logic I need already exists in the Blog Collection but I have a few changes to add support for sub-page annotations. I just extend the BlogService class and override a couple functions. I create a couple new views and controller actions which hit my new PageService class and I'm done. I'm still working through this scenario, so let me know if you have any comments on the design.
-
Picture Upload Not Supported By Blog Issue in Live Writer 2009
I seem to have stumbled across another bug in Windows Live Writer where you may get an error when posting an entry that contains an image. This error does not always occur.
Fortunately, there is a simple workaround. If you see the error, open the Blogs menu and choose Edit blog settings. Proceed through all the steps of wizard clicking Next then click OK to close the settings. You should now be able to post images again.
I posted this bug to the Windows Live Writer Forum.
Update : newer versions of AtomSite 1.0+ have a permanent workaround for this bug.
-
New Windows Live Writer Usage Guide
Since Live Writer is currently the best way to manage your blog, I created the Live Writer Guide. The guide shows you how to setup your blog, create, edit, and delete posts. It is easy to learn how to perform the basic tasks in Live Writer (except maybe for deleting posts). However, we will be updating the guide to help with some of the more complex tasks in the future.
On a side note, I created and edited the guide within Live Writer. I love switching back and forth between Edit and Source views to get things just right.
Please leave a comment if you have any questions.
-
Category Issue with Windows Live Writer 2009 RC
There is a problem with categories and AtomPub in the latest Release Candidate of Windows Live Writer. Unfortunately, there is no straight forward way to reproduce the "Null category scheme not supported" error.
System.ArgumentException: Null category scheme not supported at WindowsLive.Writer.BlogClient.Clients.AtomProtocolVersion.Atom10ProtocolVersion.CreateCategoryElement(XmlDocument ownerDoc, String category, String categoryScheme, String categoryLabel) at WindowsLive.Writer.BlogClient.Clients.AtomClient.Populate(BlogPost post, Uri documentUri, XmlElement node, Boolean publish) at WindowsLive.Writer.BlogClient.Clients.AtomClient.EditPost(String blogId, BlogPost post, INewCategoryContext newCategoryContext, Boolean publish, String& etag, XmlDocument& remotePost) at WindowsLive.Writer.BlogClient.Blog.EditPost(BlogPost post, INewCategoryContext newCategoryContext, Boolean publish) at WindowsLive.Writer.PostEditor.UpdateWeblogAsyncOperation.DoWork() at WindowsLive.Writer.CoreServices.AsyncOperation.InternalStart()
I contacted Joe Cheng about the problem and he replied with:
Can you try adding scheme="" to your <categories> element? I know that is a little weird.
If you'd rather not do that, you can create a wlwmanifest.xml file with the following contents:
<?xml version="1.0" encoding="utf-8" ?> <manifest xmlns="http://schemas.microsoft.com/wlw/manifest/weblog"> <options> <categoryScheme /> <options> </manifest>
I've added this to the wlwmanifest.xml file that is available for each collection. I believe it has fixed the problem but I won't be sure until I've done more testing.
I just wanted to get this out there in case others are having the same issue.
-
What’s Ahead in 2009
BlogService has come a long way in the past four months. We went from being a small WCF web service all the way to a solid content management system. This year we will continue to move forward with great new features.
Read More