SharePoint Experts, Information Architects, Expert Witness

We provide consulting in a broad array of business and technology from architecture to design to deployment of global systems with a focus on surfacing data in the enterprise. Specialists in Microsoft, we are a premier provider of SharePoint Expertise (including 2016 and Office 365). We also provide Expert Witness/Legal Expert in eDiscovery, source discovery, patent infringement, piracy and more! We also have established SICG DLDS s.a. - our counterpart in Costa Rica that specializes in water systems (http://www.crwatersolutions.com) - Contact me direct: david_sterling@sterling-consulting.com or call 704-873-8846 x704.

Search This Blog

Sunday, November 7, 2010

Debugging Silverlight and SharePoint

If you are like me, you've had lots of fun trying to debug Silverlight projects combined with WCF and SharePoint. The problem is that unless Silverlight is 'hosted' from the SharePoint site itself, you cannot debug it if you directly access the SharePoint API in the WCF code (it fails because you are not authenticated, alal the double hop issue). Errors include "No Cross Domain policy found" or failing on returning data (the Async call fails).

After much screwing around, I finally came up with a short way to do it reliably:

SIDE NOTE: Look into the Winsmarts tool for enabling Silverlight - I didn't need it for this but have used in the past - see : http://spwcfsupport.codeplex.com/ - as it turns out, that is only required for WCF. I found that using SharePoint web services gives you a big bang for the buck; in most cases you don't have to worry about authentication (users usually have the rights needed to run SP Web services) and you get great access (not as much as the API granted) to SharePoint lists, files, etc.

1) First off, create a new folder in the SharePoint site - i.e. c:\inetpub\wwwroot\wss\VirtualDirectories\70 (I'm using 70 as the sample port - this is whatever port you are using); name is not important but I use "SilverLtApps" (you can alternately use a SharePoint library but for debug, that requires you to upload changes each time). In practice, I've started out using the directory but when complete, simply deleted the direcotry and created a library of the same name (thus not having to change the URL in the content editor web part as you will see below).

2) Next, create your Silverlight Application using the standard setup (sellect Host the Silverlight application in a new Web Site).

3) After the project loads, create a new HTML file in the Silverlight that does a redirect to the SharePoint Site where Silverlight is to be used:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<meta HTTP-EQUIV="REFRESH" content="0; url=http://myspsite:70/Pages/default.aspx">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>Untitled Page</title>
</head>
<body>
</body>
</html>
4) Next, right click on the Solution and Set Startup Projects. Change the Startup Project to 'Single startup project' to the Silverlight project (not the .Web project).

5) Next, right click on the Silverlight Project and select Properties; on the Debug tab under Start Action, click Specific Page and select the HTML page you created in step 3. ALTERNATELY - Right click on the HTML file and select "Set as Start page".

6) Still in properties, click the Build tab - set the Output path to the folder created in Step 1.

7) Now create a clientaccesspolicy.xml file for the site - this can be generic (wide open) as so:

<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*">
        <domain url="*" />
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true" />
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

OR You can set it specific to the domain/site:

<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*">
        <domain url="http://MySPSite" />
      </allow-from>
      <allow-from http-request-headers="SOAPAction">
        <domain uri="http://MySPSite" />
        <domain uri="https://MySPSite" />
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true" />
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>
If you want to use a CrossDomain.xml file as well (this is a fall back to Adobe Flash time), it looks like this:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-http-request-headers-from domain="*" headers="*" />
</cross-domain-policy>
8) VERY IMPORTANT: Using SharePoint Designer, open the site and upload the file(s) to the ROOT of the site - you can add the files to the actual file root as well but this depends on if you have access to the file system or not - if you can use Designer, do so.

9) Next, upload the Silverlight.js file that is included in the .WEB project (or copy to the root folder if you have access).

10) If you hit F5 or Debug > Start Debugging, the site should come up as expected.

11) Now, to test your Silverlight, edit the page in SharePoint and add a Content Editor Web Part - in the Source simply put in the required settings for the control (note that the Script inclusion is optional but I generally use it - it also allows you to point to the Silverlight.js file if you have to upload it to a SharePoint Library instead of using the file system):

    <script type="text/javascript" src="Silverlight.js"></script>
    <script type="text/javascript">
        function onSilverlightError(sender, args) {
            var appSource = "";
            if (sender != null && sender != 0) {
              appSource = sender.getHost().Source;
            }
           
            var errorType = args.ErrorType;
            var iErrorCode = args.ErrorCode;
            if (errorType == "ImageError" || errorType == "MediaError") {
              return;
            }
            var errMsg = "Unhandled Error in Silverlight Application " +  appSource + "\n" ;
            errMsg += "Code: "+ iErrorCode + "    \n";
            errMsg += "Category: " + errorType + "       \n";
            errMsg += "Message: " + args.ErrorMessage + "     \n";
            if (errorType == "ParserError") {
                errMsg += "File: " + args.xamlFile + "     \n";
                errMsg += "Line: " + args.lineNumber + "     \n";
                errMsg += "Position: " + args.charPosition + "     \n";
            }
            else if (errorType == "RuntimeError") {          
                if (args.lineNumber != 0) {
                    errMsg += "Line: " + args.lineNumber + "     \n";
                    errMsg += "Position: " +  args.charPosition + "     \n";
                }
                errMsg += "MethodName: " + args.methodName + "     \n";
            }
            throw new Error(errMsg);
        }
    </script>

    <div id="silverlightControlHost">
        <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="800" height="320">
    <param name="source" value="/SilverLtApps/TestSPService.xap"/>
    <param name="onError" value="onSilverlightError" />
    <param name="background" value="white" />
    <param name="minRuntimeVersion" value="3.0.40624.0" />
    <param name="autoUpgrade" value="true" />

    <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40624.0" style="text-decoration:none">
      <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style:none"/>
    </a>
     </object><iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe></div>

Note the location of the .XAP file points to the relative folder created in step 1 - be aware that if you are using subsites, the url may need to be the full URL less the http://<site> part - example: http://site/subsite/subsite/ would be /subsite/subsite/. Close the content editor part and save/publish the page.

12) Add a button or some code and set a few brakepoints in your Silverlight app and happy debugging!!!!