Can you really execute native SQL Queries from SharePoint Web Services?
Microsoft SharePoint is great for building enterprise systems tying together various data sources. If the information you are looking for is in a SharePoint List or Document Library, it is straightforward to call the built-in Web Services to query or manipulate that data. Through custom Web Parts, you can run server-side code and easily retrieve data that lives outside SharePoint.
But what if you don’t have the access to run Server-Side
code? How can you get to the data that
lives in SQL Server from your client-side web application? You can’t call external XML web services
because of the Same Origin Policy Restrictions.
True, you can work around this if you have access to a JSONP web
service, and some browsers and servers are starting to support CORS to allow
limited cross-site access. But if you
don’t have access to the server, can’t control the browser environment and no
JSONP web services are available, you aren't out of luck. I'll show you how to get SharePoint to
execute the SQL Queries on your behalf and return the results to your web
browser. With a few tweaks, this same
technique can also be used to access arbitrary XML Web Services. In a later article, I'll expand this example to do just that.
A Word of Warning:
There is a downside to this approach. Since you will be using the SharePoint Server
as a proxy, the SQL logs will show the connection coming from the SharePoint
Server. Also, you must either pass in a
username/password with the web service call or use a guest SQL account. You will have to consider the security impact
of either approach carefully.
How does it work?
You will be using the WebPartPages.GetDataFromDataSourceControl
method. This method is intended to be used by
SharePoint Designer to render data during page design and is very sparsely
documented. According to MSDN, it takes
two string parameters: dscXml and contextUrl.
That is the extent of the MSDN documentation.
In order to make it easier to work with, I created a helper function
called SqlQuery that accepts a Server name, Database name, User name,
password, Sql Query and a callback function.
Pass in the proper parameters and your callback will be executed with
the results. You can paste the source
code below into the HTML source of a Content Editor Web Part on a page on your
SharePoint Server to test. Note, I am using JQuery to simplify the AJAX calls and form interaction.
Source Code:
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.10.2.min.js" type="text/javascript"></script>
<script type="text/javascript"> $(document).ready(function () {
//SqlQuery function - proxies a SQL Server call through sharepoint web services and executes your callback with the results.function SqlQuery(server, database, user, password, query, callback) { var soapMessage = ["<?xml version='1.0' encoding='utf-8'?>"]; soapMessage.push("<soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>"); soapMessage.push(" <soap:Body>"); soapMessage.push(" <GetDataFromDataSourceControl xmlns='http://microsoft.com/sharepoint/webpartpages'>"); soapMessage.push(" <dscXml><asp:SqlDataSource runat="server" __designer:commandsync="true" ProviderName="System.Data.SqlClient" ConnectionString=""); soapMessage.push("Data Source=" + server + ";User ID=" + user + ";Password=" + password + ";Initial Catalog=" + database + ";" "); soapMessage.push(" SelectCommand="" + query + " "/></dscXml>"); soapMessage.push(" <contextUrl></contextUrl>"); soapMessage.push(" </GetDataFromDataSourceControl>"); soapMessage.push(" </soap:Body>"); soapMessage.push("</soap:Envelope>"); var message = soapMessage.join(""); var thisSite = window.location.href.split(window.location.pathname).shift(); $.ajax({ url: thisSite + "/_vti_bin/webpartpages.asmx", beforeSend: function (xhr) { xhr.setRequestHeader("SOAPAction", "http://microsoft.com/sharepoint/webpartpages/GetDataFromDataSourceControl"); }, type: "POST", dataType: "xml", contentType: "text/xml; charset=\"utf-8\"", data: message, complete: function (xData, status) { if (status == "success") { var rows = $($.parseXML($(xData.responseXML).find("GetDataFromDataSourceControlResult").prop("text"))).find("Row"); callback(rows, status); } else { callback(xData, status); } } }); };//Set up some variables to interact with the form.var executeButton = $("#executeQuery"), serverInput = $("#server"), databaseInput = $("#database"), userNameInput = $("#userName"), passwordInput = $("#password"), queryInput = $("#query");
//When the user clicks the button, execute the query, parse and display the results.executeButton.click(function () { window.status = "calling SQL Query";
SqlQuery(serverInput.val(), databaseInput.val(), userNameInput.val(), passwordInput.val(), queryInput.val(), function (rows, status) {window.status = status; if (status == "success") { var output = ["<ol>"];
//rows is now a jquery object with the response from the sql queryrows.each(function (i, element) { var row = []; for (var j = 0; j < element.attributes.length; j++) { var attribute = element.attributes[j]; row.push("'" + attribute.nodeName + "'='" + attribute.value + "'"); } output.push("<li>" + row.join() + "</li>"); }); $("#output").html(output.join("") + "</ol>"); } else { $("#output").html($(rows.responseXML).text()); } }); }); }); </script>
<!-- And the form to let the user interact with the SqlQuery function. -->
<h1>
SQL Query Demo</h1>
<label for='userName'>
User Name:</label>
<input type='text' id='userName' value='SQLUser' />
<label for='password'>
Password:</label>
<input type='password' id='password' value='********' />
<label for='server'>
Server:</label>
<input type='text' id='server' value='SERVERNAME' />
<label for='database'>
Database:</label>
<input type='text' id='database' value='Food' />
<label for='query'>
Query:</label>
<textarea id='query' rows='5' cols='80'>SELECT TOP 10 [NDB_No] ,[Seq] ,[Amount] ,[Msre_Desc] ,[Gm_Wgt] FROM [Food].[dbo].[WEIGHT]</textarea>
<input type='button' id='executeQuery' value='Execute Query' />
<h1>
Output</h1>
<div id='output'>
</div>
No comments:
Post a Comment