Recently someone asked me to troubleshoot the problem he had with the custom web service he created.
He followed the instructions from MSDN article "Walkthrough: Creating a Custom Web Service" and generated MyWebservice.asmx, MyWebservicedisco.aspx and MyWebservicewsdl.aspx files. He also made changes to contract reference and SOAP address in both disco.aspx and wsdl.aspx to provide the necessary redirection and maintain the URL virtualization.
Web service was deployed to 12\TEMPLATE\LAYOUTS in file system and can be viewed from URL http://<site>/_layouts/MyWebservice.asmx or http://<site>/<subsite>/_layouts/MyWebservice.asmx without any issues.
"Everything looks fine except..." - he said
At this stage I knew what the problem was and his description of the problem confirmed it.
"Everything looks fine except the web service function call returns an incorrect and unexpected result"
Yes, it could be the code logic errors. But I sticked to the one obvious mistake he has made. I told him that "Only deploy your custom web service files to 12\ISAPI (\_vti_bin\) folder unless you know what you are doing"
I have seen this problem many times before from different developers, third party vendor's and IT supports. They all have their own reasons (wrong reasons) for not to deploy their custom web service files to 12\ISAPI.
Why _vti_bin folder
Why all SharePoint OOTB web serivce files are in _vti_bin in the first place?
Because _vti_bin (12\ISAPI) virtual folder has been configured to serve requests differently compared to other virtual folders in the SharePoint site.
Every web service request made to this directory will be parsed by wswsdl.aspx and wsdisco.aspx files in 12\ISAPI. wswsdl.aspx and wsdisco.aspx files then find correspondence wsdl and disco information for web service request and output correct contract reference and SOAP address.
For example when client made a request to \_vti_bin\lists.asmx, wswsdl.aspx and wsdisco.aspx will parse it and look up for listswsdl.aspx and listsdisco.aspx respectively for wsdl and disco information.(modified version of auto-generated .wsdl .disco files)
Without this mechanism (web service request made to any other virtual folder on SharePoint site) the ASP.NET auto-generated disco and wsdl will be used. Since auto-generated disco and wsdl are unaware of the SharePoint service URL virtualization, results returned by web service become unreliable.
Simple test
1. Go to 12\ISAPI\ and copy lists.asmx, listsdisco.aspx and listswsdl.aspx to 12\TEMPLATE\LAYOUTS\
2. Create a sub-site under any site.
3. Browse lists web service from http://<site>/<sub-site>/_layouts/lists.asmx and http://<site>/<sub-site>/_vti_bin/lists.asmx
4. Open SharePoint Designer and Open sub-site. In Data Source Library > XML Web Services > Connect to a web service..
5. Set-up two web service connections to web services under _layouts/lists.asmx and _vti_bin/lists.asmx with operation GetListCollection.
6. Click on these two data connections and select Show Data.
7. Compare results.
You can easily see that _vti_bin/lists.asmx GetListCollection returns all lists under sub-site but _layouts/lists.asmx returns lists under root site. Imagine what would happen if you have different access permissions for each site level ? Or what if your web service logic is heavily dependent on the running site context?
Note
You can always check if your custom web service has maintained correct URL virutalization by viewing its Service Description.
Correct SOAP path.
Incorrect SOAP path.
If you are new to SharePoint or like to know more about how SharePoint handles HTTP requests (SPRequestModule) and SharePoint architecture/infrastructure . I recommand you to read these two articles from MSDN and TechNet
For WSS 3.0 (SharePoint Server 2007) - Inside Sharepoint Building Your SharePoint Infrastructure
For SharePoint Portal Server 2003 - Architectural Overview of Windows SharePoint Services