A Practical Guide to SharePoint 2013

A Practical Guide to SharePoint 2013
A Practical Guide to SharePoint 2013 - Book by Saifullah Shafiq

Wednesday, February 7, 2007

Creating an Installer for your web service

Update: 
Originally posted: Wednesday, Feb 28, 2007
Some of the links might not work. If you find any dead links, kindly send an email to share.point@yahoo.com. Retrieved from web archive! 
When I first wrote the installer for the WSUploadService, some people asked me how did I create the installer and yesterday when I published the post "Installing WSUploadService manually", again there was a request from one of my blog readers to share the installer code with the community. In this post, I will discuss the installer code.
This installer is a .NET application that copies the web service files to the correct folders on the destination machine. All manual work stated in the article "Installing WSUploadService manually" is done automatically by the installer. After copying the files and modifying some of the default SharePoint files, installer application runs another installer package that simply copies the web service assembly to the correct bin folder. Even this step could have been added in the installer application but I did not have the time so I created a new installer to add the assembly to the GAC. Just a few more lines and we can get rid of the second installer! The source code is attached. Feel free to modify it to meet your own requirements. I found a couple of links on Google that show how to add an assembly to the GAC programmatically:
Creating the second installer (to install assembly in the GAC) is very easy. Just create a web setup project, add the web service assembly file to the project, compile it and you are done. Of course, you may want to take some additional steps that are not actually required but can enhance the performance. For example, remove all dependency files from the package to reduce the installer size. Include a readme.txt in the package to let your users know about the installation steps, history, functionality, etc.
Create a C# application and add following namespaces at the top:
using System.IO;
using System.Diagnostics;
using Microsoft.Win32;
Check Registry to see if the application is already installed. Ask the user if he wants to keep the application. Based on his response, take the action.
RegistryKey rk = Registry.LocalMachine;
RegistryKey nk = rk.OpenSubKey("SOFTWARE\UploadService");
bool bGoAhead = false;

DialogResult response;

if (nk == null)
{
bGoAhead = true;
}
else
{
if ((string)nk.GetValue("Installed") == "1")
{
response = MessageBox.Show("UploadService is already installed! Do you want to uninstall?", "Uninstall", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

If the response from the user is Yes, that is, if he wants to continue with the uninstall, run the following code:
 if (response == DialogResult.Yes)
{
//Uninstall
string dest = (string)nk.GetValue("Path") + @"Program FilesCommon FilesMicrosoft Sharedweb server extensions12ISAPI";

if (File.Exists(dest + "Files.asmx"))
{
File.Delete(dest + "Files.asmx");
}
if (File.Exists(dest + "Filesdisco.aspx"))
{
File.Delete(dest + "Filesdisco.aspx");
}
if (File.Exists(dest + "Fileswsdl.aspx"))
{
File.Delete(dest + "Fileswsdl.aspx");
}
if (File.Exists(dest + "spsdisco_backup.aspx"))
{
File.Delete(dest + "spsdisco.aspx");
File.Copy(dest + "spsdisco_backup.aspx", dest + "spsdisco.aspx");
File.Delete(dest + "spsdisco_backup.aspx");
}
RegistryKey regkey = Registry.LocalMachine;
RegistryKey newkey = regkey.CreateSubKey("SOFTWARE\UploadService");
newkey.SetValue("Installed", "0");

//MessageBox.Show("Uninstall");
System.Diagnostics.Process.Start(Environment.CurrentDirectory + "\setup.exe");

//bGoAhead = true;
this.Close();
This code will remove the values from the registry and then invoke the setup.exe (the second installer) which will remove the web service assembly from the GAC.
If he cancels the setup, simply close the application.
else
{
bGoAhead = false;
this.Close();
}
If the user is running the setup for the first time to install the web service, then use the following code to add values to the registry and run the second installer:
string[] drives = Environment.GetLogicalDrives();
string sPath = @"Program FilesCommon FilesMicrosoft Sharedweb server extensions12ISAPI";


foreach (string sDrive in drives)
{
if (System.IO.Directory.Exists(sDrive + sPath))
{

if ((File.Exists(Environment.CurrentDirectory + "\Files.asmx") && (!File.Exists(sDrive + sPath + "Files.asmx"))))
{
installed = true;
File.Copy(Environment.CurrentDirectory + "\Files.asmx", sDrive + sPath + "Files.asmx", true);

//Modify spsdisco.aspx file!
Modify(sDrive + sPath,"spsdisco",".aspx");

}
if ((File.Exists(Environment.CurrentDirectory + "\Filesdisco.aspx") && (!File.Exists(sDrive + sPath + "Filesdisco.aspx"))))
{
File.Copy(Environment.CurrentDirectory + "\Filesdisco.aspx", sDrive + sPath + "Filesdisco.aspx", true);
}
if ((File.Exists(Environment.CurrentDirectory + "\Fileswsdl.aspx") && (!File.Exists(sDrive + sPath + "Fileswsdl.aspx"))))
{
File.Copy(Environment.CurrentDirectory + "\Fileswsdl.aspx", sDrive + sPath + "Fileswsdl.aspx", true);
}
if (!installed)
{
MessageBox.Show("UploadService could not be installed because default SharePoint installation directory could not be found. Make sure SharePoint is installed on this machine.");
this.Close();
}

System.Diagnostics.Process.Start(Environment.CurrentDirectory + "\setup.exe");


//MessageBox.Show("UploadService has been installed successfully!");
RegistryKey regkey = Registry.LocalMachine;
RegistryKey newkey = regkey.CreateSubKey("SOFTWARE\UploadService");
newkey.SetValue("Installed", "1");
newkey.SetValue("Path", sDrive.ToString());
//break;
this.Close();
The above code uses a Modify() function. Modify() function modifies the spsdisco.aspx file and includes the reference to the web service being installed. After this, the web service will become visible to the users searching for the web services on the server. Here is the Modify() code:
public void Modify(string spsPath, string filename, string ext)
{
try
{
File.Copy(spsPath + filename + ext, spsPath + filename + "_backup" + ext);
File.Delete(spsPath + filename + ext);

StreamReader sr,sr1;
StreamWriter sw;

sw = File.CreateText(spsPath + filename + ext);
sr1 = File.OpenText(Environment.CurrentDirectory + "\replacement.txt");
string str2 = sr1.ReadLine();
string str1 = string.Empty;

while (str2 != null)
{
str1 += str2;
str2 = sr1.ReadLine();
}


sr = File.OpenText(spsPath + filename + "_backup" + ext);
string str = sr.ReadLine();

while (str!=null)
{
if (str.Substring(0) == "</discovery>")
{
str = str.Replace("</discovery>", str1);

}

sw.WriteLine(str);
str = sr.ReadLine();

}

sr.Close();
sr1.Close();
sw.Close();

}
catch (Exception ex)
{
MessageBox.Show(ex.Source + " - " + ex.Message + " - Could not modify the spsdisco.aspx file. Contact web service vendor!");
}
}
This function copies the content of replacement.txt to the spsdisco.aspx file. The code automatically makes a backup copy of the spsdisco.aspx file so that you can go back to the original settings if required. Replacement.txt contains the following:
<contractRef ref=<% SPEncode.WriteHtmlEncodeWithQuote(Response, spWeb.Url + "/_vti_bin/Files.asmx?wsdl",'"'); %> docRef=<% SPEncode.WriteHtmlEncodeWithQuote(Response, spWeb.Url + "/_vti_bin/Files.asmx", '"'); %> xmlns="http://schemas.xmlsoap.org/disco/scl/" />
<soap address=<% SPEncode.WriteHtmlEncodeWithQuote(Response, spWeb.Url + "/_vti_bin/Files.asmx", '"'); %> xmlns:q1="http://schemas.microsoft.com/sharepoint/soap/directory/" binding="q1:FilesSoap" xmlns="http://schemas.xmlsoap.org/disco/soap/" />

</discovery>
To learn more about these tags and to know what this text is, read the following article, which is by the way, one of the most read articles on my blog:
To download the installer code, click here. Download size is 414 KB.
To download the installer application that installs web service assembly to the GAC, click here. Download size is 358 KB.