Angel \”Java\” Lopez on Blog

October 11, 2010

Dissecting NuPack (Part 2) The Package Feed

Filed under: .NET, NuPack, Package Management — ajlopez @ 6:19 pm

In the previous post of this serie, I introduced NuPack package manager:

Dissecting NuPack (Part 1) Introduction

I would like to explore NuPack internal process. First, to run using the source code, I installed:

Visual Studio 2010 SDK
PowerShell 2.0

Then, this is the current solution (October 11th):

NuPack.Server project is a web server, written using ASP.NET MVC:

First, note the MVC mapping in global.asax.cs:

            // Map a feed route at the root
            routes.MapRoute("feed",
                            "feed",
                            new { controller = "Packages", action = "Feed" }
            );

The Package controller is in charge of producing the list of package to expose in the server. Its address is /feed. The output:

The source code of Package controller is in Controllers\PackageController.cs. The Feed action will be deprecated in NuPack CPT 2:

        //TODO: This method is deprecated. Need to keep it around till we release NuPack CTP 2.
        public ActionResult Feed() {
            // Add the response header
            Response.AddHeader(PackageUtility.FeedVersionHeader, PackageUtility.AtomFeedVersion);
            if (Request.Headers[PackageUtility.FeedVersionHeader] != null) {
                return new HttpStatusCodeResult(304);
            }
            // Get the last modified of the package directory
            DateTime lastModified = Directory.GetLastWriteTimeUtc(PackageUtility.PackagePhysicalPath);
            return ConditionalGet(lastModified, () => {
                SyndicationFeed packageFeed = PackageSyndicationFeed.Create(
                    PackageUtility.PackagePhysicalPath,
                    package => PackageUtility.GetPackageUrl(package.Id, package.Version.ToString(), Request.Url));
                packageFeed.Title = new TextSyndicationContent("Demo Feed");
                packageFeed.Description = new TextSyndicationContent("Demo package feed");
                SyndicationPerson sp = new SyndicationPerson("person@demofeed.com", "Demo", "http://www.demofeed.com");
                packageFeed.Authors.Add(sp);
                packageFeed.Copyright = new TextSyndicationContent("Copyright " + DateTime.Now.Year);
                packageFeed.Description = new TextSyndicationContent("ASP.NET package feed");
                packageFeed.Language = "en-us";
                packageFeed.LastUpdatedTime = lastModified;
                return new SyndicationFeedResult(packageFeed,
                                                 feed => new Atom10FeedFormatter(feed));
            });
        }

The packages are retrieved from PackageUtility.PackagePhysicalPath:

    public class PackageUtility {
        internal static string PackagePhysicalPath = HostingEnvironment.MapPath("~/Packages");
        internal static string AtomFeedVersion = "1.0";
        internal static string ODataFeedVersion = "2.0";
        internal static string FeedVersionHeader = "NuPackVersion";

I copied NuPack packages files (with .nupkg extension) from package directory (included in the download) (In previous versions, the Server contained a complete list of .nupkg files, but now, we should add the package to the /Packages INSIDE web server).

There is a new OData service, in /DataServices/Packages.svc. The initialization code:

        protected override void OnStartProcessingRequest(ProcessRequestArgs args) {
            base.OnStartProcessingRequest(args);
            // HACK: Exceptions for control flow yay! Only way to stop the request from completing
            // right now
            HttpRequestBase request = new HttpRequestWrapper(HttpContext.Current.Request);
            DateTime lastModified = Directory.GetLastWriteTimeUtc(PackageUtility.PackagePhysicalPath);
            if (request.IsUnmodified(lastModified)) {
                throw new DataServiceException(304, null);
            }
            // Stick the version header in the response
            args.OperationContext.ResponseHeaders[PackageUtility.FeedVersionHeader] = PackageUtility.ODataFeedVersion;
            // Try to determine if this is a request for the feed version
            if(args.OperationContext.RequestHeaders[PackageUtility.FeedVersionHeader] != null) {
                throw new DataServiceException(200, null);
            }
            HttpCachePolicy cachePolicy = HttpContext.Current.Response.Cache;
            cachePolicy.SetCacheability(HttpCacheability.Public);
            cachePolicy.SetLastModified(Directory.GetLastWriteTimeUtc(PackageUtility.PackagePhysicalPath));
        }

The PackageContext is the key class to get an IQueryable over existing packages:

namespace NuPack.Server.DataServices {
    public class PackageContext {
        private IPackageRepository _repository;
        public PackageContext(IPackageRepository repository) {
            _repository = repository;
        }
        public IQueryable<Package> Packages {
            get {
                return from package in _repository.GetPackages()
                       select new Package(package);
            }
        }
    }
}

More about WCF DataServices and OData:

http://msdn.microsoft.com/en-us/data/ee720180.aspx

http://www.odata.org/developers/protocols/uri-conventions

You can obtain the list of packages entering /DataServices/Packages.svc/Packages in browser:

I should explore the NuPack.Core, the way a package is created and installed.

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: