The problem: You are developing a web service you want Windows SharePoint Services 3.0 to host, but you have not completely finished the design of the web service.
Recently, I needed to create a web service hosted by WSS 3.0. The manual steps required to register the web service in the WSS 3.0 root folders ISAPI directory can be tedious and time consuming if your web service interface design is not complete when you begin coding (not to imply you should be coding without doing any design work!). I initially followed the steps described in the MSDN Walkthrough: Creating a Custom Web Service article (you should do this too if you want to follow along in code!). Once I had created the web service, I quickly realized that, since my web service definition was subject to change, copying files to the layouts folder, running disco.exe, manually editing the resulting files and then copying the edited files to the ISAPI directory was not going to increase my happiness!
The solution: Use the Visual Studio project formats, MSBuild and some custom MSBuild tasks to make your life easier.
After recently finding and thoroughly enjoying the value add of the STSDEV Tools (thank you Ted Pattison!), I decided to leverage the pattern of modifying the build process. I dove into how the STSDEV Tools work and patterned a possible solution to my problem of registering WSS web services during my development builds. The solution described here takes advantage of this pattern and lets Ctrl+Shift+B build and register the web service for you during development.
Let’s walk through the basic steps of the solution:
1. Create a new webservice.targets file. First, you need a targets file that can do all of this work for you. Initially, I started with a Project file and set up some properties I knew I would need.
... "C:\Windows\System32\makecab.exe" "C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\disco.exe" "$(ProgramFiles)\Common Files\Microsoft Shared\web server extensions\12\bin\stsadm.exe" "C:\Windows\System32\makecab.exe" $(ProgramFiles)\Microsoft SDKs\Windows\v6.0A\Bin\gacutil.exe ... REPLACE_WITH_YOUR_SERVICE_NAME
Remember to replace the WSFileNameRoot property with the value for your service if you try this solution out.
2. Next, we need to import a task that will help us do some text manipulation once we have created the disco and wsdl files. See the Note below for how to obtain this task.
3. Now we need a Target that will enable us to register the web service by deploying the assembly to the GAC.
<\!-\- Register in the GAC, copy to layouts and run DISCO.exe to get the WSDL and DISCO files-\-> ...
4. Now, we need to copy the asmx file to a location that is http accessible, and call disco.exe to create DISCO and WSDL files, and change the file extensions.
... <\!-\- Rename the \*.disco and \*.wsdl files to match the service asmx file with \*disco.aspx and \*wsdl.asmx suffixes-\->
5. Next, we use the custom Tasks from the SDC Tasks to replace the service binding locations in the disco and wsdl files to be SharePoint aware. For full details, get dirty and check out any of the services found in the ISAPI directory in the 12 Hive.
<\!-\- Use Sdc Tasks File.RegEx or File.Replace to udpdate the disco and wsdl files-\->
6. To make sure the service changes are caught and can be updated by a “Reload” of any web service references, we call IISRESET to reset the service and ensure our changes are updated.
7. To make sure we are removing the old registered files before we start any of the registration we create an “Unregister” dependency target.
<\!-\- simple remove of the files that are copied to ISAPI direcotry and removal from GAC --> ... ...
8. Now, to tie this into your Visual Studio project, simply right click your web service class library project in Solution Explorer, and select “Unload Project”. Then right click the project again and open in an XML Editor.
9. Add an Imports statement to import our targets file into your project. You can add this line under the Imports statement for the CSharp.targets towards the bottom of the file.
10. Add a call to your Register target by adding the following to the AfterBuild target of your project like so.
That’s it! Now right click on your project in Solution explorer, select “Reload Project” and hit Ctrl+Shift+B to build. Check the 12 Hive’s ISAPI directory for a subdirectory with the same name as your project and your as*x files should be in there. You can now create web references to this web service just like you would any other WSS 3.0 hosted web service.
Finally, there are two lessons learned in this whole process:
- always remember to unload and reload the project that contains the webservices.targets file since changes made to this file will not take effect until the project is reloaded in Visual Studio.
- to help in debugging, turn up build output verbosity by clicking Tools::Options::Projects and Solutions and increasing the “MSBuild project build output verbosity:” to “Diagnostic” to enable detailed information in the Output window
Hopefully this can help someone else save a little time when developing a WSS 3.0 hosted Web Service. Let me know if you have some suggestions or improvements, or even a better way altogether. I’d be interested in learning an alternative approach.
NOTE: This solution assumes 1) that the development environment is a Windows Server 2003 instance with WSS 3.0 installed, and 2) uses the Sdc custom MSBuild tasks located athttp://www.codeplex.com/sdctasks in order to manipulate file content. You will need to download and install these tasks in order to use this solution in your project.