Wednesday, 9 November 2011

Error executing child request for ChartImg.axd when Rendering a Custom Charting WebPart in SharePoint 2010

 I deployed a custom SharePoint 2010 web part today that uses the Microsoft Chart Controls For ASP.NET 3.5. However, after deployment, I began receiving the following exception when it rendered within an IIS 7 Hosted site (SharePoint 2010 running Windows 7)

Error executing child request for ChartImg.axd

I already had the handler entries set up the same as seen in the code samples. The main problem is that most web.config examples and the official samples don't include the required web.config entries for the ChartImg.axd httphandler (so that they operate correctly in IIS 7 and above).

Windows 7 and Windows Server 2008 use IIS 7 so using the httpHandlers section won’t work like it does in previous versions of IIS – you must instead add an item to the handlers config section of the system.webserver node, like so:

<system.webServer>
    <handlers>
      <add name="ChartImageHandler" preCondition="integratedMode" verb="GET,HEAD,POST" path="ChartImg.axd" type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </handlers>
  </system.webServer>

You should also make sure that you are using the POST value in the verb attribute like so:

verb="GET,HEAD,POST".

Once your web application is configured correctly, you should now be able to go to http://SITENAME:PORTNUMBER/Charting.axd and receive a blank screen without any errors. This shows that the charting httphandler is now operational.

Full example of web.config with correct Chart handler entries:
<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="ChartImageHandler" value="storage=file;timeout=20;dir=c:\TempImageFiles\;" />
  </appSettings>
  <connectionStrings/>
  <system.web>
    <pages>
      <controls>
        <add tagPrefix="asp" namespace="System.Web.UI.DataVisualization.Charting"
        assembly="System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      </controls>
    </pages>
    <compilation debug="true">
      <assemblies>
        <add assembly="System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add assembly="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
      </assemblies>
    </compilation>
    <httpHandlers>
      <add path="ChartImg.axd" verb="GET,HEAD,POST" type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false"/>
    </httpHandlers>
  </system.web>
  <system.webServer>
    <handlers>
      <add name="ChartImageHandler" preCondition="integratedMode" verb="GET,HEAD,POST" path="ChartImg.axd" type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </handlers>
  </system.webServer>
</configuration>

Tuesday, 1 November 2011

