Tool vs. Product

One of the things that makes ASP.NET great is it’s “no black box” approach. Rob Howard describes the approach this way: “Provide customers with the ability to replace/customize/extend the core product” [ASP.NET Overview, Slide 25]. You can see this approach all over ASP.NET. For example, ASP.NET ships with three built-in authentication modules: Windows, Forms and Passport. Don’t like those? Want something custom? Fine, write a module that handles the AuthenticateRequest event and handle authentication however you want. Heck, if you’re doing a one-off solution, you can even skip the module and stick the code in Global.asax.

As is probably apparent to anyone reading this weblog, I’ve been playing around with Windows SharePoint Services quite a bit recently. WSS seems to be made up of three distinct layers:

You would think these would be mostly independent, but they’re not. For example, the WSS docs describe how you can add a new field type to the default templates that ship with WSS. However, there’s a field type enumeration that’s part of the WSS object model. Obviously, adding a custom field to the template does not change the enumeration. What’s interesting is that if you follow the instructions to add a new field type and then add that field to a list template, you can create a list instance from that template that features the field type you defined. But if you want to modify the column with the custom field type, the WSS site admin pages (i.e. under the _layout vdir) has no idea about the new field type. Likewise, you can’t add your new field type to an existing or custom list since the WSS site admin pages are coded against the object model and the default enumeration of field types. This makes it very hard to black box replace/customize/extend the core WSS product due to it’s tightly coupled nature.

Of course, one of the reasons that ASP.NET has been more successful at extensibility is because it is a tool and WSS is a product. There is no out-of-the-box experience with ASP.NET for end users the way that WSS has. Is shipping a product harder that shipping a tool? Is targeting end users harder than targeting developers? I would think the answer to both of these questions is yes. In the end, the WSS team had to ship something that works OOB, even if that means building something that’s more tightly coupled and thus harder to extend. I hope that over future releases, WSS continues to improve (certainly v2 is a huge improvement over v1) and that it becomes easier to replace/customize/extend the core product.

UPDATE – Of course, it’s Rob Howard not Ron Howard. Rob – Great job on ASP.NET. Ron – Great job on Apollo 13.

Add Web Reference Bugaboo

While VS.NET’s whole “Add Web Reference” concept is cool, it utterly falls down in the face of multiple services exposed by the same back end. WSS exposes a multitude of web services. But VS.NET doesn’t have any way to specify that multiple web services should all be in the same namespace. So you end up each service in it’s own namespace like server1, server2, etc.

Luckily, WSDL.exe doesn’t have this problem. And VS.NET 2003 support custom build steps so it’s pretty easy to execute WSDL.exe as part of a standard build. So it’s only a minor annoyance.

I wonder if you could build your own custom Add Web Reference system via VSIP? Probably not worth the trouble. But it does make me curious – is anyone looking at using VSIP on their shareware/freeware tool to integrate it more tightly into the VS.NET shell? I see Scott Hanselman has a great list of potentials. (He even included my SccSwitch utility – I’m honored!)

Don on SOA

I’m sure I’m the last blogger to watch Don’s MSDN TVepisodes on SOA. But if I’m not, go watch them right now. I especially like Don’s comments on XML Schema. They echo my own, but are much more coherent. Plus, it makes me glad I’ve never swapped out a CPU.

More on WSS Web Services

BTW, there’s another good reason I’m not posting the code: RTM of WSS may allow you to enable hyperlinking in multi-line text fields via the UI. If that’s the case, this code becomes demoware, instead of a utility.

WSS Web Services

Not much blogging of late. Trend likely to continue. Details at 11.

However, I did make an interesting discovery about Windows SharePoint Services I wanted to share. Obviously, I’ve been thinking WSS in terms of blogging (hence the project to expose RSS from WSS). However, I’ve been frustrated by what should be a simple little thing. WSS includes a rich text editor that enables me to write content that’s bold, italics, colored, fonted, sized, indented, bulleted, etc. However, until today, I couldn’t figure out how to do hyperlinks. WSS will automagically render a url as a hyperlink. But there was no way to build an anchor tag hyperlink, so your forced to embed urls directly in the text. I didn’t like that, so I set about trying to fix it. Turns out to not be a big deal.

It turns out that the SPFieldMultiLine class supports a property named AllowHyperlinks. If you can flip this bit, the rich text editor in WSS will suddenly get a Hyperlink button and enable the creation of anchor tag hyperlinks. Unfortunately, there doesn’t appear to be any way to flip this bit via the existing UI as of B2TR (no, even though I work at MSFT, I don’t have the RTM bits yet). So I built a web app (as per these instructions) that programmatically flipped that bit via the WSS object model. I also could have done it via a console or windows form app, again via the WSS object model. However, that object model only works on the WSS machine itself – there’s no concept of remoting via the OM. But WSS does expose much of its functionality remotely via web services, including a List web service.

The WSS Web Service interface (WSI?) is a little funky, but I munged up a little utility to flip the AllowHyperlinks property programmatically. The inputs and outputs of the service are XML (actually an XML grammar called CAML) so the inputs and outputs of the service proxy are XmlNodes. The DOM is an ugly way to build XML documents, so I used Chris Lovett’s XmlNodeWriter utility class to get an XmlWriter interface on my XmlDocument. Other than that, the code was pretty straight forward. In pseudo-code, it looks like:

  1. Call ListServiceProxy.GetList(listName) to get the definition of the list in CAML
  2. Use XPath to find the element that represents the field I want to change (//sp:Field[@DisplayName='fieldName'])
  3. Create a new XmlDocument that contains a single method block for the field I want to change (see docs for UpdateList for explanation). Write the CAML representation of the field into the method block. This CAML is identical to the CAML from the previous step, except that I’ve added AllowHyperlinks=”TRUE’
  4. Call ListServiceProxy.UpdateList, passing in the the constructed XmlDocument as the updateFields parameter.
  5. UpdateList returns an XmlNode that contains the result of the update. XPath query via method block ID to determine if the update succeeded or failed.

I will post the code after I clean it up a bit. However, I don’t know when that will be.