ross dickinson: web and desktop software developer

VirtualPathProvider and ScriptManager conflict.

by Ross on January 25, 2011 at 8:05 PM under .NET | ASP.Net | Programming

I spent this afternoon working on a custom VirtualPathProvider for two websites we have at work. We need to share resources(master pages, themes, scripts, etc) between the two and I figured embedding resources in a separate project would be the best bet. The VirtualPathProvider implementation takes any old path its given(like "/resources/style.css") and looks to see if there's an embedded resource that matches. This worked out great after I got around some annoying implementation details(MSDN documentation on VirtualPathProvider is kind of terrible).

Then I got stumped. On some pages everything would work as expected. The page would include all the referenced embedded resources and load without a hitch. On other pages, though, the same reference would result in an "Directory not found" HttpException for no apparent reason. After tearing my hair out trying to find something wrong with my VirtualPathProvider, I went to look at the full stacktrace of what was wrong. I probably should have done that in the first place seeing as my problem wasn't specifically being thrown by my VirtualPathProvider class.

[HttpException (0x80070003): Directory 'C:\Solutions\Website\Resources\Dir' does not exist. Failed to start monitoring file changes.]
System.Web.FileChangesMonitor.FindDirectoryMonitor(String dir, Boolean addIfNotFound, Boolean throwOnError)
System.Web.FileChangesMonitor.StartMonitoringPath(String alias, FileChangeEventHandler callback, FileAttributesData& fad)
System.Web.Caching.CacheDependency.Init(Boolean isPublic, String[] filenamesArg, String[] cachekeysArg, CacheDependency dependency, DateTime utcStart)
System.Web.Caching.CacheDependency..ctor(String[] filenames)
System.Web.Script.Services.WebServiceData.GetWebServiceData(HttpContext context, String virtualPath, Boolean failIfNoData, Boolean pageMethods, Boolean inlineScript)
System.Web.Script.Services.PageClientProxyGenerator.GetClientProxyScript(HttpContext context, IPage page, Boolean debug)
System.Web.UI.ScriptManager.RegisterServices()
System.Web.UI.ScriptManager.OnPagePreRenderComplete(Object sender, EventArgs e)
System.Web.UI.Page.OnPreRenderComplete(EventArgs e)
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

What's ScriptManager doing? Beats me, but I looked into it and came across this: HttpException when serving a page with a ScriptManager using a Virtual Path Provider

It turns out that, prior to ASP 4.0, the ScriptManager control has a bug that causes it to ignore any custom VirtualPathProvider classes whenever it does whatever it does internally. This only happens when the ScriptManager's EnablePageModes property is set to true. Setting this to false immediately fixed my problem. That may not solve everyone's problem, though. There's a hotfix available for this specific issue, though I can't vouch for it.

 

I discovered this bug/feature today. While working on a new page for work, I was having an issue where none of the child controls inside an ascx user control were instantiating during runtime, leading to all sorts of null reference exceptions. I wasn't quite sure why, as the custom control worked fine on every other page.

After a bit of tooling around, I found out that the problem was in how I registered the control at the top of the page. The problem was here:

<%@ Register Assembly="CompanyName" Namespace="CompanyName.Controls" TagPrefix="companyname" %>

I was trying to register the project's controls namespace so that I didn't have to register each control that I used individually. Visual Studio didn't complain, nor did the compiler. I was able to put in any of the types and it worked out fine. The big mystery is that, for reasons unknown to me, the user controls would instantiate on the page normally, but none of their child controls would. 

Switching the register back to

<%@ Register Src="~/Controls/UserControl.ascx" TagName="UserControl" TagPrefix="companyname" %>

And everything worked fine again.

The only thing I can figure out is that this is specific to user controls that have a designer file. External control libraries still work fine.

Update!

I finally realized why this was happening. Because the "ascx" part of a user control is a template, the template doesn't get loaded unless it's registered specifically. You can get around this by going: CustomControl.LoadTemplate("ascx path")!

Cleaning up ASP.Net WebForms markup

by Ross on November 19, 2010 at 1:08 PM under ASP.Net | Programming

One thing that clutters up ASP.Net websites is the amount of excessive markup created by controls.

One way to reduce the overall page size of the final output is to null/remove ID's on controls created in markup that don't need it. This often pops up because you've created a label, button, or some other control in the markup that you need to access from the code behind. If the control isn't being used on the client-side(through javascript, form validation, or some other purpose), you can safely set the ID property to null to prevent ASP from rendering the attribute. This is espescially helpful in versions previous to .Net 4, where you could potentially get id fields like "ctl00_ContentPresenter1_Parent_Child_GrandChildren_CabDrivers_lblStatus" mucking things up.

Consider this before going ahead: Objects relying on the FindControl method will still require that the ID attribute be set in order to find it. To avoid causing problems, you should null the ID property during the rendering phase. This can be done on the page level or the control level.

Preventing Focus Loss in WPF

by Ross on August 19, 2010 at 3:15 PM under Programming | WPF

For my program, Crunch, I'm trying to create a program that will be easy to convert between WPF and Silverlight. While they're the same for the most part, the two have a few differences that can lead to annoying compatibility issues. One of these is WPF's lack of Silverlight's ChildWindow class. The ChildWindow class allows for modal dialogs to pop up inside the Silverlight application itself, removing the need from breaking out of the web browser and showing a window.

Sadly, WPF doesn't have this feature. I've been able to work around this by making my own ModalDialog class. I'm not going into details on that, but one aspect that was annoying me recently.

When a ModalDialog instance displays inside its owning Window, the Window displays a container grid to cover up everything underneath. This works great for preventing mouse access of underlying controls and changing focus while the dialog is open, but this does nothing for keyboard navigation. A user could still hit tab and tab out of the control, leading to any number of problems!

The first thing I tried was disabling all underlying controls. This worked, but it seemed hacky and made the layout pretty ugly.

After some searching, I found there's two simple lines of code I can use to get around this issue. With these two properties set, keyboard focus is trapped within the container until either the property is changed, or another control is forcibly focused through code.

'Locks the tab key to the focused control

KeyboardNavigation.SetTabNavigation(modalContainerGrid, KeyboardNavigationMode.Cycle)

'Locks the tab key to the focused control if the user's also holding down Ctrl

KeyboardNavigation.SetControlTabNavigation(modalContainerGrid, KeyboardNavigationMode.Cycle)

I hope this helps someone in the future!

ASP.Net's TextBox class and MaxLength

by Ross on July 26, 2010 at 3:14 PM under Programming | ASP.Net

You learn something new every day!

It appears that ASP.Net's TextBox class doesn't have any built-in validation for trimming the Text property's length if the MaxLength property is set to a value greater than zero.

I suppose this is to give user's more leeway in how they want to validate the control, but it's not immediately obvious that a user can get around this limitation just by altering the html! ie: A user could use the FireFox FireBug extension to remove the textbox input's maxlength attribute and load it up with as much text as they'd like!

So remember kids: Always validate your input!

My brain does work!

by Ross on July 15, 2010 at 3:13 PM under Programming

I'd been trying to get around the need to install SQL Compact for users that don't have it already. I'd read everything on msdn about how to do it, but my brain was just not comprehending the stupid easiness of it.

I had been trying to reference the private SQL Compact dlls in my project, thinking I was required to do that to get the private dlls to install. I'm an idiiot, and realized just now that I just need to copy the private dlls with the installer and continue to reference the regular dlls in my project.

*palm-forehead*

Crunch

by Ross on July 15, 2010 at 3:12 PM under Crunch | Programming | Software

Crunch, my diet and exercise tracking software, is coming along nicely! I think a public beta is in the near future.

About the author

rossisdead is a 26 year old web and desktop software developer from New Jersey. He has two cats and likes long walks on the beach.

On Stackoverflow

On Stackoverflow Careers

On Codeplex

On Github