Browsing C#

  1. 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.

    DomainProject  RepoServicesProjects

    Posted by Jarrett on August 19 at 8:37 AM

  2. 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.

    Posted by Jarrett on August 04 at 5:22 PM

Valid XHTML 1.0 Strict