Page.ParseControls combined with custom webcontrols

I recently ran into a problem that had me stumped for a while.  In one of my legacy ASP.NET 1.1 applications, I use a few different custom webcontrols where I’ve over-ridden the default render() method in order to produce different output.  For example, I wanted to use a CheckBoxList web control, but I was unhappy with the way it rendered by default, for both the flow and table methods.

This worked fine for normal pages, and is usually not really a big deal.  However, when it came time to using them in a project of mine that used Page.ParseConrols() to dynamically generate ASP.NET controls, I was always getting the error “Unknown server tag: blah”.

Page.ParseConrols() is not a very common method to use for generating ASP.NET pages, but in my case it was necessary.  This particular application generated webpages by transforming XML using an XSL stylesheet, and then sought to render the results of that transformation to the page.  However, I also wanted to be able to use the results of that transformation in codebehind, if the user wanted to perform a postback on the rendered page.  So instead of using XSL to simply output common HTML tags, I output tags like asp:TextBox and asp:Button.  Normally all this would do is print literal text of asp.net tags to the screen, because the webcontrols aren’t being processed.  But Page.ParseConrols() allows you to pass a string to it, and it outputs a control that can be added to a PlaceHolder.

That description is a little muddled, but hopefully you sort of get the idea.  Anyways, the problem came about when I tried to also use a custom webcontrol in this manner, alongside the regular asp.net webcontrols.  It would always give me the unknown server tag error, even though I had clearly included my @Register TagPrefix directive on the page with the placeholder.

The trick was, you have to include the @Register directive along with the rest of the content that’s passed to Page.ParseConrols().  Once you include that directive as a prefix to the rest of the html, it works as expected.

See the following links for resources that helped me:

http://groups.google.com/group/microsoft.public.dotnet.framework.aspnet.webcontrols/browse_frm/thread/1bb2ab396fd26b0b?hl=en&lr=&ie=UTF-8&oe=UTF-8&rnum=1&prev=/groups%3Fq%3DPage.ParseControl%2Btag%2Bprefix%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3DUTF-8%26selm%3D%2523lZ%2524jzRdCHA.1540%2540tkmsftngp10%26rnum%3D1

http://forums.asp.net/p/376584/1514100.aspx#1514100

Workflow not updating using SharePoint Designer

I recently came across a really frustrating problem where I had to make an update to a workflow that had been in place for a few months (changing the wording in an email that’s sent out).  The strange thing was, the changes never seemed to be applying, the behaviour of the site was such that it always seemed like the “old” workflow was running, even though I had updated it, the wording in the emails were not changing.

I eventually ran across this post:

http://blogs.msdn.com/sharepointdesigner/archive/2007/03/27/tip-clearing-the-spd-workflow-assembly-cache.aspx

Which gave instructions on how to clear the SharePoint Designer Workflow Assembly Cache.  That fixed the problem.

To clear the SPD activity cache:

1. Close SPD.
2. Open “My Computer”.
3. Go to %System Drive%\Documents and Settings\%user%\Local Settings\Application Data\Microsoft\WebSiteCache (If you are running Vista, that path is different – look for %System Drive%\Users\%user%\AppData\Local\Microsoft\WebSiteCache).
4. Go to a directory that looks similar to the name of the website you were connecting to. (Alternatively, you can just delete all these directories and everything should work when you boot SPD).
5. Delete the assembly with the name similar to the one you are changing.
6. Boot SPD.
7. You can now work with your updated activity.

Postbacks and Web User Control (ASCX) pages

Recently I had a problem where I was loading a web user control (ASCX) file onto a web form through a placeholder.  The actual web form had very little to it, all it did was load the web user control into the placeholder, and nothing else, all the work happened in the user control.

Whenever I did a postback from the ASCX file, I could not programatically extract any values from them, either by referencing the form objects directly (TextBox1.Text), or indirectly (PlaceHolder1.FindControl(TextBox1.Text).  In either case, the object would always be found, but it would never have its value saved, it would always be empty, regardless of whether it was a textbox, dropdown, checkbox, etc.

I tried messing around with ViewState options and scopes, but I eventually traced it back to the fact that I was loading the placeholder from the Page_Load area, rather than the OnInit() section.  Once I moved the following code:

PlaceHolder1.Controls.Add(Page.LoadControl("MyUserControl.ascx"));

from the Page_Load() area to the OnInit() area, the code worked fine.  I really should take some time to carefully read the documentation about the ASP.NET page life cycle and how it handles viewstate.  I have somewhat of an understanding of it, but problems like this stem from my ignorance about aspects of it.

Javascript Scope Oddity

Stupid problem I had to deal with today.  One program I am developing is a dynamic XML form tool, and one of it’s features is the ability to incorporate dependencies, only show this question if questionA was set to true, and questionB was set to 5, or questionC was set to “cookies”, etc etc, you get the idea.  The dependency code is triggered by onBlur() events on each element.

This was fine when filling out a form, but when you wanted to view a form that had already been filled out, certain answers would not appear because by default, they were not visible.  Now, this problem could have been solved a few ways, but what I felt would be easiest would be just to go through all the form elements and call the onBlur() event on each one.  I used the following code:

for (i = 0; i < document.forms[0].elements.length; i++) 
{  
    if (typeof(document.forms[0].elements[i].onblur) == 'function')
    { 
        document.forms[0].elements[i].onblur(); 
    }  
}

Fairly straightforward.  I then used

Page.RegisterStartupScript()

in my code behind to allow the javascript code to run when the page is loaded.

Funny thing happened though.  Only one onBlur() event would occur.  It’s like the others got stuck in a queue that never fired.  This seemed like such a stupid problem, but i spent a long time trying to figure out what was happening.

What I eventually discovered, was that in my doDependencies javascript code, which performed the show/hide logic on form elements that depended on others, I also used index variable i to loop through various form elements.  When I changed the name of my loop index variable, it worked fine.  I’m still not quite sure why this was even a problem, I would have thought that once you entered the onBlur() function, that the scope would be different and you would be able to re-use the same variable.  Strange.

InfoPath Rich Text Fields and “stuck” formatting

I’ve been working on an odd problem off and on for the last little while.  My organization uses a customized electronic forms workflow system based on Microsoft InfoPath 2007 to manage forms, policy documents, manuals, etc etc, to control the authoring and revision process.  The InfoPath templates we use include several Rich Text fields that allow the user to format the policy/instructions/etc nicely with all the headings, lists, styles that their little hearts desire.  Usually what this means however, is that they are copying blocks of text out of an existing Word document that they’ve drafted, and pasting it into the InfoPath template. 

Usually this is not a problem, and everything does smoothly. However, for larger documents, I’ve found that InfoPath’s rich text fields have a hard time … umm … “digesting” more complex blocks of rich text.  Sometimes you paste in a large block of formatted text, you save or submit the document, and then the next time you load it using the template, everything comes back bold, or everything comes back underlined, or something really wacky happens with the text.  The *really* great part is that it’s almost like the formatting becomes “stuck”, you try to undo the bold for a selection of text, and it won’t let you! 

I’m pretty sure this has something to do with all the invisible formatting junk that comes along for the ride when you copy and paste text from Word into InfoPath.  A quick look at the source xml shows beautiful stuff like this:

<font style=”FONT-SIZE: 11pt”/></ul></ul></ul></font></font></font>
</div></div><div><div><font face=”Calibri”><font face=”Calibri”>
<font face=”Calibri”><font style=”FONT-SIZE: 11pt”>
<font face=”Calibri”><font style=”FONT-SIZE: 11pt”><strong><strong>
<strong><strong/></strong></strong></strong></font>
</font></font></font></font>
</font> </div></div></font></font>

What a giant mess.  This was found at the end of a block of text that was pasted into the rich text field.  The only solution I have found is to first copy the text from Word into NotePad, which strips out all of that crap, then pasting it into InfoPath, and spending a bit of time to re-do the formatting.  It’s tedious, but necessary for larger, more complex documents.

MOSS Database Connectivity / Crawler Problem

Recently we ran into a strange problem where after a variable length of time, sometimes hours, sometimes days, our MOSS application server would lose connection with our content database.  The event viewer would be inundated with messages similar to this:

Cannot connect to SQL Server. <servername> not found. Additional error information from SQL Server is included below.
[DBNETLIB][ConnectionOpen (Connect()).]SQL Server does not exist or access denied.

and

A runtime exception was detected. Details follow.
Message: An error has occurred while establishing a connection to the server. When connecting to SQL Server 2005, this failure may be caused by the fact that under the default settings SQL Server does not allow remote connections. (provider: Named Pipes Provider, error: 40 – Could not open a connection to SQL Server)

We were fairly sure this didn’t have anything to do with remote connections, they had been setup fine since the beginning, and rebooting the application server always seemed to fix the problem temporarily.

The other problem that we seemed to be having was that crawls of our site seemed to be getting “stuck” in the “Full Crawl” state within SharedServices.  Attempting to stop the crawl via the gui manager and through stsadm -o spsearch -action fullcrawlstop were unsuccessful.  The most that was accomplished was that a message was placed in the log saying that there was an “attempt” to stop the crawl, but it clearly wasn’t working properly.

Both of these were pretty important issues, when I ran across a solution that effectively killed both of these birds with one stone here:

http://www.sharepointblogs.com/gnarus/archive/2007/02/12/the-indexing-status-remains-in-the-crawling-state.aspx

The author concludes that this was happening because the Database server that SharePoint 2007 was using was a SQL 2005 server which has maintenance plans that rebuilds indexes. This issue was occurring because the Rebuild index task did not restore all the options that were set on the indexes that are used by SharePoint Server 2007 after indexes are rebuilt. The Ignore duplicate values option is turned off after indexes are rebuilt.

I would suggest heading there to see the full problem and resolution, but here is at least the resolution part repeated in case that site goes down or something.  This worked for us, but the maintenance plan kept bringing us back to the same problem.  We later discovered that upgrading to SQL Server 2005 SP2 helped with the maintenance plan problem (we were using SP1).  The knowledge base entry that was the source of this is found here: http://support.microsoft.com/kb/930887

Here is the RESOLUTION
To resolve this issue, you need to disable the maintenance plan that contains the Rebuild Index task. Then, use SQL Server Management Studio to locate the indexes that are specified in the following table, as appropriate for your situation. For each index, make sure that the Ignore duplicate values check box is selected.
 
Go into your SQL management studio and change the following tables in your search database to have the Ignore duplicate values check box enabled

* (You may have to temporarily click The Unique check box on the General tab on the Index Properties page so that the Ignor Duplicate check box is not grayed out)
 
Database Table name Index name
Search      MSSAlertDocHistory                 IX_AlertDocHistory
Search      MSSAnchorChangeLog                 IX_MSSAnchorChangeLog
Search      MSSAnchorPendingChangeLog                 IX_MSSAnchorPendingChangeLog
Search      MSSCrawlChangedSourceDocs                 IX_MSSCrawlChangedSourceDocs
Search      MSSCrawlChangedTargetDocs                 IX_MSSCrawlChangedTargetDocs
Search      MSSCrawledPropSamples                 IX_MSSCrawledPropSamplesByDocid
Search      MSSCrawlErrorList                 IX_MSSCrawlErrorList_hrResult
Search      MSSCrawlHostList                 IX_MSSCrawlHostList_Name
Search      MSSCrawlQueue                 IX_MSSCrawlQueue
Search      MSSDocSdids                 IX_MSSDocSdids

 Before you re-enable the maintenance plan, delete the Rebuild Index task or replace the Rebuild Index task with an Execute Transact-SQL Statement task. The Execute Transact-SQL Statement task should restore all options on indexes.