FIX - I'm using the ASP.NET 3.5 Charting Controls in SharePoint 2010 to render charts - but the charts don't print out in Internet Explorer (they're fine in Firefox). Why?

Internet Explorer seems to have to re-download the images generated by the charting control when printing them - if the Chart Image Handler (ChartImg.axd) setting is at deleteAfterServicing=true, then the subsequent request to render the chart with that same GUID (for printing) will fail.

To resolve, you can change the setting on your web.config for "deleteAfterServicing" to false so it doesn't automatically remove the requested image each run.

<add key="ChartImageHandler" value="storage=file;timeout=20;dir=c:\inetpub\YourApplicationName\temp\;deleteAfterServicing=false">

It is also best to have a cleanup job on this directory depending on your space requirements and number of chart requests made to your site.

DDK

Monday, 31 October 2011

Specifying Sort Order When Querying the SharePoint List Web Service with CAML and jQuery (via Lists.asmx)

I had a couple of problems today with specifying the sort order of data returned from a CAML query via a jQuery AJAX call. It seemed that no matter what setting I put in, it always seemed to return an unordered resultset.

I resolved the problem by looking at the requests in Fiddler that were produced by U2U CAML query Builder. The main problem was that I wasn't correctly wrapping the CAML "Query" node in a parent "query" node. Now you only have to do this when you're doing jQuery calls directly against web services - and are shielded from this somewhat when you are calling the SharePoint client object model (for details you can look here http://msdn.microsoft.com/en-us/library/gg701783.aspx). Why I'm using web service calls directly is a discussion for another time (and I wouldn't automatically turn to using it as a preference - as described here http://msdn.microsoft.com/en-us/library/ee539764.aspx) - but I'll say for now that it is for consistency with existing code (The client object model is using the web services underneath as well, but has batching facilities). See below for an example of a jQuery call which does sorting that worked for me. U2U CAML Query builder will also give you the valid internal name for the field.

var errorMessage;
  //Add order by if variable is set in other part of page (so it can be switched on or off on a page-by-page basis.
  if (typeof missingCategoryDisplayMode_IsOnline != 'undefined' && missingCategoryDisplayMode_IsOnline == true  ) //Variable should be set by another content query web part on page
  {
   var orderBy = "\
       \
      ";
  }

try
  {
   var contentCategoryCAML = "<?xml version='1.0' encoding='utf-8'?> \
        <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/'><soap:Body> \
           <GetListItems xmlns='http://schemas.microsoft.com/sharepoint/soap/'> \
           <listName>Content Categories</listName> \
           <query>\
           <Query xmlns=''>\
           " + orderBy +
           "</Query>\
           </query>\
           <viewFields>\
           <ViewFields xmlns='' />\
           </viewFields>\
           <queryOptions>\
           <QueryOptions xmlns=''/> \
           </queryOptions></GetListItems> \
         </soap:Body></soap:Envelope>";
   $.ajax({
    url: listUrl,
    type: "POST",
    dataType: "xml",
    data: contentCategoryCAML,
    complete: ContentCategoryResult,
    contentType: "text/xml; charset=\"utf-8\""
   });
  }
  catch (ex)
  {
   displayError("There was an error retrieving data from the Content Categories list. Please see IT support for assistance.");
   return;
  }
  
  function ContentCategoryResult(xData, status)
  {
   $(xData.responseXML).find("z\\:row").each(function () 
   {           
      var Title = $(this).attr("ows_LinkTitle");           
      arrContentCat.push(Title);  //Adding the results in an array
   });
  }


This adds items to an array that are used later for rendering. I needed a different sort order based on the page - so this was done using a seperate javascript file that is placed into a Content Editor Web Part on pages to set the sort order variable.

I also use the SharePoint client model to programatically determine the site collection path and to ensure that the list web service of the current site collection root is used (you can't determine that just by the url):

function MenuInitialize()
 {
     var clientContext = new SP.ClientContext();
        var siteColl = clientContext.get_site();
        myweb = siteColl.get_rootWeb();
        clientContext.load(myweb);
        /* Execute async required*/
        clientContext.executeQueryAsync(Function.createDelegate(this, executeRequestAndRender), Function.createDelegate(this, getFailed));
 }
 
 function executeRequestAndRender() {
  var siteCollectionUrl = myweb.get_serverRelativeUrl();
  var listWebServiceUrl = siteCollectionUrl + "/_vti_bin/lists.asmx"
  //When at the root, siteCollectionUrl is '/', but other sites have /sitecollection/sites
  listWebServiceUrl = listWebServiceUrl.replace('//', '/');
  /* When complete, we can render requests */
  RenderMenu_ContentCategoryList(listWebServiceUrl);
 }


For the SharePoint Client Object model to work of course, you should always tell Script on demand (SOD) to process the code that references the SP client object model only when the SP.js file has been loaded:

$(document).ready(function()
{
 /*Ensure that the Sp.js is loaded (using Script on Demand (SOD) SharePoint library) so the client object model functions correctly */
 SP.SOD.executeOrDelayUntilScriptLoaded(MenuInitialize, 'SP.js');

DDK

Tuesday, 18 October 2011

SharePoint 2010 - My jQuery Scripts are Broken on the Publishing Portal Thumbnails.aspx Page. All other pages are fine.

I've had this problem many times in ASP.NET but never in SharePoint 2010. Today, one of our jQuery script implementations was failing on just a couple of the SharePoint pages - in particular the Publishing Portal Thumbnails Page.

All the jQuery objects were returning null values even though it worked for all the pages in the SharePoint site. The problem is back to that golden oldie of the jQuery object shortcut of $ conflicting with the Microsoft AJAX framework. Both frameworks use the $ as an object shortcut and so this causes problems. I almost felt nostalgic getting this exception :o).

Why does it only happen on a couple of pages in SharePoint 2010? They are the only ones which have script references to the MS AJAX javascript libraries.

There are ways around this using aliases (via the jQuery.noConflict() command) - but the simplest way is to just use jQuery as a best practice when working within SharePoint 2010 -  with a find and replace of "$(" with "jQuery(" as needed. This fixed the problem.

Too easy!

DDK

Wednesday, 12 October 2011

CSS Positioning Refresher - Relative vs Absolute vs Static vs Fixed - SharePoint 2010 Branding

My current client is a media company who wanted branding done as part of a SharePoint 2010 Portal implementation project. One problem arose because their standard operating environment uses Internet Explorer 7. Our IE 7 specific issues arose because of IE7's position behaviour and it's interaction with a dynamic pop-down DIV that we were injecting with jQuery.

In IE7 (not in IE8+ or Firefox), our whole content div in SharePoint was getting pushed down by our hidden div used as part of the pop-down menu. Turns out our resolution to fix this IE 7 was to make our hidden div to use position:absolute rather than relative/static.

The critical difference between relative and absolute in particular is not how it changes the behaviour of the div - but rather how it affects the flow of OTHER elements on the page. This is particularly important when you are injecting elements into SharePoint with jQuery. The best explanation of CSS positioning (and how it affects other html elements) I've found is here:

http://www.w3schools.com/css/css_positioning.asp


RELATIVE: The content of relatively positioned elements can be moved and overlap other elements, but the reserved space for the element is still preserved in the normal flow.
ABSOLUTE:
Absolutely positioned elements are removed from the normal flow. The document and other elements behave like the absolutely positioned element does not exist (Yes! this is what we really want)

This still doesn't explain the rendering difference in IE7 vs IE8 vs Firefox apart from the fact that other browsers seem to be more forgiving when specifying your CSS positioning compared to IE7 (in Standards mode).

DDK

Wednesday, 5 October 2011

SharePont 2010 - Why is Inline Editing not working even when enabled for the current view?

One of my colleagues at Oakton had issues in that a SharePoint 2010 Custom List wasn't allowing editing inline.

Even when modifying the view and enabling the "Allow Inline" editing property of the list view - no errors, it just didn't work and the Edit icon just opened the full blown SharePoint modal dialog box as usual.



The problem was that the list view must use the Default Style for Inline editing to work.



DDK

Thursday, 8 September 2011

Fix - My SonicWall Client Keeps Prompting for a Phone Book Entry even though I'm already connected

When connecting via Telstra Mobile Broadband and attempting to connect to a SonicWall VPN with the SonicWall client, I kept getting prompted for a Dialup Phone Book entry mutliple times. Every time I connected (though not when using normal wireless from home), I had to keep attempting a connection until the username and password prompt displayed.

The fix for this problem is to ensure that the "LAN Only" drop down is selected:
1) Open the SonicWall VPN Global Client
2) Click on Peers and Choose the correct connection; Click Edit
3) Under Interface Selection, Choose "LAN Only" rather than "Automatic" in the drop down list.


Tuesday, 6 September 2011

Fix - Duet Enterprise/SharePoint 2010 Exception - "System.ServiceModel.QuotaExceededException: The size necessary to buffer the XML content exceeded the buffer quota."

When attempting to establish communications between SAP and SharePoint (using the Duet Enterprise Claims provider) today at a new client, I encountered the following exception in SharePoint (as per the ULS logs):

InnerException 1: System.ServiceModel.QuotaExceededException: The size necessary to buffer the XML content exceeded the buffer quota. Server stack trace:

at System.ServiceModel.Channels.BufferedOutputStream.WriteCore(Byte[] buffer, Int32 offset, Int32 size)
at System.Xml.XmlStreamNodeWriter.FlushBuffer()
at System.Xml.XmlBinaryNodeWriter.FlushBuffer()
at System.Xml.XmlStreamNodeWriter.GetBuffer(Int32 count, Int32& offset)
at System.Xml.XmlBinaryNodeWriter.UnsafeWriteText(Char* chars, Int32 charCount)
at System.Xml.XmlBinaryNodeWriter.WriteText(Char[] chars, Int32 offset, Int32 count)
at System.Xml.XmlBaseWriter.WriteChars(Char[] chars, Int32 offset, Int32 count)
at System.Xml.XmlBinaryWriter.WriteTextNode(XmlDictionaryReader reader, Boolean attribute)
at System.Xml.XmlDictionaryWriter.WriteNode(XmlDictionaryReader reader, Boolean defattr)
at System.ServiceModel.Channels.ReceivedFault.CreateFault12Driver(XmlDictionaryReader reader, Int32 maxBufferSize, EnvelopeVersion version)
at System.ServiceModel.Channels.MessageFault.CreateFault(Message message, Int32 maxBufferSize)
at System.ServiceModel.Channels.SecurityChannelFactory`1.ClientSecurityChannel`1.TryGetSecurityFaultException(Message faultMessage, Exception& faultException)
at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.ProcessReply(Message reply, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) Exception rethrown
at [0]:
at Microsoft.SharePoint.BusinessData.SystemSpecific.Wcf.WcfSystemUtility.Execute(Object[] args)
at Microsoft.SharePoint.BusinessData.SystemSpecific.Wcf.WcfSystemUtility.ExecuteStatic(IMethodInstance methodInstance, ILobSystemInstance lobSystemInstance, Object[] args, IExecutionContext context)
at Microsoft.SharePoint.BusinessData.Runtime.DataClassRuntime.ExecuteInternalWithAuthNFailureRetry(ISystemUtility systemUtility, IMethodInstance methodInstanceToExecute, IMethod methodToExecute, ILobSystemInstance lobSystemInstance, ILobSystem lobSystem, IParameterCollection nonReturnParameters, Object[] overrideArgs)
at Microsoft.SharePoint.BusinessData.Runtime.DataClassRuntime.ExecuteInternal(IDataClass thisDataClass, ILobSystemInstance lobSystemInstance, ILobSystem lobSystem, IMethodInstance methodInstanceToExecute, IMethod methodToExecute, IParameterCollection nonReturnParameters, Object[]& overrideArgs)

I also received the following exception immediately after the above exception:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ServiceModel.QuotaExceededException: The size necessary to buffer the XML content exceeded the buffer quota. Server stack trace:

at System.ServiceModel.Channels.BufferedOutputStream.WriteCore(Byte[] buffer, Int32 offset, Int32 size)
at System.Xml.XmlStreamNodeWriter.FlushBuffer()
at System.Xml.XmlBinaryNodeWriter.FlushBuffer()
at System.Xml.XmlStreamNodeWriter.GetBuffer(Int32 count, Int32& offset)
at System.Xml.XmlBinaryNodeWriter.UnsafeWriteText(Char* chars, Int32 charCount)
at System.Xml.XmlBinaryNodeWriter.WriteText(Char[] chars, Int32 offset, Int32 count)
at System.Xml.XmlBaseWriter.WriteChars(Char[] chars, Int32 offset, Int32 count)
at System.Xml.XmlBinaryWriter.WriteTextNode(XmlDictionaryReader reader, Boolean attribute)
at System.Xml.XmlDictionaryWriter.WriteNode(XmlDictionaryReader reader, Boolean defattr)
at System.ServiceModel.Channels.ReceivedFault.CreateFault12Driver(XmlDictionaryReader reader, Int32 maxBufferSize, EnvelopeVersion version)
at System.ServiceModel.Channels.MessageFault.CreateFault(Message message, Int32 maxBufferSize)
at System.ServiceModel.Channels.SecurityChannelFactory`1.ClientSecurityChannel`1.TryGetSecurityFaultException(Message faultMessage, Exception& faultException)
at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.ProcessReply(Message reply, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) Exception rethrown
at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at BCSServiceProxy.IWXManageCustomerIn.FindCustomerByElements(FindCustomerByElementsRequest request)
at BCSServiceProxy.WXManageCustomerInClient.BCSServiceProxy.IWXManageCustomerIn.FindCustomerByElements(FindCustomerByElementsRequest request)
at BCSServiceProxy.WXManageCustomerInClient.FindCustomerByElements(BPCCustGetAll BPCCustGetAll) -
-- End of inner exception stack trace ---
at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at Microsoft.SharePoint.BusinessData.SystemSpecific.Wcf.WcfSystemUtility.Execute(Object[] args)

With my experiences with SAP, buffer overflows normally indicate that a large Java stack trace is coming back from SAP and it overloads the WCF client buffer which is expecting a normal SOAP response.

To see the real exception, I tried to use Wireshark (http://www.wireshark.org/)- but our setup had (not by choice) Netweaver and SharePoint on the same box - and Wireshark cannot listen to localhost traffic.

As usual, the Fiddler Tool HTTP proxy (http://www.fiddler2.com/fiddler2/) came to the rescue- as it can actually listen to traffic occurring between applications on the same machine. When running Fiddler and listening to the https traffic, it popped up with an exception regarding certificate errors:

Session #24: The remote server (ausyd-a-sh1) presented a certificate that did not validate, due to RemoteCertificateChainErrors.

SUBJECT: CN=ausyd-a-sh1, OU=I0020310622, OU=SAP Web AS, O=SAP Trust Community, C=DE
ISSUER: CN=ausyd-a-sh1, OU=I0020310622, OU=SAP Web AS, O=SAP Trust Community, C=DE
EXPIRES: 1/01/2038 11:00:01 AM
I went to the server url in Internet Explorer and sure enough there was a certificate error occurring when going to the URL of the SAP server - at https://ausyd-a-sh1:8001/


Basically this exception was occurring because the SAP SSL certificate was not in the Trusted Root Certification Authorities store in Windows. To import it, I just opened mmc at a command prompt and added the certificates Snap-In (via File - Add/Remove Snap In... - for the Local Computer.

In Certificates (Local Computer), I went to Trusted Root Certification Authorities - Certificates and Imported the SAP Certificate in.

However, I kept getting the same exception. On closer inspection, the thumbprint of the SharePoint Security Token Service (STS) certificate was not the same as what had been imported into SAP - this was becuase SharePoint had been reinstalled - which changes the SharePoint STS certificate (i.e. SharePoint STS certificates are install specific).

I then received the following Exception - which was related to user mappings in SAP:

An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail


To resolve this last exception:
1) We made sure SharePoint:: was used to prefix the name in SAP (in the VUSEREXITID table) - this prefix would normally be added through the Duet Active Directory user import job (specific to Duet Enterprise) - but we don't have AD in our environment.
2) We then updated the STS certificate in the SAP Certificate store (using SAP transaction /nstrust)
3) Used the /nsaml2 transaction to update the certificate used there as well.

This resolved all our SAP to SharePoint communication issues.

DDK