Tuesday 29 April 2008

Considerations when referencing assemblies in your page layouts

This one came up in the office last week, and I thought it worthy of discussion. On one project we have, the page layouts use the ASP.Net Register directive to reference assemblies containing our controls. So we have several directives in the code similar to:

<%@ Register TagPrefix="psw" Namespace="OurCompany.OurClient.SharePoint.WebControls" Assembly="Parity.SharePoint.WebControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=00000000000000" %>


These serve the purpose of telling the page layout about our controls assembly, and ensuring the designer can supply us with Intellisense for the controls and their members.


The question which then arises is "what happens when we update the shared assembly and we want to increment the version number? Surely we don't have to update and republish all our page layouts?" There are a couple of answers to this:



  • we could use assembly redirects in application config to avoid changing the page layouts. These entries would then tell .Net to load (for example) version 2.0.0.0 of our assembly whenever version 1.0.0.0 is requested. This would work, but would mean that we don't get Intellisense for any new/changed members added in subsequent assembly versions.

  • we could also avoid referencing common assemblies in this way completely, and centralize the reference in web.config instead


So instead of having an entry in each page layout, the 'Pages' section of web.config (in .Net 2.0 and upwards) allows us to reference assemblies containing controls in one central place, meaning any changes to the assembly name are simple to implement:



<pages>
<controls>
<add tagPrefix="psw" namespace="OurCompany.OurClient.SharePoint.WebControls"
assembly="OurCompany.OurClient.SharePoint.WebControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=00000000000000" />
<!-- also works with short assembly name -->
<!--
<add tagPrefix="psw" namespace="OurCompany.OurClient.SharePoint.WebControls"
assembly="OurCompany.OurClient.SharePoint.WebControls" />
-->
</controls>
</pages>


[Side note] - as I specify in the comment, it is possible to reference the assembly with the short name, but shops with a defined versioning strategy will want to avoid this since it's then not possible to have side-by-side versions of assemblies, one of the fundamental forward steps introduced with .Net.


However, it's not all clear cut. Unfortunately SPD isn't clever enough to resolve the assembly reference in web.config to provide Intellisense. I initially thought it was, but alas closing and re-opening shows that in fact something was cached. Visual Studio is sufficiently aware (if we were in a pure .Net scenario), but not SPD.


So it's a trade-off as far as I can see - either have the @Register directive in your page layout (with version numbers in it), or reference in web.config but lose Intellisense.


I wondered if it was possible to use the short assembly name in the @Register directive, but supply a 4 part assembly name in web.config for use at runtime. Unfortunately this doesn't work since .Net sees it as an ambiguous registration. So if you want to keep assembly version numbers out of your page layouts but keep Intellisense, one strategy could be to remove the @Register directives as part of your release process.


Or as an alternative final thought - which is more important, Intellisense during development or minimising running into this problem at release time? For my money, losing the inconvenience of Intellisense in SPD for controls in is a minor hassle, so referencing assemblies in web.config is a better approach.

3 comments:

Anonymous said...

Yeah, I came to this same conclusion because of the Telerik RadEditor for MOSS. When they release a new version, they increment up. Their documentation says to put the reference in the page...

Guess if you need intellisence at design-time, you can put the Register tag in temporarily. But that has holes.

BTW - you've got some killer posts. I come back to your stuff alot, and your CT as Feature post is one of my all time faves (geeky grin...)

-Rich

Unknown said...

If the assemblies that you want to change are in the GAC, have you tried using a publisher policy (i.e. a DLL with only the redirect info in the GAC) ?
This should work for all applications using the DLL, potentially also for the code running on the server that handles SPD requests. I am not sure because I have not tried it.
-- Jean-Marie

Chris O'Brien said...

@Timores,

Publisher Policy is an alternative to assembly binding redirects (i.e. version redirects) in application config, but isn't a substitute for the directive which actually links the page/app with the assembly. So you'd still need to use one of the approaches discussed in this article.

In terms of using Publisher Policy to override which assembly gets loaded by the runtime, I see it primarily as a tool for packaged software vendors only. The technique basically provides an assembly redirect without having to ask the admin to manually modify their web.config correctly - so looks far more professional for the vendor and probably results in less support calls. But I guess could work in other scenarios if you can live with having to recompile (over simply modifying a config file) just to change the instruction. Interesting thought though.

Cheers,

C.