Refactor for Extensibility
Posted in BlogSvc, MVC by JarrettV on 1/14/2009 11:47:44 AM - CSTUpdate: 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.
Comments
Posted by Oisin Grehan on 2/2/2009 4:42:00 PM - CST
Trackback from News Blog on 3/15/2009 7:28:29 PM - CST
Plug-Ins and Dynamic Controllers
Update: The content of this post is out of date. The concept of plug-ins has since been…