If you have read my comments on the Writing Custom Web Service for SharePoint, Is it supported? (http://blog.libinuko.com/2011/02/16/sharepoint-writing-custom-web-service-for-sharepoint-is-it-supported/) ; you may have already created standard ASPNET web services. It is working, but with some limitation:
So, how can we write custom web service for SharePoint in supported mode?
Before we start, we have to understand SharePoint architecture and how does the processing works for web services. I take following picture from SharePoint Architecture in MSDN. It describe how SharePoint process our request. There is SPHttpApplication which has SPRequestModule and any additional ASP.NET Module; and before the request returned back to the user SPHttpHandler is doing the job.
If we dig into into the process on how SharePoint process request to web services in _vti_bin.
There are 3 scenarios of http request to the web services,
Every request will be processed by SPHttpHandler (SharePoint) and ScriptHandlerFactory (system.web.extension), but the SPHttpHandler will be selective only for Disco and Wsdl request.
On disco/wsdl request, SPHttpHandler will transfer the request to wsdisco.aspx or wswsdl.aspx using Server.Execute operation. This operation ensure that wsdisco.aspx/wswsdl.aspx is receiving same request object. wsDISCO.aspx or wsWSDL.aspx will then instantiate SharePoint Context object. Any *.aspx will be successfully instantiate SharePoint context object because they are managed by SPHttpApplication and hence it also impacted by SPVirtualPath provider from SharePoint which will activate path virtualization.
Next, wsDISCO.aspx will transfer the request to the <service>DISCO.aspx and wsWSDL.aspx will transfer to the <service>WSDL.aspx – using Server.Execute operation. So here we have seen 2 transfer operation. At the end, the result is correct WSDL/DISCO request. The correct WSDL/DISCO will point to the correct virtual path of the request. (Remember how do you create <service>disco.aspx / <service>wsdl.aspx)
When a consumer use the contract and tries to consume it. The SPHttpHandler will no longer intercept the request, but the normal ScriptHandlerFactory from System.Web.Extensions. However with the correct path in disco/wsdl, now the asmx now have the ability to look into current context from SharePoint. And hence you will be able to use SPContext.Current.Web in custom web services.
Create Visual Studio Solution
Create ASP.NET Web Services
Create SharePoint 2010 Project
01.
public
void
ProcessRequest(HttpContext context)
02.
{
03.
StringWriter sw1 =
new
StringWriter();
04.
// Original - cop spdisco.aspx
05.
context.Server.Execute(
"spdisco.disco.aspx"
, sw1);
06.
XmlDocument spdiscoXml =
XmlDocument();
07.
spdiscoXml.LoadXml(sw1.ToString());
08.
09.
var files = Directory.GetFiles(context.Server.MapPath(
""
),
"*.spdisco.aspx"
);
10.
foreach
(var file
in
files)
11.
12.
StringWriter sw2 =
13.
context.Server.Execute(System.IO.Path.GetFileName(file), sw2);
14.
15.
XmlDocument otherSPDiscoXml =
16.
otherSPDiscoXml.LoadXml(sw2.ToString());
17.
(XmlNode importedNode
otherSPDiscoXml.DocumentElement.ChildNodes)
18.
19.
spdiscoXml.DocumentElement.AppendChild(spdiscoXml.ImportNode(importedNode,
true
));
20.
}
21.
22.
23.
context.Response.Write(String.Format(
"<?xml version='1.0' encoding='utf-8' ?> {0}"
, spdiscoXml.InnerXml));
24.
Finally you can build and deploy the solution.
Fantastic article!!
Fantastic job, both images are showing exaclty estructure that a lot of us are looking for.