Koen about .Net

May 5, 2011

Converting User Controls into Custom Controls

Filed under: Development — Tags: , — koenwillemse @ 16:30

In the project I’ve been working on, we had to deal with a design agency, which creates a lot of html markup, which must stay exactly the way it was created by them be. Next to that, the product should eventually work in SharePoint, so we have to use WebForms :-(. I’ve been developing a framework which will be used which looks very similar to the FrontController pattern, however there are a few differences, for instance, the Commands (or ViewActions as we call them) will not give a ActionResult, but our controller will do this, since there is a lot of knowledge there around navigation between forms etcetera. But that’s not the subject of this post.

One of the things we’ve also been working on is to make the transition of the designers stuff to the asp.net stuff as small as possible, so that changes made by them can easily be merged in our controls. So the designers have been working on control-like pieces of html which will be reused to compose pages. Nothing strange here from a developers point of view, so we made UserControls out of them which will be the equivalent of their control-like html markup. These UserControls had to be used in several portal web project. So there were a few options on the reuse of the controls:

  1. Create CustomControls for each control-like element of the designersThis was not an option because the html delivered by the designers was sometimes very much in one control (over 300 lines) which would make it a nightmare (and laborious task) to keep CustomControl in sync with their markup files.
  2. Use the ‘Add as Link’ option to add the user controls to the portal projectsThis option was killed by the specific software factory what we had to use, since that didn’t support this construction which made all several nightly builds fail.
  3. Copy each UserControl to each portal projectYeah right… not an option at all of course.
  4. Convert UserControls into CustomControls.OK, that option was the only option left worth investigating.

So I had some work to do. This post by David Ebbo was a very good starting point on how to do it. So I started out with a small demo project where I did all the steps outlined by David and I got that part working. However, there were some things that were not the way we wanted it.

  1. The fixednames was not handy for us since we want to have one resulting dll, otherwise there were way to many dlls to reference in the portal projects.
  2. The name of the assembly of the controls was something like App_Web_BLABLA_ascx.dll which just looks ugly and might change over time, which made it useless for us in a automated scenario.
  3. The functionality should be integrated in the build of the project, to be able to make it work how the other projects work using the software factory

So I started out to fix these points. The first two points I wanted to fix was to merge the assemblies that were created and name them the way I wanted it. So I started with using ILMerge to do this. In my demo I had created two very small user controls to do this and after the ILMerge, it seemed to work. I then added a larger user control and tried that also, but that one just did not work correctly. Just a small part of the markup was visible and that was it. I did a lot of googling on it but eventually found out that when you go over a specific number of characters in your user control (I can’t remember the actual amount anymore :-(), resources are used in the generated code. And then ILMerge breaks it. After being stuck there for a while, one of my colleagues mentioned that I could try aspnet_merge instead. I didn’t know that it existed, but I tried it out and it worked like a charm.

So I only had to fix the 3rd point mentioned above. The software factory has a mechanism built in to copy assemblies created by the project to a specific location every time you build the project. So that lead me to the idea to add the aspnet_compile and aspnet_merge as a post build command, since the magic of the software factory was done using a AfterBuild MSBuild task, so I could not use that. Eventually my post-build command looked like this:

rmdir /S /Q "%TEMP%\Publish_$(TargetName)"
del  "%CD%\$(TargetName).dll"
del  "%CD%\$(TargetName).pdb"

"C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet_compiler.exe" -v "$(ProjectName)" -p "%CD%\.." -f "%TEMP%\Publish_$(TargetName)"

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\aspnet_merge.exe" "%TEMP%\Publish_$(TargetName)" -keyfile "%CD%\..\..\..\..\src\_Key\Product.snk" -a -copyattrs -o $(TargetName) -debug

copy "%TEMP%\Publish_$(TargetName)\bin\$(TargetName).dll" "%CD%\$(TargetName).dll" /Y
copy "%TEMP%\Publish_$(TargetName)\bin\$(TargetName).pdb" "%CD%\$(TargetName).pdb" /Y

 

First I remove the directory where I’m going to publish the web app (using the aspnet_compile).
Next step is also related to the software factory workings. The resulting assembly of the project has to be exactly the same name, otherwise it won’t be copied. So I delete the current dll created by the project, otherwise my aspnet_merge step will create an assembly which is not exactly the name I wanted. However, the result is that there can’t be worked with code behind files, but that was not a problem for this.
Then I use aspnet_compile to precompile the site and write the resulting stuff to a temporary folder.
Then the aspnet_merge is  executed to merge the created App_Web assemblies to one assembly with the same name as the assembly that would have been created by my original web application project. Note that I’m also resigning the assembly to make sure it is strong named.
The last step is to copy the merged dll and pdb files back to the original location.

With this small piece of post-build commands I got the solution eventually working and it is being used now in multiple solutions without problems. I hope some of you guys can also benefit from this. Please let me know if it helps.

Blog at WordPress.com.

%d bloggers like this: