Wednesday, August 29, 2007

Web Services on SharePoint - making F5 Work

I was getting many questions on best practices to write custom web services for sharepoint, and I wanted to write an article about it for some time now. Also, I just had a chance to fiddle around with making F5 (run from visual studio into debug mode) work for a web service I am testing on a sharepoint site. This involved a few tricks, so I am documenting them:

Note - only do this on your development box!

Note - code lines marked in red means that you will need to change the values to your environment values.


I hold that the best practice is not to use the web service as a web application template (that is the default with visual studio) because when deploying to sharepoint, you'r web service usualy needs to sit in the layouts folder, and you do not want to deploy your code files there. You also don't want to use the visual studio publishing mechanism that uses the frontpage server extensions.
The alternative is creating a web service that is deployed as an asmx file to the layouts folder, pointing to a DLL that is deployed to the GAC. That makes it safe and secure, and easier to deploy and track versions.



Step 1 - Create a Web Service (DLL) Project

To create the web service, use Visual Studio 2005, and click "File-New-Project" and select ASP.NET Web Service Application.



If you don't have that project type installed, you may need to change the installed features of Visual Studio on your machine. The good think about this project type is that it creates a web service as a DLL and an asmx and not as a web site.



After the project is created, change the file names, namespace and assembly names as needed (make sure the namespace of the webservice attribute is changed - you don't want "http://tempuri.org/" as your namespace...) and most importantly - sign the assembly as strong name (right click the project, properties, signing tab, sign the assembly).




Now we have to find out the key that was given to the assembly when it was signed. To do that you must first build the web service (I use ctrl-shft-B, or right click the project and select build) and then either drag and drop the DLL to the assembly folder, right click and get the key:



Or you can run a command line from the visual studio SDK (start-programs-visual studio 2005-visual studio tools-Visual Studio 2005 Command Prompt) and type

sn -T "c:\temp\WebService1\WebService1\bin\WebService1.dll"



Once we have the public key token, we can change the web service's asmx file to use the DLL that will be deployed to the gac. Right click the service1.asmx file and choose "View Markup". You need to change the markup to point to the DLL that will be in the GAC, so this is the format you need to use:



<%@ WebService Language="C#" Class="WebService1.Service1, WebService1, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=db33ac6baa259170" %>

Expalantion:

  1. The "WebService1.Service1" part is the "namespace dot classname" of your code. To get that, you will need to open your .cs file, and copy the namespace you are using, add a dot after it, and add the class name.

  2. The "WebService1" (after the comma) is the name of the DLL that you may have set in the project properties under the "application" tab (the "assembly name")

  3. The public key token is the key we got earlier.





Note - I am not sure if this is needed, but I also registered my web service as a safe control in the web.config, before I used any sharepoint code. It's worth checking if this is required or not, and I will update if I have time to test.



Step 2 - Setting up the Build Events

While in the project's properties, switch to the "Build Events" tab. Paste the following in the "post-build event command line" box:


"c:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" /i "$(TargetPath)" /f

copy "$(ProjectDir)\*.asmx" "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS"

"C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\bin\RecycleAppPools.vbs"

"c:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\disco" http://localhost/_layouts/service1.asmx /o:"C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS"




Explanation:


  1. The first line puts the DLL in the GAC.


  2. The second line copies the web service asmx file to the layouts folder. You should make sure your projects do not create same names for asmx files, or they will overwrite eachother!


  3. The third line recycles the application pools. I am doing this with a vbs file that I have written, and placed in the 12 hive's "\bin" folder for my comfort. Here are the contents of the file:


    Set locator = CreateObject("WbemScripting.SWbemLocator")

    Set Service = locator.connectserver(strServer, "root/MicrosoftIISv2")

    Set APCollection = Service.InstancesOf("IISApplicationPool")

    For Each APInstance In APCollection

    APInstance.Recycle

    Next

    echo "Recycle Complete."


  4. The last line build a discovery file for the web service in the layouts folder. if you installed your visual studio 2005 in a different location, you will need to change the folder path to the disco.exe file, and if you changed the name of the asmx (or if you have more than one) you will need to modify that as well. You will also want to change the url to point to a sharepoint site on your machine if you are not using the "localhost" header. In my case, I use the header "portal", so I change is to "http://portal".



Step 3- Change the F5 behavior

To change what happens when you press F5, switch to the "Web" tab, and change the start url to the url to the web service (I use http://portal/_layouts/service1.asmx), then change the "use IIS web server" and change the project url to the rool sharepoint url (I use "http://portal") and tick the "override application root URL and type the same url as the project url:





Last Step - set up your web.config to allow debugging

If you want F5 to work, and have visual studio debug the web service when you press it, the sharepoint web.config should be changed to allow debugging. To do that, you will need to open the web.config file for the virtual server you are using (in my case "http://portal" - which means the web.config is under "c:\Inetpub\wwwroot\wss\VirtualDirectories\portal80\web.config") and find the "<compilation>" tag, and set the attribute "debug" to true:




This is it!

If you didn't miss anything, you should be able now to press F5 and the web service will launch in the sharepoint context, with debugging in the visual studio! You can set breakpoints and debug the web service.







2 comments:

Anonymous said...

Nice Article...can I suggest something with WCF as well.
I can help you out with this if you like :-)
Cheers,
Aaron

Mark said...

After creating your web service you can Automatically Generate the SharePoint disco.aspx and wsdl.aspx files using the SPDev utility found here. Works great and takes only seconds. http://www.crsw.com/mark/Lists/Posts/Post.aspx?ID=57