A better HTTP publishing script for App-V Clients

02.04.2012

App-V, Tools

Recently I was involved with the customer who uses, amongst the traditional App-V Management Server –based RTSP publishing, a HTTP publishing script that was posted in the App-V Team’s blog mid-2010. This script constructs necessary APPLIST information out of manifest XML files detected on a virtual directory, but unfortunately it has some shortcomings which I decided to fix and present an enhanced version here as a replacement.

One of the shortcomings in the script is actually mentioned in the comments –section of the original blog article and second one is kind of noted at the end of the article itself. Namely the problems were these facts:

  • The script leaves manifest file(s) open, which means that IIS will then have a lock over it preventing updates for the package and resulting a need to do a IIS reset whenever you need to copy over files from the Sequencer.
  • The way client interprets the ICON and OSD attributes in the application list is so that the %SFT_MIME_SOURCE% variable is replaced with whatever you have as an Application Source Root (ASR) setting. If your package files’ location does not exactly match the location that is derived from combining the ASR + what’s comes after the variable in the APPLIST, client is unable to download OSD and/or icon files, resulting a need to do manual fixups of the manifest file.

The first one is definitely a “bug” in the code, but easily fixed, whereas the second point is more interesting one. We are commonly taught to define package path (i.e. Server URL) in the Sequencer’s Deployment –tab as a correct path inside the content directory, but for whatever reason Path –part of that Server URL is not used for Manifest’s OSD and ICO attributes. However, the blog article vaguely makes a statement that:

“Usually, the application files are located in a subfolder on the content share. If this would be the case, and if the package would be located in \\appvcontent\deep zoom composer, and we would set the ASR to http://IISSERVERNAME:80/contentname, this would fail because the client will look in http://IISSERVERNAME:80/contentname/DeepZoomComposer.osd. So on the sequencer, we should make sure the Package Folders are set right so that we do not have to modify the XML manifests afterwards.”

Now, I’m not entirely sure what this “Package Folders” is supposed to be, but at least the URL as set in Deployment tab does not get reflected in Manifest, only in the HREF –attribute of the OSD files. As an example, since I had to test this to be sure, when I used Sequencer 4.6 SP1 HF3 version to do a quick test package with subdirectory part set to “7-Zip Test Package”, I would get this resulting Manifest file:

A manifest file for App-V package does not have modified OSD and ICO paths

As you can see clearly from the screenshot, there aren’t any intermediate subdirectories between %SFT_MIME_SOURCE% and the OSD file (or ICO files for that matter)… So our Manifest definitely needs some on-the-fly patching unless you are willing to fix them by hand, of course!

Since the original article was written in 2010, it could also be that there’s been regression in the App-V Sequencer itself from whatever version was most recent at the time (4.5 I believe), but that theory is not very plausible since I believe that by having directory between the variable and the OSD/ICO name would actually break standalone import capability in App-V when you do it through sftmime.exe and/or associated App-V MSI file.

And why’s that you say? Simply because sftmime importing would need to locate OSD and ICO files when you do importation via “add package:XXX /manifest …” string, and one would assume that %SFT_MIME_SOURCE% is getting replaced with whatever at that time is the current directory for the manifest XML file (which is a temporary directory in the case of MSI importation method). If there’s an extra package-specific subdirectory set after the variable and before OSD file name, App-V Client would then actually try to look for that subdirectory inside the actual package directory already!

Please note that this all is purely educated speculation on my part, this behavior has not been confirmed or documented by the Microsoft as far as I can tell.

Anyways, getting back to the topic at hand we now clearly have a need to do something about that missing subdirectory to make HTTP publishing work correctly with the script. What would be even better is if we could add content directory just as a virtual directory link in IIS instead of having the requirement of placing the script files directory at the root of the content (kind of enforcing the “separation of concerns” –principle, wherein the actually IIS site would be a logically separate directory on the IIS server and content could just be linked from file-server or whatever by UNC mapping virtual directory), but this would require hot-patching the OSD files’ reference to SFT file then as HREF would in that case have an extra subdirectory in-between the base URI coming from ASR and the actual root of the content. Maybe someday even more improved publishing script will emerge, who knows…

Improving the publishing script

