tag:blogger.com,1999:blog-234479092024-03-08T01:18:46.193-05:00AspNet2HolesASP.NET 2.0 does great things but like its ancestors also has holes: things we need to do but can't -- or can't without dodging around it with inside knowledge, JScript and other tricks. AspNet2Holes is about those holes and the ways to step around them.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.comBlogger38125tag:blogger.com,1999:blog-23447909.post-22201186457996500162008-12-22T04:12:00.001-05:002008-12-22T04:14:26.075-05:00Recovering the MissingUnder IIS 5.0 and before, and when debugging under Visual Studio 2005, HTTP file-not-found errors can be caught in a global.asax Application_Error event function, obscurely documented by Microsoft, whose first argument can be cast to global_asax, which supplies context, including an error message but not an HTTP error code. By using Server.Transfer error handling can be redirected to an ASP.NET page.<br /><br />Microsoft documentation for Visual Studio 2005 does not explain how to catch HTTP file-not-found errors under IIS 6.0, and many of the contributors to forums and Web logs have spread misinformation. IIS 6.0 will redirect HTTP file-not-found errors when configured for Custom Errors: HTTP Error 404, Type URL and Contents a so-called "absolute URL" for an ASP.NET page, for example, /VirtualDirectory/ErrorHandler.aspx where ErrorHandler.aspx.cs provides code to handle the file-not-found error.<br /><br />The key to this approach, omitted from Microsoft documentation, is that Request.RawUrl in the code for the error handler page identifies the HTTP error and provides the original URL that provoked it. It has the format, ErrorHandlerURL?nnn;OriginalURL, where ErrorHandlerURL is the URL to reach the error handler page, nnn is the HTTP error code, and OriginalURL is the URL that provoked the HTTP error. An error handler page can set Response.ContentType and write to the Response.Output stream to supply content for the OriginalURL.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com1tag:blogger.com,1999:blog-23447909.post-40559026697821540082008-11-30T20:17:00.021-05:002008-12-05T01:46:28.511-05:00Remoting without HeartburnThe infrastructure for .NET Remoting is capable of supporting any number of remotable objects, each with any number of remotable functions. For applications implemented on a LAN, the simplest and most efficient approach is a Windows service using one or more TCP channels with binary formatting serviced by one or more remotable objects with infinite life. If each potential client is serviced by its own object, no conflicts need occur, and services will be supplied simultaneously to multiple clients. This approach is not scalable, but it is suitable when there will be only a small number of clients.<br /><br />Microsoft documentation and several Web logs provide instructions to create services and remotable objects. What they do not clearly explain is that remotable objects need not be registered. When registered the framework may create instances on client demand rather than let the service control objects. Microsoft refers to the approach to remoting described here as "direct remoting" and "dynamic publication" but provides only a single example and a cursory description.<br /><br />Microsoft explains remotable objects with infinite life only in a Developer's Guide article and not in the class reference for MarshalByRefObject.InitializeLifetimeService. The VS2005 Microsoft documentation is misleading as to specifying paths to configuration files and as to specifying full URIs when launching remotable objects. For whatever reasons, you will not find direct remoting detailed in books that purport to explain .NET Remoting, including Ingo Rammer and Mario Szpuszta, "Advanced .NET Remoting" (2 Ed., 2005, Apress), a circumstance that probably tended to retard adoption of remoting technology.<br /><br />The configuration file for a Windows service with a "TcpAgent" channel is simple, in the following form:<br /><span style="font-family:courier new;font-size:80%;"><br /><~configuration~><br /> <~system.runtime.remoting~><br /> <~application~><br /> <~channels~><br /> <~channel name="TcpAgent" ref="tcp" port="9000"<br /> useIpAddress="true" bindTo="10.20.40.99" /~><br /> <~/channels~><br /> <~/application~><br /> <~/system.runtime.remoting~><br /><~/configuration~><br /></span><br />Using ASP.NET 2.0, the OnStart and Onstop methods for an "Agent" Windows service with a "Remote" class, providing an "AgentRemote" object, are also simple, in the following form:<br /><span style="font-family:courier new;font-size:80%;"><br />using System;<br />using System.Runtime.Remoting;<br />using System.Runtime.Remoting.Channels;<br />using System.Runtime.Remoting.Channels.Tcp;<br />using System.ServiceProcess;<br />static Remote m_oRemote = null;<br />public partial class Agent : ServiceBase<br />{<br /> protected override void OnStart(string[] args)<br /> {<br /> try<br /> {<br /> AppDomain oAppDomain = AppDomain.CurrentDomain;<br /> string sBaseDirectory = oAppDomain.BaseDirectory;<br /> string sConfigurationPath = sBaseDirectory + "Agent.exe.config";<br /> RemotingConfiguration.Configure(sConfigurationPath, true);<br /> m_oRemote = new Remote();<br /> RemotingServices.Marshal(m_oRemote, "AgentRemote", typeof(Remote));<br /> }<br /> catch (Exception oException)<br /> {<br /> }<br /> }<br /> protected override void OnStop()<br /> {<br /> if (m_oRemote != null)<br /> RemotingServices.Disconnect(m_oRemote);<br /> m_oRemote = null;<br /> }<br />}<br />public class Remote : MarshalByRefObject<br />{<br /> public override Object InitializeLifetimeService()<br /> {<br /> return null;<br /> }<br /> // remotable service functions<br />}<br /></span><br />In a VS2005 Windows service project, add an Application Configuration File item named app.config, and it will be automatically copied to the executable file directory and renamed using the ".exe.config" form shown above. For Windows services it is necessary to provide a full path to the configuration file, done as above when in the same directory as the executable. Returning null from InitializeLifetimeService allows infinite life. Multiple, named remotable objects from the same or different classes can be launched with multiple copies of new and Marshal statements.<br /><br />Client access to the "AgentRemote" object above is also simple, in the following form:<br /><span style="font-family:courier new;font-size:80%;"><br />using System;<br />using System.Runtime.Remoting;<br />using System.Runtime.Remoting.Channels;<br />using System.Runtime.Remoting.Channels.Tcp;<br />using System.ServiceProcess;<br />class AgentRemoteClient<br />{<br /> void ClientFunction()<br /> {<br /> TcpChannel oTcpChannel = new TcpChannel();<br /> ChannelServices.RegisterChannel(oTcpChannel, true);<br /> Remote oRemote = (Remote)Activator.GetObject(<br /> typeof(Remote), "tcp://10.20.40.99:9000/AgentRemote");<br /> if (oRemote != null)<br /> { // invoke methods on oRemote<br /> }<br /> else<br /> { // log exception<br /> }<br /> }<br />}<br /></span><br />The client needs a reference to the server executable and a using statement specifying the server namespace. Both client and server need references to System.Runtime.Remoting.dll, usually found in C:\Windows\Microsoft.NET\Framework\v2.0.50727.<br /><br />A Microsoft remoting configuration does not provide syntax for specifying multiple, named object instances launched via Marshal, but it is simple to provide an auxiliary text file that designates an object type and name for each, thus obtaining the benefits of configuration files without undesirable complications. The OnStart and OnStop methods and the remotable object functions can be elaborated with a variety of logging techniques to create a record of operations and exceptions.<br /><br />The Microsoft framework does not provide a way to associate remotable objects launched by Marshal with channels. That could be achieved with a Windows service for each channel. Otherwise, as a Developer's Guide article says, remotable objects can share but cannot own channels. Contrary to what Microsoft documentation implies in places, adding network addresses and ports to object names in the second Marshal argument will not work.<br /><br />To configure multiple channels and multiple remotable objects dynamically, the Microsoft configuration file can be replaced with a text file specifying channels to be registered with ChannelServices.RegisterChannel and remotable objects to be launched with RemotingServices.Marshal. Channels created using the TcpServerChannel class can be associated with IP adddresses, port numbers, formatters and other sink objects. With that approach, custom sinks can be added to provide interpretation, compression, encryption and other services.<br /><br />[Note: because of display limitations, characters "< " and " >" here are shown with a tilde ~ after or before them.]Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com1tag:blogger.com,1999:blog-23447909.post-20391452343678278672008-11-22T16:49:00.004-05:002008-12-05T01:54:24.542-05:00Remotely PossibleThe .NET Remoting services introduced with ASP.NET made interprocess communication much less burdensome for the C# (and C++) developer. Visual Basic developers long had the benefit of COM automation, but C++ developers were stuck with the tedious tasks of writing proxies and marshalling code. So .NET Remoting is life in the fast lane.<br /><br />However, the Microsoft examples of .NET Remoting and their emulations in most Web logs are only half debuggable (on the client side). With Microsoft's approach, the work on the server side is done in an object encapsulated in a DLL, not accessible to the debugger running a server (actually a server launcher). Beneficiaries of welcome automation must resort to archaic, file-writing techniques to debug a server-side process.<br /><br />The solution is actually simple. Just insert the remote object code in the server code, and don't put it in a separate project. In the client code, create a reference to the .exe file for the server. The Server code now looks like the following example, using a console application as a test vehicle for a TCP channel server:<br /><span style="font-family:courier new;font-size:80%;"><br />using System;<br />using System.Runtime.Remoting.Channels;<br />using System.Runtime.Remoting.Channels.Tcp;<br />namespace Server<br />{<br /> public class ServerFunctions : MarshalByRefObject<br /> {<br /> public int ServerFunction1( . . . .<br /> public bool ServerFunction2( . . . .<br /> . . . .<br /> }<br /> <br /> public class ServerLauncher<br /> {<br /> static void Main(string[] args)<br /> {<br /> try<br /> {<br /> TcpServerChannel oTcpChannel = new TcpServerChannel(9000);<br /> ChannelServices.RegisterChannel(oTcpChannel, true);<br /> RemotingConfiguration.RegisterWellKnownServiceType<br /> (<br /> typeof(ServerFunctions), "RemoteService",<br /> WellKnownObjectMode.Singleton<br /> );<br /> Console.WriteLine("Type Enter to exit");<br /> System.Console.ReadLine();<br /> }<br /> catch (Exception oException)<br /> {<br /> Console.WriteLine("Error: " + oException.Message);<br /> Console.ReadLine();<br /> }<br /> }<br /> }<br />}<br /></span><br />Be sure to add a reference to System.Runtime.Remoting.dll in a .NET Remoting project, when using ASP.NET 2.0 typically found in C:\Windows\Microsoft.NET\Framework\v2.0.50727. With code structured this way running under the Visual Studio debugger, functions in the ServerFunctions class can be debugged as usual. Corresponding client programs will acquire copies of the entire server .exe instead of just a .dll; that is the difference.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com1tag:blogger.com,1999:blog-23447909.post-62259806463956593762007-12-29T05:21:00.000-05:002007-12-29T05:22:34.391-05:00Staying in BoundsASP.NET 2.0 translates its Label control to an HTML SPAN element enclosing the text. Although a Label provides Width and Height attributes, they are simply translated to corresponding sytle properties of the SPAN and in most browsers have no effect. Since the SPAN does not contain an HTML tag, nothing constrains the Label text to an HTML box. How can you make a Label stay within bounds?<br /><br />Only by going a little outside the bounds of ASP.NET 2.0, as it turns out. For example, to constrain a Label to a single-line box, add a subsequent Label at the same top coordinate and at a left coordinate where the first Label should end, with Text=" " specified. Give both labels a style="white-space: nowrap" property, which is documented by MSDN under Web Development, not under .NET Development. Browser interpretation will overlay text of the first Label with the offset, blank text of the second Label, hiding text from the first Label that extends beyond the desired box boundaries.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-61596053343406784182007-11-15T05:06:00.001-05:002007-11-15T05:09:43.976-05:00Clicking and GamblingAs Mose Allison might have said, clicking can be a risky business. Especially when you click() on an ASP.NET 2.0 Button control. See "Check, set, click, whirr," May 26, 2007.<br /><br />Internet Explorer 6.0 will crash and burn if you do that inside the handler for an 'onclick' event. So tarry a bit, and keep customers happy. Just timeout:<br /><br /> window.setTimeout(ClickButton, 50);<br /><br />function ClickButton()<br />{<br /> var oButton =<br /> document.getElementById('<~% = ofButton.ClientID %~>');<br /> if (oButton != null)<br /> oButton.click();<br />}<br /><br />[Note: because of display limitations, characters "< " and " >" here are shown with a tilde ~ after or before them.]Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-31121294889659442252007-10-07T14:16:00.000-04:002007-10-07T14:32:13.258-04:00Validators LostAn obvious ASP.NET 2.0 wart is its poor documentation of validators. As previously noted, there is a March, 2002, background article for ASP.NET 1.0 validators, no longer distributed with MSDN. However, it has not been updated since 2002, and it fails to explain many validator behaviors.<br /><br />For example, when you enclose validators in a DIV that is initially hidden, you will find they don't work. That is because ASP.NET 2.0 conveniently disables them for you. Validators undergo preprocessing by the JavaScript that ASP.NET 2.0 emits, at the time a page loads in a browser. Hidden validators are disabled then; ASP.NET designers apparently thought that would be helpful. However, if you make a DIV visible, they didn't follow through by enabling validators it may enclose.<br /><br />To remedy the deficiency, enable validators in JavaScript. ASP.NET 2.0 provides a global JavaScript function to do that, invoked in the following example:<br /><span style="font-family:courier new;font-size:80%;"><br /> var oValidator =<br /> document.getElementById('<~% = ofValidator.ClientID %~>');<br /> if (oValidator != null)<br /> {<br /> ValidatorEnable(oValidator, true);<br /> if (oValidator.style.display != 'none')<br /> oValidator.style.visibility = 'hidden';<br /> }<br /></span><br />A wrinkle, as the example suggests, is that the Text message for a validator will be conveniently made visible when the validator is enabled. If that is not so convenient, then hide the message as shown.<br /><br />[Note: because of display limitations, characters "< " and " >" here are shown with a tilde ~ after or before them.]Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-62727863971643233582007-09-12T10:47:00.000-04:002007-09-12T10:49:17.576-04:00Attributes LostAll ASP.NET 2.0 controls accept an arbitrary collection of string-named and string-valued attributes in an Attributes property, populated with server-side C# statements such as:<br /> ofCheckBox.Attributes["oDatum2"] = "23a";<br /> string sDatum2 = ofCheckBox.Attributes["oDatum2"];<br />This example assigns the value "23a" to an attribute named "oDatum2" for a control with ID="ofCheckBox" and then fetches the value assigned into a string. Undocumented by Microsoft is that assigning an attribute value quietly replaces any prior attribute value with the same name.<br /><br />Sometimes Attributes items are used to add control-specific information sent to a browser, but they are also useful as memo fields and for communication with client-side JavaScript. Although not documented by Microsoft, values of Attributes items are maintained with control state. They do not depend on view state, and after a postback they can be retrieved from controls server-side even if using the Page EnableViewState="false" option.<br /><br />Looked at client-side, controls may seem to lose attributes. Use the JavaScript debugger to examine one:<br /> var oCheckBox =<br /> document.getElementById('<~% = ofCheckBox.ClientID %~>');<br />When "ofCheckBox" is the ID for an ASP.NET 2.0 CheckBox, the JavaScript debugger will not show properties of oCheckBox corresponding to any Attributes assignments made server-side. The attributes are not lost, however. They are elsewhere.<br /><br />Some ASP.NET 2.0 controls generate HTML composites; CheckBox is one of them. Following are the ways, undocumented by Microsoft, in which some of the common ASP.NET 2.0 controls are translated to HTML elements:<br /> Label -- span<br /> TextBox -- input<br /> RequiredFieldValidator -- span<br /> CheckBox -- span (label, input)<br /> RadioButton -- span (input, label)<br /> DropDownList -- select<br /> Button -- input<br /><br />A CheckBox is translated to a span that contains a label and an input. Attribute items assigned to a composite control will be encoded as properties of the outermost HTML element. For a CheckBox, they will appear on the corresponding span. The ID for an ASP.NET 2.0 composite control, however, does not necessarily go to the outermost element. In particular, undocumented by Microsoft, it becomes the ClientID property of the input element for a CheckBox or a RadioButton.<br /><br />In order to get the client-side value of an Attributes item named "oDatum2" that was assigned server-side to a CheckBox with ID="ofCheckBox" as ahown above, use a JavaScript statement like the following:<br /> var oDatum2 = oCheckBox.parentNode.oDatum2;<br />Communication using Attributes items is one-way. One can create attributes and assign values to attributes client-side, as JavaScript object properties, but new attributes and attribute values will not be transmitted to a server with postbacks.<br /><br />[Note: because of display limitations, characters "< " and " >" here are shown with a tilde ~ after or before them.]Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com1tag:blogger.com,1999:blog-23447909.post-8197336595909465412007-08-28T17:19:00.000-04:002007-08-28T17:21:34.643-04:00Passage to IndiaDespite company origins as a Basic compiler vendor, Microsoft has long shown an erratic, often indifferent attitude toward software tools. It dropped the ball in the mid-1980s and was scooped by Borland with C++. It dropped the ball again in the mid-1990s and was scooped by Sun with Java. After a surge of work in the early 2000s on the second (and the first successful) versions of C# and ASP.NET, it again shows signs of fatigue.<br /><br />Key management roles have been turned over to sharp pencils, and they have outsourced support to India. While India certainly has many competent software engineers, those working on Microsoft tools support either do not have or are not allowed to use much skill, and they apparently lack close relationships with developers. Their working knowledge matches what appears in Microsoft documentation.<br /><br />Microsoft support for software tools has become relatively expensive and also relatively ineffective in just those situations where it could matter the most. If one has a problem, as one frequently will, with software issues not explained or poorly explained by documentation, and if one has already studied the documentation, then there will be little help from Microsoft. Time and money will be wasted revisiting the documentation, and usually there will be nothing beyond it.<br /><br />Keepers of the various Microsoft and Microsoft-oriented Web forums are similar. The latter often have business interests with Microsoft, and they will rarely venture beyond the company lines. Many forum-keepers appear to lack knowledge other than documentation, although some of them try to make up for that with arrogance. There are, fortunately, several book authors and Web logs, most independent from Microsoft, covering trouble spots. As a practical matter, they have become our key sources of support.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-56215978850185911812007-08-07T23:38:00.000-04:002007-08-08T13:08:25.399-04:00What were they thinking?In winter, 2007, Microsoft provided Service Pack 1 for Visual Studio 2005. It arrived hobbled with an installer that could take as long as 6 hours to run, using up to 8 GB of system drive storage when the VS software was on some other drive. That put it far down the priority list.<br /><br />Eventually, Service Pack 1 got installed in the hope of solutions to at least a few of the longstanding bugs and problems with VS 2005, including these:<br /> * random process lockup with concurrent activities<br /> * random errors with application domain unload<br /> * random errors responding to view change keystrokes<br /> * random errors with focus lost<br /> * random errors with miscolored text<br /> * random errors indenting inserted text<br /> * design views unusable from clumsy formatting<br /> * inability to generate resources if using includes<br /> * lack of response during searches and builds<br /> * hyperactive popup of error and status panes<br /> * very slow searches across project files<br /> * failure to maintain context of a project search<br /> * missing resources not reported at build time<br /> * JavaScript errors not reported at build time<br /> * JavaScript breakpoint requires code insertion<br /> * inability to compare files or file versions<br /> * inability to search within Quick Watch panels<br /> * only dynamic ListBox usable with AutoPostBack<br /><br />A couple month's use shows not a single bug fixed or problem solved, certainly not the mother of all bugs. See "Cover your buttons," March 2, 2007. So what were they thinking?Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-4476437102590784542007-06-04T14:43:00.000-04:002007-08-12T13:52:45.972-04:00Button validation and moreASP.NET 2.0 introduced the ValidationGroup property associating validators with action controls. It is often used to make asp:Button controls activate a designated set of validators before a postback. Sometimes buttons also need to trigger other client-side work before a postback. For such purposes ASP.NET 2.0 introduced the OnClientClick property of asp:Button, specifying JavaScript to be executed before postback, which can return a boolean value to control whether or not postback occurs.<br /><br />Useful features, except when you need them both. If you try that, you will find that your OnClientClick code runs but your validators do not. Microsoft does not give advice on how to handle this situation or even tell you that it happens. What is going on here is that the HTML produced to represent an asp:Button with validators has an onclick property specifying a function that runs the validators in the associated ValidationGroup. The OnClientClick property of asp:Button overrides that onclick HTML property.<br /><br />You get both features to work together by activating the validators inside the JavaScript code specified by OnClientClick, using undocumented variables and functions as shown in the following partial example:<br /><br /><span style="font-family:courier new;font-size:80%;"><br /><~asp:Button ID="ofButtonTest" runat="server"<br /> OnClientClick="return ValidateAndDoWork('Submit')"<br /> OnClick="ButtonTest_Click" ValidationGroup="Submit" ... /~><br /><br><br />function ValidateAndDoWork(oValidationGroup)<br />{<br /> if (Page_Validators == null || ValidatorValidate == null<br /> || ValidatorUpdateIsValid == null || Page_BlockSubmit == null<br /> || ValidationSummaryOnSubmit == null || Page_IsValid == null<br /> || __defaultFired == null)<br /> {<br /> DoWork();<br /> return true;<br /> }<br /> var oValidatorCount = Page_Validators.length;<br /> for (var oValidatorIndex = 0;<br /> oValidatorIndex < oValidatorCount; ++oValidatorIndex)<br /> ValidatorValidate(Page_Validators[oValidatorIndex],<br /> oValidationGroup, null);<br /> ValidatorUpdateIsValid();<br /> ValidationSummaryOnSubmit(oValidationGroup);<br /> Page_BlockSubmit = !Page_IsValid;<br /> if (Page_IsValid)<br /> DoWork();<br /> else<br /> __defaultFired = false;<br /> return Page_IsValid;<br />}<br /><br><br />function DoWork()<br />{<br /> ...<br />}<br /></span><br /><br />The ValidateAndDoWork function first executes all validators for a specified validation group. Note that the JavaScript specified for OnClientClick must return a value and must know, determine or receive as a function argument the name of the associated ValidationGroup. If validation passes, ValidateAndDoWork invokes DoWork to perform other client-side work before a postback and returns true. Otherwise ValidateAndDoWork returns false, preventing a postback.<br /><br />ASP.NET client-side validation does not operate under FireFox, Mozilla and Netscape. Thanks to Tom Newman, posting on Scott Guthrie's Web log at http://weblogs.asp.net/scottgu/archive/2005/08/04/421647.aspx, who illustrated undocumented client-side variables and functions that work under ASP.NET 2.0 and are used here.<br /><br />[Note: because of display limitations, characters "< " and " >" here are shown with a tilde ~ after or before them.]<br /><br />----------------------------------------------------------------------<br /><br />Update, August 12, 2007<br /><br />Page_Validators, ValidatorValidate, etc. are not entirely undocumented. Anthony Moore, Microsoft's Development Lead for .NET Framework and later for Base Class Libraries, wrote a helpful article on validation describing these elements at http://msdn2.microsoft.com/en-us/library/aa479045.aspx, last updated for ASP.NET 1.1 in March, 2002. This article has not been updated for ASP.NET 2.0 and is not distributed with the Visual Studio 2005 documentation.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-7126193442312570712007-05-26T08:12:00.000-04:002007-05-26T08:28:41.042-04:00Check, set, click, whirr<span style="font-family:georgia;"><br />A useful characteristic of most ASP.NET controls, not documented by Microsoft, is an ability to be addressed as ordinary HTML elements while also practicing all their usual ASP.NET behaviors. From JavaScript, for example, ASP.NET checkboxes can be checked, text fields can be filled, and pushbuttons can be pressed. Postbacks will respond in the same ways that they respond to equivalent user actions. Typical JavaScript looks like this:<br /></span><br /><span style="font-family:courier new;font-size:80%;"><br /> var oCheckbox = document.getElementById('<~% = ofCheckbox.ClientID ~>');<br /> if (oCheckbox != null)<br /> oCheckbox.checked = true;<br /> <br><br /> var oTextbox = document.getElementById('<~% = ofTextbox.ClientID ~>');<br /> if (oTextbox != null)<br /> oTextbox.value = 'Sample text string';<br /></span><br /><span style="font-family:georgia;"><br />The <~% = ... %~> display blocks reference ID properties of asp.CheckBox and asp.TextBox markup elements, here illustrated as ofCheckbox and ofTextbox. They are needed for compatibility with master pages. See "Mastering and paging JavaScript: Solutions," June 1, 2006.<br /></span><br /><span style="font-family:georgia;"><br />Hidden pushbuttons are handy for server-side interaction. Just add "display: none" to the Style attributes of an asp.Button element. Typical JavaScript looks like this:<br /></span><br /><span style="font-family:courier new;font-size:80%;"><br /> var oButton = document.getElementById('<~% = ofButton.ClientID %~>');<br /> if (oButton != null)<br /> oButton.click();<br /></span><br /><span style="font-family:georgia;"><br />Hidden textboxes, checkboxes and other controls are an easy way to exchange context information with a server. This approach is simpler than using the also undocumented __doPostBack function sometimes recommended, which requires additional JavaScript enoding and server-side decoding. It minimizes exposure to proprietary features of the Microsoft environment.<br /></span><br /><span style="font-family:georgia;"><br />[Note: because of display limitations, characters "< " and " >" here are shown with a tilde ~ after or before them.]<br /></span>Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-46718441536111049442007-03-02T12:18:00.000-05:002007-03-02T12:22:10.534-05:00Cover your buttonsMicrosoft users sometimes wait years for mistakes to be repaired. Such appears to be our fate with the "Hurry Up and Crash" bug that has plagued ASP.NET 2.0 since its release. A report of the bug appeared on Microsoft's Connect site three months after product release, followed by repeated comments from developers urging Microsoft to fix the problem.<br /><br />The "Hurry Up and Crash" bug appears when a user of an ASP.NET 2.0 application clicks on a button or exercises another control "too soon." That crashes the application. If the user is lucky, a diagnostic appears saying, "Validation of viewstate MAC failed." Only users in Microsoft's UI development group are likely to understand. The cause of the problem is that ASP.NET 2.0 event validation may fail if a postback occurs before a page has been fully interpreted by Internet Explorer or by another browser that provides early activation of controls.<br /><br />Developers were alarmed. This is a Class 1 bug threatening most ASP.NET 2.0 applications. It is unpredictable and also fatal. Forum pages buzzed with unhappiness, but Microsoft took a couple of months to say "Many thanks for your feedback. We are investigfating [sic]." The "Hurry Up and Crash" bug is so gross it seems hard to believe Microsoft testers missed it before product release. But maybe they didn't.<br /><br />Finally, about a year after a report of the bug appeared on the Connect site, Microsoft offered its lordly opinion, a gem of sorts: "...we are being very strict about the number and scope of bugs that are fixed...we are not able to address it....Before starting work on the next full release of the .NET Framework, we will review the Connect data to help us identify and address the top customer reported issues." So there we have it. A bug that can crash almost any application -- maybe it will be fixed some time in 2009 or 2010. Maybe not; this bug might never make the cut.<br /><br />The answer, of course, is to cover your buttons. Since the release of ASP.NET 2.0 a new Web site paradigm has begun to appear: the page with a curtain of decoration that vanishes to reveal content. A less drastic approach is to specify every potentially troublesome control with visibility hidden. Then at the end of page markup add JavaScript to make them visible. By the time a browser reaches that point it will (probably) have interpreted Microsoft's critical elements and can do postbacks correctly.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-61503407752972158562007-02-19T16:54:00.000-05:002007-02-19T16:56:09.047-05:00Debug-heaven in Server 2003 Web EditionUsers of Visual Studio 2005 and Internet Information Services 6.0 will probably discover that the Visual Studio tools cannot be used to build a Web site via a network link to Windows Server 2003 Web Edition, because these tools require more network connections than the Web Edition server will provide. At first glance this limitation appears to prevent remote debugging of an ASP.NET 2.0 Web Forms application that is running on a Web Edition server under IIS 6.0.<br /><br />However, Microsoft provides Visual Web Developer 2005 Express as a free download. Installing this tool on the server and building on the server, with debug enabled, generates a Web site that can be opened via a network share in Visual Studio 2005 Professional or Team Edition. The Express tool is also useful to verify that a site will behave properly when it runs in a production user account environment.<br /><br />Visual Studio 2005 Professional or Team Edition can use the Visual Studio 2005 Remote Debugger service installed with the Express tool, attaching an IIS 6.0 process. A developer will then be able to set breakpoints and debug code normally. Running under IIS 6.0, properties of the Environment class may be different from those found when running under a built-in Visual tool debugging server. When a rebuild is needed, the Express tool must be used to do it, and the site should not be open in both Express and Pro tools at the same time.<br /><br />To use this approach, create Administrator accounts with the same name and password on both the development machine and the server. Also visit the Visual Studio 2005 Remote Debugger service properties, enable and start the service, and specify the developer's user account under the Log On tab. While debugging under IIS 6.0, the worker process is stopped whenever the code is on break. That causes any other session or Web site in the same IIS 6.0 application pool to stop.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-50215117468901121082007-01-17T10:35:00.000-05:002007-01-17T10:38:43.957-05:00C# as evolutionWhen introduced with trumpets and fanfares, Microsoft's C# language provided little beyond the C++ language, for which Microsoft already offered a widely used tool set, that was not also provided by the Java language. Unlike the extensive, collaborative and sometimes public efforts in which Bjarne Stroustrup designed C++ and James Gosling designed Java, the design of C# was a mostly private process. Initially rather constricted and viewed by some as a crippled C++, the C# language was revised in a fall, 2005, release that improved its capabilities.<br /><br />While C++ and Java were each major innovations, C# has an industrial tone. It is mostly a language for applications rather than systems. It disfavors pointers, which can crash applications but are often necessary for systems. As did Java, it revives from classic application languages like PL/I constructs such as built-in strings, arrays and streams that may be misfits or excess baggage in systems. Thread management is provided by built-in constructs similar to Java, while the ability to pass function arguments by reference rejects Java's limitations. The native class library was strengthened in the second edition with type-safe "generic" classes, but collections classes remain scattershot as compared with the C++ template library.<br /><br />C# is performance-oriented. Although it allows copy-constructors, it rejects the C++ convention of using them for collection objects, gaining run-time performance at a potential cost in robustness. Passing function arguments by reference likewise trades performance against robustness, protected to some extent by requiring matching "ref" or "out" attributes in function declarations and references. Unlike Java, C# retains the "enum" and the "struct" from C++, originally taken from C in round-about inheritance from Pascal, PL/I and COBOL. In C#, however, the "struct" is distinct from the class, more efficiently allocated and accessed and providing no inheritance. Once again the main benefit is performance.<br /><br />A key differentiator for C#, not apparent from syntax, is strong typing when implementing its type-safe classes, improving performance as compared to Java and preventing run-time errors as compared to C++. Distinctive features of C# syntax are built-in constructs for events and delegates, main ingredients of ASP.NET applications, and for class properties. In a similar spirit of automation its development environment automatically prepares declarations for and extracts them from compiled assemblies, eliminating "header" files of declarations.<br /><br />Perhaps as a marketing ploy, Microsoft has played up what it calls "innovations" in C#, but nearly all are new words or new implementations for well-established concepts. The "managed code" concept is a good (and key) example; its roots are in the automatic bounds checking of PL/I and other classic procedural languages. The Ada language remains a reference standard for managed environments, with rigorous component definition, type safety, bounds checking, automatic garbage collection and exception handling. C# joins these concepts with a concise syntax and an orientation to high-performance, event-driven applications.<br /><br />The future development of C# is reported to be integration with database access, currently supported by class libraries. That would be a risk-laden approach for Microsoft, likely to be seen as a venture to build out a monopoly for its SQL Server database products. Signals as to Microsoft's intents, if such a road is taken, will be whether or not unique features or syntax of SQL Server become imbedded in C# language constructs.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-56109978958980050632007-01-08T09:49:00.000-05:002007-01-08T09:51:03.154-05:00Who's on first? An IIS identity crisisMicrosoft Internet Information Services (IIS) version 6.0 introduced essential capabilities for managing Web page services to the Windows environment, including process pools, caching and server farms. Along with that came several more security features, including detailed control of the privileges under which Web page services execute on a server.<br /><br />IIS 6.0 includes several protentially conflicting ways to specify privileges, yet Microsoft provides very little information about how they interact. The most obvious of these potential conflicts is specifying a user account for a Web site and also specifying a user account for the process pool in which the site's services execute. When they are not the same, who's on first? What happens?<br /><br />The Web site's user account is specified in the IIS Manager tool under the properties "Directory Security," "Authentication and access control (Edit)," "Enable anonymous access." The process pool's user account is specified in IIS Manager under the properties "Identity," "Configurable." Both affect documented fields in the XML metabase of IIS, but undocumented is what will happen when the specified user accounts are not the same. Other, largely undocumented complications are "special privileges" and the default user accounts similarly specified for all Web sites and all process pools.<br /><br />At present most of this remains a mystery to be disentangled mainly through experimental programming. The few Internet forums and Web logs that touch on these topics reveal a general lack of knowledge. The only significant book on IIS 6.0, by Mitch Tulloch (Osborne, 2003), provides no more help than one can get on-line from Microsoft. At the "deliberate speed" with which Microsoft provides documentation, the next version of IIS is likely to be available before the current one has been explained.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-78542643544602246742007-01-02T06:49:00.000-05:002007-01-02T07:00:27.719-05:00Postback grief: some causes and a cureValidity checking of postbacks in ASP.NET 2.0 is a useful feature, but it can fail, generating mysterious messages that may begin, "Exception reported in __Page view...Invalid postback or callback argument...." One may also see, "Invalid postback or callback argument...Description: An unhandled exception occurred...." The messages go on with paragraphs that are likely to confuse a software developer, let alone a hapless user.<br /><br />Many problems result from Internet Explorer or other browsers responding to user actions before a page has been completely constructed. An early postback may lack necessary information from controls that have not yet been fully processed by a browser. That is likely to happen when a page contains a grid or other bulky data or when it uses third-party controls that construct themselves on a client through JavaScript. In its designs for ASP.NET 2.0 and Internet Explorer, Microsoft evidently failed to anticipate such synchronization errors, and its marketing and support cheerleaders do not candidly acknowledge them either.<br /><br />Validity checking can be disabled for all pages in web.config:<span style="font-family:courier new;font-size:85%;"><br><br /> <~system.web~><br /> <~pages buffer="true" validateRequest="true"<br /> enableEventValidation="false" /~><br /> <~/system.web~></span><br><br />Validity checking can be disabled for individual pages by adding markup attributes ValidateRequest="false" and EnableEventValidation="false" to Page directives. Although sometimes recommended by novices, these are usually poor approaches, since they will open major security holes in applications. Yet how else to prevent users from tripping across ugly error boxes? Microsoft does not advise, and neither do makers of third-party controls such as Telerik.<br /><br />Many such problems can be solved by strategic testing and design. Pages that contain bulky data or self-constructing controls must be tested aggressively to see whether early user action can cause errors. If such errors can occur, then controls that would provoke them need to be kept hidden until a page's controls have all been processed by a browser. The trouble-provoking controls are often buttons, but any control that is configured to generate a postback or an AJAX callback may be the source of a problem.<br /><br />To hide a control, in markup add the option "visibility: hidden" to its Style attribute. At the end of the markup for a page, add a JavaScript block such as: <span style="font-family:courier new;font-size:85%;"><br><br /> <~script type="text/javascript"~><br /> var oControl = document.getElementById<br /> ('<~% = ofControl.ClientID %~>');<br /> if (oControl != null)<br /> {<br /> oControl.style.visibility = 'visible';<br /> }<br /> <~/script~></span><br><br />In the example, ofControl matches the ID attribute of a control that can trigger a postback and is initially hidden. The JavaScript block makes these controls visible. By the time it does so a browser will have processed a page's controls, and they should be prepared to participate correctly in a postback.<br /><br />[Note: because of display limitations, characters "< " and " >" here are shown with a tilde ~ after or before them.]Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-78766437637785464072006-12-05T09:49:00.000-05:002006-12-05T10:19:34.008-05:00Web delivery and its discontentsPromises of Web delivery of applications have been circulating for years, but until ASP.NET 2.0 and its tools the technologies could rarely produce a credible and maintainable product. Microsoft has not been eating its own cooking from this kitchen. None of its major applications has been reimplemented for Web delivery. Lack of responsiveness comparable to client-based and client-server applications may have provoked the troubled "Atlas" effort, which at this juncture looks to be all hat and no cattle.<br /><br />In favorable circumstances, AJAX technology can remedy the lack of responsiveness from Web delivery. There are two proven success cases: point update of a limited display from a large backing store, and continuous update of display borders to produce smooth scroll. However, AJAX is uncomfortable for software writers, because it disrupts orderly processing to gain performance.<br /><br />Some vendors have been grandly promoting AJAX "frameworks" that more nearly resemble plaster patches for bunions. These home remedies all aim to reduce the amount of cookbook coding to process AJAX callbacks, but some, including Microsoft's and Telerik's, also try to relieve discomfort by providing orderly processing.<br /><br />Results show one can't have it both ways. We recall "cold fusion," "artificial intelligence" and their great ancestor "perpetual motion." The overhead of orderly processing sacrifices the performance potential and yields nothing that anyone can take to the bank.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-33865809079653197652006-12-04T04:56:00.000-05:002006-12-08T08:49:31.506-05:00Quo vadis server transfer?Nearly all professional quality Web Forms applications use Server.Transfer to switch pages rather than the easily hijacked cross-page posting approach. But when running under IIS in a virtual directory, where does Server.Transfer transfer?<br /><br />With IIS 6.0, Server.Transfer stays within the same virtual directory if there is no directory component to the page path. A directory component may specify either a different virtual directory or a subdirectory. For an application contained within a single directory, only the original URL accessing the first page specifies the virtual directory.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-1164211113334973852006-11-22T10:55:00.000-05:002006-11-24T05:15:41.946-05:00Debug ASP.NET 2.0 running under IIS 6.0Visual Studio 2005 Professional or Team Edition can perform remote debugging of an ASP.NET 2.0 Web Forms application running in its prime deployment environment, Internet Information Services (IIS) 6.0 on a Windows Server 2003 R2 platform. However, sloppy Microsoft technical writers and their dimwitted managers have made it a labor of experimental programming to find out how to do this. Their documentation on the topic is scattered across many articles and notes, omitting critical information that may be known to some Microsoft insiders but will be neither known nor obvious to experienced application developers and system administrators. We found that an MSDN support engineer could not explain how to do remote debugging under IIS 6.0 and that so-called "experts" from the MSDN Visual Studio Debugger Forum could not explain it either.<br /><br />A key element is that to debug remotely the server running IIS 6.0 and the development machine running Visual Studio 2005 (Pro or Team) must have Administrator accounts with the same user name and password. The Visual Studio Remote Debugger must be started on the server or run as a service under this user name and password, and the user at the development machine must be logged in under the same user name and password. Otherwise Visual Studio 2005 will fail to connect with the server. Some Microsoft documentation claims that the server must be operating in a network domain, but that is not necessary. A domain is a convenient way to distribute account identification, but the server can also be in a workgroup. Visual Studio Remote Debugger must be installed on the server directly from Visual Studio 2005 Pro or Team media, either CD or DVD. Some Microsoft documentation claims it can be installed from a development computer, but that is not true with any standard installation of Visual Studio 2005.<br /><br />Installation of Visual Studio Remote Debugger is provided by rdbgsetup.exe, located on the CD "Disc 2" in the Remote Debugger directory and on the DVD in the vs\Remote Debugger directory and in the x86, x64 or IA64 subdirectory that matches the server processor. An installation wizard provides an option to install a service. With that approach, it is necessary to visit the Visual Studio Remote Debugger service from Control Panel/Administrative Tools/Services and bring up a context menu with the alternate mouse button to access its Property page. On the Property page under the Log On tab enter the key user name and password, and under the General tab change Start Up from Disabled to Manual or Automatic. After exiting the Property page start the server from the context menu. If not installed as a service in this way, the Visual Studio Remote Debugger must be started prior to debugging by logging on the server under the key user name and password and launching msvsmon.exe from directory \Program Files\Microsoft Visual Studio 8\Common7\IDE\Remote Debugger on the system drive and the subdirectory that matches the server processor.<br /><br />To debug an application running under IIS 6.0, source code must be placed on the server. A published build with source code only on the development machine but not on the server will not debug. By using a server share, Visual Studio 2005 can access an application Web site’s directories on the server and will build the application. A permission error that it may report at the end of the build can be ignored. Before building, the Debug option must be included in the web.config file for the application. Before debugging, an option in the IIS properties for the application must also be enabled. This is found by visiting Control Panel/Administrative Services/Internet Information Services, expanding Web Sites, selecting the application and then selecting Properties from a context menu. Under the ASP.NET tab, the Edit Configuration button brings up an ASP.NET Configuration Settings dialog. Under the Application tab of this dialog the Enable Debugging option must be checked.<br /><br />Before trying to debug, make sure that the application pool and Web site are running by looking on the server using Control Panel/Administrative Services/Internet Information Services and checking the status shown when selecting Application Pools and Web Sites. If either is not running, select it and start it from a context menu. Using Visual Studio 2005 on a development machine, bring up the source code for the application that is located on the server. In this view of the application, breakpoints can be set in the code. Attach Visual Studio 2005 to the IIS 6.0 worker process, using Debug/Attach to Process. The appropriate Transport option is Default, and the Qualifier option is the network name of the server. The IIS 6.0 worker process under Available Processes will have the name w3wp.exe. Select this process and click the Attach button. Launch the application from the development machine by pointing Internet Explorer to the Web site, using its network address. Visual Studio 2005 does not do this automatically. When the code reaches a breakpoint, Visual Studio 2005 will show the same debugging display that it does when using its built-in server and will step through the code and show watchpoint information in the same ways.<br /><br />While debugging under IIS 6.0, the worker process is stopped whenever the code is on break. That causes any other session or Web site in the same IIS 6.0 application pool to stop. For this reason, it is best to perform remote debugging with a dedicated test server, if available, or to set up a separate application pool for testing.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com3tag:blogger.com,1999:blog-23447909.post-1157307507321485452006-09-03T14:18:00.000-04:002006-09-03T14:18:27.323-04:00Conveniences of controlsAs one of its undisclosed "features" ASP.NET 2.0 will conveniently inhibit control events when you try to use "too many" of them. For example, suppose you need to confirm a user action and also validate that the user has specified an action to take. You might think you could use a standard approach -- a JavaScript function for OnClientClick with a Button and a RequiredFieldValidator in the < body > section of your .aspx file:<br /><br /> < script type="text/javascript" ><br /> function ConfirmActivate()<br /> {<br /> var bConfirm = confirm('Confirm Activate');<br /> return bConfirm;<br /> }<br /> < /script ><br /> <br /> < asp:Button ID="ofButtonActivate" runat="server"<br /> Style="left: 8px; position: absolute; top: 24px;"<br /> Text="Activate" Width="176px" OnClick="Activate_Click"<br /> ValidationGroup="Test" Font-Size="Large"<br /> OnClientClick="return ConfirmActivate()" / ><br /> <br /> < Asp:TextBox ID="ofTextActivate" runat="server"<br /> Style="left: 200px; position: absolute; top: 24px"<br /> Height="24px" Width="600px" / ><br /> <br /> < asp:RequiredFieldValidator ID="ofValidActivate"<br /> runat="server" ControlToValidate="ofTextActivate" <br /> ErrorMessage="Selection required" ValidationGroup="Test" / ><br /> <br /> < asp:ValidationSummary ID="ofValidSummary" runat="server"<br /> ShowSummary="False" ShowMessageBox="True"<br /> ValidationGroup="Test" / ><br /><br /><br />Apparently Microsoft doesn't think your users should be bothered with "too many" messages, so ASP.NET 2.0 will conveniently inhibit the ValidationSummary, and no popup message will appear. One solution is to take out the validators and provide your own validation in JavaScript, for example:<br /><br /> function ConfirmActivate()<br /> {<br /> var oTextActivate = document.<br /> getElementById('< % = ofTextActivate.ClientID % >');<br /> var oText = oTextActivate.value;<br /> if (oText == null || oText.length < 1)<br /> {<br /> alert('Activation name required');<br /> return false;<br /> }<br /> var bCancel = confirm('Please confirm Activate');<br /> return bCancel;<br /> }<br /><br /><br />[Note: because of display limitations, characters "< " and " >" here are shown with a space after or before them.]Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-1156006030388736882006-08-19T12:45:00.000-04:002006-08-19T12:47:10.403-04:00Reference to the wiseA Russian-born friend, now a U.S. citizen, has a watchword for software systems. "The most important things," he says, "are never written down."<br /><br />Hardly a better example can be found than documentation of the ASP.NET 2.0 collection classes. Many such classes, including all the hobbled C++ imitators that Microsoft calls "generic collections" in C#, accept objects -- or rather, references to objects. What they collect is merely the references. This probably seemed so obvious to Microsoft writers that they did not think to mention it, but neither did the redoubtable Herb Schildt, in his book on C# 2.0 laughingly labeled "The Complete Reference."<br /><br />Although it is possible to write copy-constructors in C# just as one usually does in C++, Microsoft does not provide default copy-constructors or use copy-constructors in its ASP.NET interfaces. Omission of copy-constructors as a routine practice makes it tricky to produce collections like those of C++ providing copy-semantics. Microsoft does not seem to have tried. Its practices extend to the collections implemented for visual controls such as TemplateGroupCollection, yielding interesting consequences.<br /><br />Experiments suggest that all ASP.NET collections accepting reference types will accept duplicate references without an exception and are unprotected against changes to the referenced objects after they have been added. In some situations, such as user interfaces, effects of adding duplicate references or changing an object after a reference to it has been added can depend on timing and may be unpredictable.<br /><br />In all but special circumstances, therefore, rules of thumb for peaceful coexistence with ASP.NET 2.0 collections have to be: add only unique objects, and don't change objects after adding them to these collections.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-1153999406555890612006-07-27T07:21:00.000-04:002006-07-28T09:12:27.623-04:00Panel DynamicsBrowser renderings of data and controls can produce dynamic displays that traditional client-side applications could only hope for. Particularly useful is a scrollable collection of controls, including ones such as buttons that produce actions. In a sterling example of cuteness and opacity, Microsoft's ASP.NET 2.0 documentation hints that creating such a display might be possible but won't tell you how to do it. Neither will the usually helpful Dino Esposito, although his book "Programming ASP.NET 2.0 Core Reference" does have a sentence explaining that dynamic controls must be regenerated each time a page loads (see page 113).<br /><br />Microsoft recommends its PlaceHolder as a container for dynamic controls, but that is a dead object, offering no mobility. Much more useful is Panel, which can provide both horizontal and vertical scrolling. Action controls inside a Panel operate normally as long as they are visible, no matter where they may be moved on the display.<br /><br />Each action control has one or more collections of event handlers. Button has Click, CheckBox has CheckChanged, and so on. Server-side event handler functions are connected to the corresponding events by adding a delegate in C#. To get the events from dynamic controls, the code to create the controls and specify their event handler functions can be placed in the Page_Load function and must execute every time. For example, using a statically declared Panel:<br /><br />In the .aspx markup --<br /> < asp:Panel id="ofPanelView" runat="server" ><br /><br />In the .aspx.cs Page_Load function --<br /> ControlCollection oControls = ofPanelView.Controls;<br /> oControls.Clear();<br /> Button oSpecialButton1 = new Button();<br /> oSpecialButton1.CommandName = "1";<br /> oSpecialButton1.Click += new System.EventHandler(SpecialButton_Click);<br /> oControls.Add(oSpecialButton1);<br /> Button oSpecialButton2 = new Button();<br /> oSpecialButton2.CommandName = "2";<br /> oSpecialButton2.Click += new System.EventHandler(SpecialButton_Click);<br /> oControls.Add(oSpecialButton2);<br /><br />Elsewhere in the .aspx.cs code --<br /> SpecialButton_Click(object sender, EventArgs e)<br /> { string sCommandName = ((Button)sender).CommandName;<br /> . . .<br /><br />If you will be changing a pattern of dynamic controls for a page, then you must also assign the .ID property of each control and do so in a consistent way, so that on postback values and events will be paired with corresponding server-side objects. If a pattern of dynamic controls does not change, default ID values will do the job.<br /><br /><br />[Note: because of display limitations, characters "< " and " >" here are shown with a space after or before them.]Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-1152029431913965182006-07-04T12:07:00.001-04:002006-07-04T12:12:24.133-04:00DIV and conquerASP.NET 2.0 becomes most unfriendly to JavaScript when you want to change the visibility of Web form controls. Documentation won't explain how to do this, but it's simple. Set style.visibility to "visible" or "hidden" for most browsers. Problems arise when you want to change controls such as CheckBox or RadioButton that generate multiple elements, an input and a label in these cases. Addressing a control in the usual way affects only one element. In these cases, it does not change the label.<br /><br />The solution is to put an HTML DIV element around one or more controls that you want to change, such as:<br /><br />< div id="ofDivCheck23" style="visibility: hidden" runat="server" ><br /> < asp:CheckBox ID="ofCheck23" runat="server" Text="Report Required" / ><br />< /div ><br /><br />Be sure to put "id" in lower case, or Visual Studio 2005 will bark at you with a diagnostic such as "Error...name contains uppercase characters, which is not allowed," a rule routinely violated by its own markups.<br /><br />With such a div element in place, show or hide everything that it brackets with JavaScript statements such as:<br /><br />var oDivCheck23 = document.getElementById('< % = ofDivCheck23.ClientID % >');<br />var oCheckEnabled = document.getElementById('< % = ofCheckEnabled.ClientID % >');<br />if (oCheckEnabled.checked == true)<br />{<br /> oDivCheck23.style.visibility = "visible";<br />}<br />else<br />{<br /> oDivCheck23.style.visibility = "hidden";<br />}<br /><br />[Note: because of display limitations, characters "< " and " >" here are shown with a space after or before them.]Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-1151629823900950592006-06-29T21:09:00.000-04:002006-06-29T21:10:23.913-04:00Say it in ChineseExpressing binary information by using text characters has always been wasteful. The simplest solutions use octal or hexadecimal representations, and they waste half or more of storage space or transmission bandwidth. In a Unicode environment like that provided by ASP.NET 2.0, the bloat is much worse.<br /><br />A Unicode environment, however, permits a safe and relatively efficient alternative, using the segment of the 16-bit code points occupied by the "Unihan" characters. Set the high-order two bits of each character to 01, and use the low-order fourteen bits for binary data. Data expressed in this way will populate 16K of the 27K code points assigned by 16-bit Unicode to Chinese characters. Data bit efficiency is 87.5 percent.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0tag:blogger.com,1999:blog-23447909.post-1151010622308961642006-06-22T17:09:00.000-04:002006-06-22T17:13:31.886-04:00Lightly crossing pagesThe Server.Transfer method is an efficient way to transition between pages under server control, but it transmits no parameters to specify a context. There are indirect ways to do this with added costs in performance and data management. However, the C# language provides data transfer with no added programming or overhead, provided the destination page knows the type of the origin page. Simply declare and assign public members in the origin page and use their values in the destination page. This is made possible by the PreviousPage property of the Page class, the strong typing of C# and the run-time type identification system.<br /><br />In a Login page, for example, declare a member such as m_ilUserTag to identify a validated user:<br /><br />public partial class Login : System.Web.UI.Page<br />{<br /> public long m_ilUserTag = 0;<br /><br />Once a user is validated, assign an identifier value to m_ilUserTag and transfer to the Home page:<br /><br /> Server.Transfer("Home.aspx");<br /><br />The Home page can pick up the value of m_ilUserTag directly. For example:<br /><br /> protected void Page_Load(object sender, EventArgs e)<br /> {<br /> object oObject = (object)PreviousPage;<br /> Login oLoginPage = (Login)oObject;<br /> long ilUserTag = oLoginPage.m_ilUserTag;<br /><br />Although you might think that the reference to the Page base class furnished by PreviousPage could be cast immediately to the Login derived class, Visual Studio 2005 will bark at that with a diagnostic such as "Error...Cannot convert type 'System.Web.UI.Page' to 'System.Web.UI.WebControls.Login'." If you pass the reference through the type, object, it's happy. RTTI will check validity of the cast and throw an exception if PreviousPage did not reference a Login object.Craig Bolonhttp://www.blogger.com/profile/14569851577673286112noreply@blogger.com0