Miscellaneous Debris

Avner Kashtan's Frustrations and Exultations

May 2005 - Posts

CAML still has its humps.

The last few days I found myself wrestling quite a bit with CAML. The basic idea was to replace the standard "Create New Document" button in a document library with some logic - if no document template is specified for the doclib, replace the button with three different buttons - Create Word Document, Create Excel Spreadsheet and Create Powerpoint Presentation.

This involved several operations to the SCHEMA.XML - wrapping the proper buttons in an <IfEqual> tag to check if the TemplateUrl property has been set, rendering the proper buttons, and adding a new createNewDocument javascript function to instantiate the Sharepoint.OpenDocuments class and open the new document in its proper editor.

All this sharply highlighted the problems with CAML as it stands today, and reminded me of what I felt when I first saw ASP code - total and complete panic. I remember opening Visual InterDev and being completely baffled by the huge mess of HTML layout and virulent yellow ASP tags, all thrown haphazardly and confusingly. It's possible to write neat code in classic ASP that seperates content from layout, but it sure as hell ain't easy. I loved ASP.NET and the code-behind model, even though it still has many drawbacks. I think it's a great improvement and encourages readble, understandable code.

CAML, unfortunately, is still deep in the phase that Classic ASP was in. Instead of HTML layout with embedded server-side commands, we have the main CAML flow interspersed with <HTML> and CDATA blocks. The CAML syntax itself takes some getting used to - like polish notation, it's hard for someone used to the function(arg1, arg2) syntax to read the <Function><Arg1><Arg2></Function> style. But it's definitely doable. What makes it unreadable is the fact that in between the program flow and logic of the CAML code is the final rendered output, in full. So a simple condition such as:

if (TemplateUrl = "")
   RenderThreeButtons();
else
   RenderOneButton();

Becomes a huge mass of HTML code, all escaped with CDATA delimiters. It's hard to find what you're looking for even when it's right in front of you. This is due to several problems:

  1. Lack of inclusion support. CAML doesn't allow me to define arbitrary chunks of code and then include them later on in the code. This means that I can't abstract code, but have to have it fully written every time. It also means that I can't reuse code - in the example above I needed to replace the button rendering code TWICE - once in the AllItems view, once in the WebFolder view.
  2. Lack of proper development tools and standards. Some of this is mitigated by a good XML editor, but certainly not all of them. This includes:
    • A proper CAML editor that supports nested syntax highlighting - for the top-level CAML, the embedded HTML, and javascript/vbscript embedded in the HTML.
    • Support for code-folding, like Visual Studio's regions. The ability to view the CAML logic without the rendered HTML would clear up the mess immensely.
    • An ability to flatten a CAML structure into a templated rendered view. This means that the following structure (slightly snipped for clarity):
      <HTML>Owner of list </HTML> <ListProperty Property="ListName" /> <HTML>is </HTML> <ListProperty Property="Owner" />
      should be flattened into:
      "Owner of list <ListProperty Property=ListName> is <ListProperty Property=Owner>" - all HTML nodes normalized into a single string, with the intervening CAML nodes turned into placeholders.

This is, I suppose, a call for Microsoft to improve CAML support in future versions of Sharepoint - according to this post it will still be there in future versions, and several replies have echoed my problems.
Additionally, it's a call for community efforts to improve CAML usability. U2U have already released a tool to ease creation of CAML queries, but there is still a lot more to do.
I will try, of course, to add my own contributions to the community's struggle with CAML, but I can't promise anything - my personal pet projects tend to get neglected after a while. :)

Posted: May 31 2005, 11:23 AM by AvnerK | with 3 comment(s)
Filed under:
NT Networks, Delegation, Kerberos and Impersonation.

The issue of delegation of permissions over a network is one of the most confusing issues people run into, it seems. I don't think I've been to a project that involves web pages or services in some form that didn't run into it - people simply expect permissions to flow naturally between different network nodes. It's logical. It's intuitive. However, it doesn't work.

I've blogged about this and the Double-Hop problem before, but for neatness' sake and because I found myself explaining it three times today, I'll reiterate here, linking to various resources so I have somewhere to point people when they ask.

1) Larry Osterman explains about network delegation and its limitations.
2) MSDN Article on troubleshooting authentication and double-hop issues.
3) A blog entry of mine on using RevertToSelf() to bypass the double-hop problem.
4) Scott Allen's Roadmap to Delegation has links on how to set up Kerberos delegation.
5) If you have a username and password to authenticate with, you can use LogonUser to acquire a primary logon token that can be delegated, or use DuplicateTokenEx to turn an impersonation token to a Primary token. Here is some C# code, if you prefer.

Hope this helps clarify matters.
And remember - it's not a link blog if I also link to my own entries. :)

Posted: May 04 2005, 09:42 PM by AvnerK | with 2 comment(s)
Filed under:
Automatic population of web-parts in a New Web Part Page.

When a new sharepoint is created, the default page is automatically populated with several default web-parts as described in the ONET.XML and the <Modules> section. This is (relatively) well documented and clear.

However, if I create a new Web Part Page in an existing site (from the Create -> Web Part Page menu) based on one of the 9 templates in the DOCTEMP\SMARTPGS directory, it is also populated with a web-part - the TitleBarWebPart, specifically. I don't want this web-part added to my new pages, and I want others to be auto-added. However, I am yet to find where this population is defined - couldn't find it in any XML file under the site definition, and the actual code that creates the webpage is in owssvr.dll, hence not managed code and not browsable with the Reflector.

Anyone know where this is hiding?

Posted: May 02 2005, 12:05 PM by AvnerK | with 1 comment(s)
Filed under:
The Good, the Bad and the DataViewWebPart

Been wrestling lately with Sharepoint's DataViewWebPart (DVWP, from now on). I'm still pretty ambivalent about it.

Pros:

  • Easy to set up  - just add a list as a web-part, open it in Frontpage, right-click and Convert to XSLT.
  • Very customizable. I like XSLT. I can tweak it any way I want, generating custom rendering for my fields that would otherwise require me to write a custom web-part or a custom FieldType, which is too much hassle.
  • Presentation only. All the data-access logic is taken care of behind the scenes, and I have all the properties of my list items as XSLT parameters to play with as I choose.

Cons:

  • Not Portable. If I build a menu off of a list (as detailed here, excellent article), that DVWP is linked to the list's GUID. If I now want to copy that DVWP to a different subsite, I have to edit the hardcoded GUID or start messing with passing GUIDs as parameters and whatnot.
  • Messy, messy, messy. Tweaking unformatted XSLT in FP2003's Code view is a big, big pain - and a slip of the keyboard can make the DVWP unrenderable with no real explanation where you screwed up.
  • Maintainability is hell. Code is embedded directly in the page. If I want that DVWP on every page in my site (for the menu), I have to add it to every page manually, and update every change manually - even if I export it to a DWP file and just import to each page, I still need to update manually when things change. Anyway, it's a break from the content/presentation split that ASP.NET is pushing.

Right now I've given up on the DVWP approach and simply wrote a web-part in C# - it's portable, integrates well with my source-control-provider-of-choice, and the distinctions between unit of functionality and the page it resides in is clear.

Anyone have any supporting/opposing POVs? Any hints or tricks that make DVWPs more useful outside of the single-site scope?

Posted: May 01 2005, 11:46 AM by AvnerK | with 12 comment(s)
Filed under:
More Posts