When you’re writing provider hosted app, you probably know the procedure for publishing those. That procedure includes packaging the app package, which is an action Visual Studio will do for you. You enter your website URL, a client ID and you’re off. But what if you host your app on multiple locations having different URL’s?
Upon packaging a SharePoint app, Visual Studio will present you with this window:
When you click Finish, Visual Studio will start the packaging process. It uses the above information for that process, mainly to perform some find & replace actions in the files you are packing. One of those files is you AppManifest.xml, which contains:
<Title>Contoso provider hosted TestApp</Title>
Notice the ~remoteAppUrl token. This will be replaced by Visual Studio with the URL you’ve inputted in the above dialog (https://app.contoso.com in this example).
So, why is that a problem? Well, as long as your app is always running in the exact same spot, it isn’t. But there might be scenarios in which you have different hosting locations for different environments, for instance when having several intranet farms. For me, I wrote a test app which we deploy to customer farms to test some connectivity and API stuff before delivering the farm to the customer. These farms are not connected and cannot use the same IIS instance, so we deploy the app to multiple servers.
Each time you want to deploy to a different URL, you need to repackage your app with the correct URL. That can be annoying since it’s normally not something you want to bother your developers with.
SharePoint app packages are based open OPC: Open Packaging Conventions. And the great thing is: those have an API which is hidden in WindowsBase.dll, found in the .NET 4.5 framework. That API allows you to create or manipulate packages, which we will use to edit our SharePoint package.
A Package consists of Parts, which represents the files in the package. These parts expose the GetStream method which can be used to open the content as a Stream object. More information about the OPC standard can be found here: http://msdn.microsoft.com/en-us/magazine/cc163372.aspx.
Note: since you can rename app packages to .zip and extract them, you might consider unzipping, editing the files and then rezipping. That will not work due to additional information a package contains which you will lose when unzipping and rezipping.
So I wrote below Powershell function which changes the AppManifest.xml file inside of an app package, and saves it to disk. The functionality is a simple find & replace on the contents, so you can replace https://app.contoso.com with https://app.company.com for instance. The result is a valid app package file which you can upload to SharePoint without issues.
Function Update-AppManifest($appPackage, $oldUrl, $newUrl)
Add-Type -Path (Get-ChildItem "WindowsBase.dll")
$package = [System.IO.Packaging.Package]::Open($appPackage, [System.IO.FileMode]::Open)
$manifestUri = New-Object System.Uri("/AppManifest.xml", [System.UriKind]::Relative)
$partNameUri = [System.IO.Packaging.PackUriHelper]::CreatePartUri($manifestUri)
$part = $package.GetPart($partNameUri)
$partStream = $part.GetStream()
$reader = New-Object -Type System.IO.StreamReader -ArgumentList $partStream
$content = $reader.ReadToEnd()
$content = $content.Replace($oldUrl, $newUrl)
$partStream.Position = 0
$writer = New-Object -TypeName System.IO.StreamWriter -ArgumentList $partStream
You can use the same code in C# as well obviously. The WindowsBase.dll assembly can be found in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.
Note: a final note; this code only handles appmanifest and the URL. It is not unlikely that more extensive solutions might require more replacing in different files as well. Obviously you can get different Parts of the Package object which represent the other files to repeat the process on those as well.