Fixing the first issue – i.e. file handles remaining open – is easy; we can wrap the “FileStream file = File.OpenRead(filename)” call with using() –statement, which will ensure that the opened stream will always be closed (disposed) when the using –block ends; even if the inner code generates exception (which is the downside of using that explicit Close() statement as suggested in the comments as a fix: if exception is generated that call would not be reached unless is it’s in finally –block of the error handling). This way we won’t lock the Manifest XML files but only for the short duration script is executing, allowing overriding of package files without IISreset command:

Using statement ensures file stream is closed

Fixing or improving the OSD and ICO path requires somewhat more work, but not overly so as we can leverage the fact that we are dealing with a XML data here. The script basically works by reading in the whole XML tree of the Manifest file and then just rendering a part of it (the APPLIST –part which is pretty much the whole of Manifest sans the initial PACKAGE -element) into output HTTP stream which is the containing XML document as expected by App-V Client for HTTP publishing refresh.

Since we already have the APPLIST content from Manifest in an in-memory XmlDocument object, it’s relatively easy to continue selecting all relevant attributes from it with additional XPath query and modify those attribute as we go before handing the XML out to the world. This way, we can inject our additional subdirectory directly into OSD and ICO paths without having to do anything to the physical Manifest file sitting in our disk. In addition, we need to inject the same data for ICON elements of the file-type association’s ProgId settings so that we will get correct icons for our document types.

We add our new code after the initial XPath query and before writing out the selected part into response stream:

Additions to the script to patch OSD and ICO paths on the fly

I opted for doing some additional checking of selected XML nodes before accessing them despite the fact that there’s overall exception handling block because if there’s some parts missing from the APPLIST for one particular Manifest, you would not want the whole application/package to not be present in the output. And besides, exception handling is much slower in most cases than just doing some sanity checks in the actual logic, not to mention spamming the log file with exception messages of a problem that might not actually be a problem after all.

If we really like to optimize the code, some of the commonalities between three different selects could be refactored to a separate helper method but in this case I think that’s not really necessary. All in all, after these modifications to the publishing script it will return dynamically modified APPLIST so that all OSD and icon references will point to the correct subdirectory underneath the directory where publishing script lives. As I mentioned earlier in the article, better yet would be to support arbitrary levels of nesting (now the script only enumerates immediate subdirectories under the root) for package directories, but this would then require making sure that OSD files’ HREF references are correctly set if you happen to use HTTP or FILE –based streaming for SFT files as well, since in those methods the absolute streaming URI path is critical whereas with RTSP/RTSPS the server side “knows” the location of SFT files and only the ASR –modified part needs to go right.

I have renamed the script file to “HttpPublish.aspx” from the original one (you can have it side-by-side on your IIS directory with the original one while testing), and it can be downloaded from below:

Download attachmentHTTP_publishing_script.zip

And if you happen to have any other ideas for enhancements, please send the mail and I’m happy to have a follow-up post to this one with even more useful script for HTTP publishing!

, , , , , ,

About Kalle Saunamäki

As one of the first four Microsoft App-V MVP's, Kalle has been doing application virtualization since 2003 and virtualization in general from 2000, and is a recognized in-depth technological expert in Microsoft application virtualization community.

View all posts by Kalle Saunamäki

Subscribe

Subscribe to our RSS feed and social profiles to receive updates.

2 Comments on “A better HTTP publishing script for App-V Clients”

  1. David Kozera (@davidkozera) Says:

    Any idea on why I get this error?

    “Parser Error Message: Could not load type ‘Appv_publishing_service.Publish’.”

    Everything seems correct…
    – using .Net 4.0 on the
    – virtual directory converted to application
    etc.

    Any help would be appreciated.

    Reply

  2. Connie Smaardijk Says:

    Thank you. Great stuff!
    I needed to change a few things, but now it works fine.

    The scripts are case-sensitive, I guess that is why David Kozera ran into the parser error.

    My httppublish.aspx:

    First lines of HttpPublish.apsx.cs:

    using System;
    using System.Xml;
    using System.IO;

    namespace appv_publishing_service
    {
    public partial class publishing : System.Web.UI.Page
    {
    protected void generate_app_xml()

    In our environment, we need only the applications to be loaded, and the File Type Associations to be made. But we do not want the shortcuts being created. Therefore I added this piece of code:

    XmlNodeList shortcutNodes = applist.SelectNodes(@”//SHORTCUTLIST”);

    if (shortcutNodes != null)
    foreach(XmlNode shortcut in shortcutNodes)
    {
    shortcut.RemoveAll();
    }

    Reply

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

%d bloggers like this: