I created a new web site project earlier this week using Visual Studio 2005 SP 1. Everything worked great except for building - when there was an error, no line numbers showed up in the Errors window! While this annoyance is sufferable when there are only a few pages, classes, and so forth in the project, as the number of pages and classes grew, the lack of line numbers made debugging increasingly difficult. There'd be some error message and then I'd have to track down where the error might reside out of the dozens of classes and pages that may have been modified since my last build. Urp.
After needlessly putting up with this nuisance for a couple days, I decided to get to the bottom of this. I found the following newsgroup post to microsoft.public.vsnet.debugging from an obvious Simpsons fan, someone going by the name of Rainier Wolfcastle:
“It turns out that there is some really helpful bug in Visual Studio 2005 whereby you don't get file names or line numbers in the Error List if your solution lives in a directory with parentheses in the path.”
Sure enough, the parent folder of the root of the web site application had a parenthesis in it. Once that was removed, line numbers returned to the Errors window. I wonder why this wasn't fixed in SP 1...
I teach two ASP.NET classes through the Extension program at the University of California - San Diego, and one of the most common questions I am asked regarding Master Pages is, “How do I pass information from my Master Page to its content page (or vice-a-versa)?”
For example, in the ASP.NET Programming II class, students create a custom site map provider whose structure is based upon the data in the database. The Master Page contains navigation controls (a TreeView, perhaps, or a Menu) that uses this custom site map provider. The challenge is on administrative pages, where an admin might add, update, or delete the corresponding database data, the Master Page's navigation is rendered before the content page executes its database command to modify the site map structure. Consequently, the page's navigation is not up-to-date immediately after modifying the site map structure (although it picks up the changes on the next postback). This can be remedied by having the content page tell the Master Page, “Hey, you there! I just updated the site map data, so go ahead and rebind the site map data to your TreeView.“
This begs the question, How do you get the content page and Master Page talking? To address this question, I wrote up an article discussing different techniques: Passing Information Between Content and Master Pages.
When building an ASP.NET 2.0 application in Visual Studio 2005, I received the following error: “Cannot implicitly convert type 'string' to 'System.Web.UI.WebControls.TextBox'”. No line number, no source page informing me where to begin my search. And it had been a while since my last build so there was a lot of code and markup that could be the source of the problem.
A quick Google search turned up this entry by Sam Judson:
Strange ASP.NET 2.0 Error
While developing a new web site using ASP.Net 2.0 recently I came across this strange error on compilation.
Cannot implicitly convert type 'string' to 'System.Web.UI.WebControls.TextBox'
It took my ages to work out what the hell was the problem, which string was it trying to convert?
The problem occurred because of the new Page.Title property. I had a TextBox whose ID was also set to Title. It was therefore trying to convert the string in the Page declaration into a textbox - not gonna work! This Title property is new for ASP.Net 2.0 so you might want to watch that one in your apps.
And that was the cause of my problem, a TextBox with an ID of Title. Once the ID was changed to something else, the project compiled without error. For more on the Page.Title property new to ASP.NET 2.0, see Dynamically Setting the Page's Title in ASP.NET 2.0.
In a couple of weeks I'll be presenting a full-day, hands-on conference/lecture/class/lab at the Robert Half Technology offices in Los Angeles. Together we will build a complete, functional, real-world blog engine that highlights recommended practices and ASP.NET 2.0-specific features. Topics discussed and implemented will include: using base page classes for encapsulating common functionality; logging and gracefully handling errors; building data access and business object layers; working with data through the ObjectDataSource; displaying and customizing data using the data Web controls; efficiently paging and sorting data; and employing caching to boost performance.
There is only room for 50 attendees and, at the time of this writing, close to half the spots are already taken. There are no computer workstations, so attendees are encouraged to bring their own laptops loaded with Visual Studio 2005 and SQL Server 2005 to follow along. (The free versions - Visual Web Developer and SQL Server 2005 Express Edition - will suffice.)
Here are the details:
- Cost: $45 (includes lunch; parking nearby for an additional $6-7 for the day)
- When: Saturday, Feburary 10, 2007, 9:00 AM - 5:00 PM (with a one hour lunch break)
- Where: Robert Half Technology, 10877 Wilshire Blvd, 4th floor (Suite 400), Los Angeles, CA 90024-4341, Phone: 310.209.6838 [map]
- Signup: To sign up, use the PayPal link at http://www.ladotnet.org/EventDescription.asp?133
Hope to see you there!
For years I've had a very low-end Lexmark InkJet printer, the kind that sells for $39.95, which is just a shade more than what they charge per ink cartridge. In retrospect, I really should have ditched it earlier. It was painfully slow in printing and I was unable to share it on the network, meaning that if my wife wanted to print something she'd have to copy the file(s) to my computer and I'd print them. And did I mention it was slow? But if you don't work in an office where they have sleak, ultra-fast, network-shared printers, you don't know what you're missing. So I was content with my little Lexmark and my wife, after coming home from an office full of high-end laser printers had to copy anything she needed to print to my machine and then wait several minutes as the printer caughed them out.
Finally we decided enough was enough and went looking for an All-In-One option to replace our printer and fax machine and to add scanning and copying capabilities. We ended up settling on the HP LaserJet 3050 All-In-One (shown on the right), which retails for $299.
Not counting furniture moving, installation and setup was a breeze. Just plugged in the various cords, plugged in the printer to my machine via the USB cable, and we were off and running. Faxing, copying, scanning, and printing are all very straightforward, simple, and FAST. In the time it would take the ol' Lexmark to churn out a single page, this puppy can put out reems of paper. It just sucks in the paper and spits it out, taking a second or two. Yeah, yeah, this is probably no big deal to those of you who haven't been living with outdated technology, but for yours truly, this alone has made the purchase more than worthwhile.
There are a couple of things that are less than ideal regarding the 3050:
- No USB-to-printer cable included. I don't know if any printer manufacturer includes this anymore. I used my old one from the Lexmark printer (which I had to buy separately back in the day). In any event, I think most people would rather HP (or Lexmark or whomever) would charge $5 or $10 more and just include the damn cable rather than having you get home, get to setting it up, and then realizing, “Cripes, it's back to the store for me.“
- No direct connection to network. The only way to hook up the 3050 model is through a USB cable, which is no biggie since it's hooked up to my always-on computer. But in a more traditional network setting, it's obviously ideal to have the printer hooked up to the network rather than a computer. To get the network hookup, you have to upgrade to the 3052 model, which is $100 more. $100 more also buys you a flatbed scanner/copier, which is nicer than the sheet feed option on the 3050. And I was just about ready to pony up the extra $100 for the 3052 and then found out that the 3052 doesn't include fax capabilities! If you want to fax and have a network jack and a flatbed scanner then you need the 3055, which is yet another $100. A 66% increase in the base price for a network jack and a flatbed scanner seemed a little too steep for this ol' cheapskate.
In any event, I really have liked the 3050 and am sure the 3052 and 3055 are just as good models. Highly recommended!
My 14th Toolbox column in the February 2007 issue of MSDN Magazine is now avaiable online. The February issue examines three products:
This month's issue reviewed .NET Test Automation Recipes, by Dr. James D. McCaffrey. From the review:
All programs, regardless of their size, scope, or complexity, should be thoroughly tested to ensure correct results and behavior for both expected and unexpected inputs. Many developers employ commercial or open source testing frameworks to aid and automate the testing process. While testing frameworks have their place, in his book .NET Test Automation Recipes: A Problem-Solution Approach (Apress, 2006), fellow MSDN® Magazine columnist Dr. James D. McCaffrey proposes that these testing frameworks be complemented with lightweight test harnesses. A lightweight test harness is a short (four "pages" of source code or less), simple, standalone program written to perform a test or set of tests against the target app. ... Lightweight test harnesses are, by definition, simple and should not take significant time to develop. This time can be lessened by having the recipes discussed in Dr. McCaffrey's book at your fingertips.
As always, if you have any suggestions for products or books to review for the Toolbox column, please send them into firstname.lastname@example.org.
I installed Visual Studio 2005 Service Pack 1 today on my main development box (Windows 2003 Server) and ran into the following error: “The installation source for this product is not available. Verify that the source exists and that you can access it.” In particular, I received the following error dialog box:
Some Googling turned up a fix for a very common error message when installing SP1 - “Error 1718. File FileName was rejected by digital signature policy” - but it took a bit more searching before I found this bug report in which user rlasker provided the following helpful comment:
I had this issue. When I looked in the event log I found this:
Event Type: Error
Event Source: MsiInstaller
Event Category: None
Event ID: 1008
Time: 12:18:31 PM
The installation of C:\DOCUME~1\...\LOCALS~1\Temp\ZNWA0\VS80sp1-KB926601-X86-ENU.msp is not permitted due to an error in software restriction policy processing. The object cannot be trusted.
I followed the instructions at this link:
And it no longer gave me the error descibed above.
Looking in my Event Log I found the same details and dutifully applied the workaround described at the KB (http://support.microsoft.com/default.aspx/kb/925336). These steps remedied the problem, and after rebooting I was able to successfully install SP1. Hopefully this post makes it to the first page of Google's results so future developers running into the same problem who are Googling the error message can more quickly find a fix.
For more VS 2005 SP1 info, see:
Tomorrow night, Tuesday January 16th, I'll be speaking at the ASP.NET Specicial Interest Group here in San Diego. The meeting, held at Microsoft's office in UTC on La Jolla Village Drive east of Genese, starts at 6:30 PM with announcements and free pizza and soft drinks!!! I'll start blathering around 7:00.
My talk examines techniques for handling errors in an ASP.NET web application and includes looking at:
- Using custom, human-friendly error pages (avoid the Yellow Screen of Death!)
- Techniques for automatically logging unhandled exceptions
- Ways to automatically notify developers in the face of an unhandled exception
- How to handle exceptions that arise from the depths of ASP.NET 2.0's data source controls. That is, we'll see how to handle exceptions that occur when you are working with data in an ASP.NET 2.0 page using the SqlDataSource control and a GridView and an exception is raised from the database layer.
If you can't make the talk, you can download the PowerPoint slides and code demos here. Hope to see you tomorrow!
It's about time for me to upgrade my laptop and am soliciting any
recommendations/advice you, my faithful blog reading audience of six, care to share. I use the laptop for User Group talks, conferences, and as the
presentation/demo machine for my classes and training. In total, it gets used maybe
once or twice a week for a total average of maybe four hours/week. That's the
only time the laptop is on. I do all my "real" work/development on a
Currently I have an older Dell I bought four years ago with 512 MB of RAM. It can crawl at times with a couple Visual Studio 2005 instances running, SQL Server Management Studio up, a couple browsers going, and so on.
I'd like to strike a nice balance between performance and portability, but there's no need to pay a premium for an "ultra-light." Moreover, since I only upgrade my laptop once every four or five years, I'd like something that's still capable (albeit slower, for sure) of handling Visual Studio 2010.
It's been so long since I've been in the market for a laptop and I've yet to start researching prices/specs, but thought I'd put out a request for comments and feedback. My budget is in the $1,500-$2,000 range.
Any comments, advice, or suggestions are most welcome.
Alert Working with Data in ASP.NET 2.0 tutorial reader Nathan P. wrote in to let me know that there is a small bug in the code for the paging and sorting with the DataList and Repeater tutorials. It's a silly off-by-one error that I should have caught long before turning in the tutorials.
In any event, the problem in the default paging examples is in computing the PageCount. I use:
1 private int PageCount
5 return (TotalRowCount / PageSize) + 1;
Which works well unless TotalRowCount and PageSize are evenly divisible. For example, let TotalRowCount = 79 and PageSize = 10, then this formula works as desired since 79/10 = 7, and 7+1 = 8, indicating that there are, indeed, 8 pages. But if there are 80 records in total, then 80/10 = 8, and 8+1 = 9, even though there are just 8 pages of data.
I fixed this by changing this to the following:
1 private int PageCount
5 if (TotalRowCount <= 0 || PageSize <= 0)
6 return 1;
8 return ((TotalRowCount + PageSize) - 1) / PageSize;
Alternatively, you could just return ((TotalCount - 1) / PageSize) + 1, which is equivalent to the formula in on line 8 in the above snippet.
Similarly, in the custom paging example I have the same off-by-one error, but it's in computing the starting index of the last page. In the ProductsDataSource's Selecting event handler there is:
int LastPageStartRowIndex = (TotalRowCount / MaximumRows) * MaximumRows;
Change this to:
int LastPageStartRowIndex = ((TotalRowCount - 1) / MaximumRows) * MaximumRows;
Also update this formula in the LastPage Button's Click event handler.
I've submitted the code/article updates for the affected tutorials. It should be updated on the live site within a few days, hopefully.
In order to use SQL cache dependencies in ASP.NET 2.0 on the Express Edition of SQL Server 2005 or on SQL Server 7.0 or 2000, ASP.NET needs to continuously poll the database to determine if there's been any change to the monitored tables. For this to work, the database needs some infrastructure installed on it - namely a “maintenance” table named AspNet_SqlCacheTablesForChangeNotification that keeps track of each monitored table and its latest changeId, stored procedures for reading and writing to this table, and triggers on the monitored tables.
This infrastructure is created using the aspnet_regsql.exe command line program, pointing it to the appropriate database and specifying that the polling infrastructure should be created on the database (which adds the maintenance table and sprocs) as well as what tables need to be monitored (which adds the triggers). aspnet_regsql.exe contains a switch called -sqlexportonly that will output the SQL syntax to a specified file, but sadly this option does not work with the polling infrastructure option. I was curious as to the output so I used SQL Profiler to examine the incoming T-SQL from aspnet_regsql.exe. I figured others might be interested as well, so I post it here to save others the three minutes it took me to get it from SQL Profiler:
Running the database-related command, aspnet_regsql.exe -S server -d database -E -ed, results in the following T-SQL sent to the database:
Running the table-related command, aspnet_regsql.exe -S server -d database -E -t tableName -et, simply calls the AspNet_SqlCacheRegisterTableStoredProcedure sproc passing in the name of the specified table:
exec dbo.AspNet_SqlCacheRegisterTableStoredProcedure @tableName=N'tableName'
This stored procedure - added when registering the infrastructure eith the -ed switch - creates an insert/update/delete trigger on the specified table that invokes the AspNet_SqlCacheUpdateChangeIdStoredProcedure stored procedure, passing in the table's name. AspNet_SqlCacheUpdateChangeIdStoredProcedure simply updates the changeId value in the appropriate row in AspNet_SqlCacheTablesForChangeNotification.
For more on using SQL cache dependencies in an ASP.NET 2.0 web application, see Caching in ASP.NET with the SqlCacheDependency Class, Overview of SqlCacheDependency, or wait for my upcoming Working with Data in ASP.NET 2.0 tutorial on the topic.