January 21st, 2009
January 16th, 2009
December 1st, 2008
November 28th, 2008
http://msdn.microsoft.com/en-us/lib
November 14th, 2008
November 7th, 2008
November 6th, 2008
I am using SQL Server 2005 and trying to create a linked server on Oracle 10. I used the commands below:
EXEC
sp_addlinkedserver@server
= 'test1',@srvproduct
= 'Oracle',@provider
= 'MSDAORA',@datasrc
= 'testsource'exec
sp_addlinkedsrvlogin@rmtsrvname
= 'test1',@useself
= 'false',@rmtuser
='sp',@rmtpassword
='sp'November 1st, 2008
October 31st, 2008
October 30th, 2008
October 13th, 2008
Сайт занимающийся координацией людей, желающих выучить иностранный язык. Т.е. сводящий двух носителей языка вместе, что бы они могли пообщаться и выучить язык.
October 3rd, 2008
Debugging ASP.NET AJAX Applications
Dan Wahlin
The ability to debug code is a skill that every developer should have in their arsenal regardless of the technology they’re using. It goes without saying that understanding the different debugging options that are available can save a tremendous amount of time on a project and perhaps even a few headaches. While many developers are accustomed to using Visual Studio .NET or Web Developer Express to debug ASP.NET applications that use VB.NET or C# code, some aren’t aware that it’s also extremely useful for debugging client-side code such as JavaScript. The same type of techniques used to debug .NET applications can also be applied to AJAX-enabled applications and more specifically ASP.NET AJAX applications.
In this article you’ll see how Visual Studio 2008 Beta 2 and several other tools can be used to debug ASP.NET AJAX applications to quickly locate bugs and other issues. This discussion will include information about enabling Internet Explorer 6 or higher for debugging, using Visual Studio 2008 and the Script Explorer to step through code as well as using other free tools such as Web Development Helper. You’ll also learn how to debug ASP.NET AJAX applications in Firefox using an extension named Firebug which lets you step through JavaScript code directly in the browser without any other tools. Finally, you’ll be introduced to classes in the ASP.NET AJAX Library that can help with various debugging tasks such as tracing and code assertion statements.
Before you try to debug pages viewed in Internet Explorer there are a few basic steps you’ll need to perform to enable it for debugging. Let’s take a look at some basic setup requirements that need to be performed to get started.
Configuring Internet Explorer for Debugging
Most people aren’t interested in seeing JavaScript issues encountered on a Website viewed with Internet Explorer. In fact, the average user wouldn’t even know what to do if they saw an error message. As a result, debugging options are turned off by default in the browser. However, it’s very straightforward to turn debugging on and put it to use as you develop new AJAX applications.
To enable debugging functionality, go to Tools à Internet Options on the Internet Explorer menu and select the Advanced tab. Within the Browsing section ensure that the following items are unchecked:
- Disable script debugging (Internet Explorer)
- Disable script debugging (Other)
Although not required, if you’re trying to debug an application you’ll probably want any JavaScript errors in the page to be immediately visible and obvious. You can force all errors to be shown with a message box by checking the "Display a notification about every script error" checkbox. While this is a great option to turn on while you’re developing an application, it can quickly become annoying if you’re just perusing other Websites since your chances of encountering JavaScript errors are pretty good.
Figure 1 shows what the Internet Explorer advanced dialog should look after it has been properly configured for debugging.
Figure 1: Configuring Internet Explorer for debugging. (Click to view full-size image)
Once debugging has been turned on, you’ll see a new menu item appear in the View menu named Script Debugger. It has two options available including Open and Break at Next Statement. When Open is selected you’ll be prompted to debug the page in Visual Studio 2008 Beta 2 (note that Visual Web Developer Express can also be used for debugging). If Visual Studio .NET is currently running you can choose to use that instance or to create a new instance. When Break at Next Statement is selected you’ll be prompted to debug the page when JavaScript code is executed. If JavaScript code executes in the onLoad event of the page you can refresh the page to trigger a debug session. If JavaScript code is run after a button is clicked then the debugger will run immediately after the button is clicked.
Note: if you are running on Windows Vista with User Access Control (UAC) enabled, and you have Visual Studio 2008 set to run as an administrator, Visual Studio will fail to attach to the process when you are prompted to attach. To work around this issue, start Visual Studio first, and use that instance to debug.
Although the next section will demonstrate how to debug an ASP.NET AJAX page directly from within Visual Studio 2008, using the Internet Explorer Script Debugger option is useful when a page is already open and you’d like to more fully inspect it.
Debugging with Visual Studio 2008 Beta 2
Visual Studio 2008 Beta 2 provides debugging functionality that developers around the world rely on everyday to debug .NET applications. The built-in debugger allows you to step through code, view object data, watch for specific variables, monitor the call stack plus much more. In addition to debugging VB.NET or C# code, the debugger is also helpful for debugging ASP.NET AJAX applications and will allow you to step through JavaScript code line by line. The details that follow focus on techniques that can be used to debug client-side script files rather than providing a discourse on the overall process of debugging applications using Visual Studio 2008.
The process of debugging a page in Visual Studio 2008 can be started in several different ways. First, you can use the Internet Explorer Script Debugger option mentioned in the previous section. This works well when a page is already loaded in the browser and you’d like to start debugging it. Alternatively, you can right-click on an .aspx page in the Solution Explorer and select Set As Start Page from the menu. If you’re accustomed to debugging ASP.NET pages then you’ve probably done this before. Once F5 is pressed the page can be debugged. However, while you can generally set a breakpoint anywhere you’d like in VB.NET or C# code, that’s not always the case with JavaScript as you'll see next.
Embedded Versus External Scripts
The Visual Studio 2008 debugger treats JavaScript embedded in a page different than external JavaScript files. With external script files, you can open the file and set a breakpoint on any line you choose. Breakpoints can be set by clicking in the grey tray area to the left of the code editor window. When JavaScript is embedded directly into a page using the <script> tag, setting a breakpoint by clicking in the grey tray area isn’t an option. Attempts to set a breakpoint on a line of embedded script will result in a warning that states "This is not a valid location for a breakpoint".
You can get around this issue by moving the code into an external .js file and referencing it using the src attribute of the <script> tag:
<script type="text/javascript" src="Scripts/YourScript.js"></script> What if moving the code into an external file isn’t an option or requires more work than it's worth? While you can’t set a breakpoint using the editor, you can add the debugger statement directly into the code where you’d like to start debugging. You can also use the Sys.Debug class available in the ASP.NET AJAX library to force debugging to start. You’ll learn more about the Sys.Debug class later in this article.
An example of using the debugger keyword is shown in Listing 1. This example forces the debugger to break right before a call to an update function is made.
Listing 1. Using the debugger keyword to force the Visual Studio .NET debugger to break.
function BuildPerson() { var person = { FirstName: $get("txtFirstName").value, LastName: $get("txtLastName").value, Address: { Street: $get("txtStreet").value, City: $get("txtCity").value, State: $get("txtState").value } }; debugger; UpdatePerson(person); } Once the debugger statement is hit you will be prompted to debug the page using Visual Studio .NET and can begin stepping through the code. While doing this you may encounter an issue with accessing ASP.NET AJAX library script files used in the page so let's take a look at using Visual Studio .NET's Script Explorer.
Using Visual Studio .NET Windows to Debug
Once a debug session is started and you begin walking through code using the default F11 key, you may encounter the error dialog shown in see Figure 2 unless all script files used in the page are open and available for debugging.
Figure 2: Error dialog shown when no source code is available for debugging. (Click to view full-size image)
This dialog is shown because Visual Studio .NET isn't sure how to get to the source code of some of the scripts referenced by the page. While this can be quite frustrating at first, there's a simple fix. Once you have started a debug session and hit a breakpoint, go to the Debug à Windows à Script Explorer window on the Visual Studio 2008 menu or use the Ctrl+Alt+N hotkey.
Note: If you can’t see the Script Explorer menu listed, go to Tools à Customize à Commands on the Visual Studio .NET menu. Locate the Debug entry in the Categories section and click it to show all available menu entries. In the Commands list, scroll down to Script Explorer and then drag it up onto the Debug à Windows menu in mentioned earlier. Doing this will make the Script Explorer menu entry available each time you run Visual Studio .NET.
The Script Explorer can be used to view all scripts used in a page and open them in the code editor. Once the Script Explorer is open, double-click on the .aspx page currently being debugged to open it in the code editor window. Perform the same action for all of the other scripts shown in the Script Explorer. Once all of the scripts are open in the code window you can press F11 (and use the other debug hotkeys) to step through your code. Figure 3 shows an example of the Script Explorer. It lists the current file being debugged (Demo.aspx) as well as two custom scripts and two scripts dynamically injected into the page by the ASP.NET AJAX ScriptManager.
Figure 3. The Script Explorer provides easy access to scripts used in a page. (Click to view full-size image)
Several others windows can also be used to provide useful information as you step through code in a page. For example, you can use the Locals window to see the values of different variables used in the page, the Immediate window to evaluate specific variables or conditions and view the output. You can also use the Output window to view trace statements written out using the Sys.Debug.trace function (which will be covered later in this article) or Internet Explorer’s Debug.writeln function.
As you step through code using the debugger you can mouse over variables in the code to view the value that they are assigned. However, the script debugger occasionally won’t show anything as you mouse over a given JavaScript variable. To see the value, highlight the statement or variable you’re trying to see in the code editor window and then mouse over it. Although this technique doesn’t work in every situation, many times you will be able to see the value without having to look in a different debug window such as the Locals window.
A video tutorial demonstrating some of the features discussed here can be viewed at http://www.xmlforasp.net.
Debugging With Web Development Helper
Although Visual Studio 2008 (and Visual Web Developer Express 2008) are very capable debugging tools, there are additional options that can be used as well which are more light-weight. One of the latest tools to be released is the Web Development Helper. Microsoft’s Nikhil Kothari (one of the key ASP.NET AJAX architects at Microsoft) wrote this excellent tool which can perform many different tasks from simple debugging to viewing HTTP request and response messages. Web Development Helper can be downloaded at http://projects.nikhilk.net/Projects/Web
Web Development helper can be used directly inside of Internet Explorer which makes it convenient to use. It’s started by selecting Tools à Web Development Helper from the Internet Explorer menu. This will open the tool in the bottom portion of the browser which is nice since you don’t have to leave the browser to perform several tasks such as HTTP request and response message logging. Figure 4 shows what Web Development Helper looks like in action.
Figure 4: Web Development Helper (Click to view full-size image)
Web Development helper isn’t a tool you’ll use to step through code line by line as with Visual Studio 2008. However, it can be used to view trace output, easily evaluate variables in a script or explore data is inside of a JSON object. It’s also very useful for viewing data that is passed to and from an ASP.NET AJAX page and a server.
Once Web Development Helper is open in Internet Explorer, script debugging must be enabled by selecting Script à Enable Script Debugging from the Web Development helper menu as shown earlier in Figure 4. This enables the tool to intercept errors that occur as a page is run. It also allows easy access to trace messages that are output in the page. To view trace information or execute script commands to test different functions within a page, select Script à Show Script Console from the Web Development Helper menu. This provides access to a command window and a simple immediate window.
Viewing Trace Messages and JSON Object Data
The immediate window can be used to execute script commands or even load or save scripts that are used to test different functions in a page. The command window displays trace or debug messages written out by the page being viewed. Listing 2 shows how to write a trace message using Internet Explorer’s Debug.writeln function.
Listing 2. Writing out a client-side trace message using the Debug class.
function BuildPerson() { var person = { FirstName: $get("txtFirstName").value, LastName: $get("txtLastName").value, Address: { Street: $get("txtStreet").value, City: $get("txtCity").value, State: $get("txtState").value } }; Debug.writeln("Person name: " + person.LastName); UpdatePerson(person); } If the LastName property contains a value of Doe, Web Development Helper will display the message "Person name: Doe" in the script console’s command window (assuming that debugging has been enabled). Web Development Helper also adds a top-level debugService object into pages that can be used to write out trace information or view the content of JSON objects. Listing 3 shows an example of using the debugService class’s trace function.
Listing 3. Using Web Development Helper’s debugService class to write a trace message.
function BuildPerson() { var person = { FirstName: $get("txtFirstName").value, LastName: $get("txtLastName").value, Address: { Street: $get("txtStreet").value, City: $get("txtCity").value, State: $get("txtState").value } }; if (window.debugService) { window.debugService.trace("Per son name: " + person.LastName); } UpdatePerson(person); } A nice feature of the debugService class is that it will work even if debugging isn’t enabled in Internet Explorer making it easy to always access trace data when Web Development Helper is running. When the tool isn’t being used to debug a page, trace statements will be ignored since the call to window.debugService will return false.
The debugService class also allows JSON object data to be viewed using Web Development Helper’s inspector window. Listing 4 creates a simple JSON object containing person data. Once the object is created, a call is made to the debugService class’s inspect function to allow the JSON object to be visually inspected.
Listing 4. Using the debugService.inspect function to view JSON object data.
function BuildPerson() { var person = { FirstName: $get("txtFirstName").value, LastName: $get("txtLastName").value, Address: { Street: $get("txtStreet").value, City: $get("txtCity").value, State: $get("txtState").value } }; if (window.debugService) { window.debugService.inspect("P erson Object",person); } UpdatePerson(person); } Calling the GetPerson() function in the page or through the immediate window will result in the Object Inspector dialog window appearing as shown in Figure 5. Properties within the object can be changed dynamically by highlighting them, changing the value shown in the Value text box and then clicking the Update link. Using the Object Inspector makes it straightforward to view JSON object data and experiment with applying different values to properties.
Debugging Errors
In addition to allowing trace data and JSON objects to be displayed, Web Development helper can also aid in debugging errors in a page. If an error is encountered, you will be prompted to continue to the next line of code or debug the script (see Figure 6). The Script Error dialog window shows the complete call stack as well as line numbers so you can easily identify where issues are within a script.
Figure 5: Using the Object Inspector window to view a JSON object. (Click to view full-size image)
Selecting the debug option allows you to execute script statements directly in Web Development Helper’s immediate window to view the value of variables, write out JSON objects, plus more. If the same action that triggered the error is performed again and Visual Studio 2008 is available on the machine, you will be prompted to start a debug session so that you can step through the code line by line as discussed in the previous section.
Figure 6: Web Development Helper’s Script Error Dialog (Click to view full-size image)
Inspecting Request and Response Messages
While debugging ASP.NET AJAX pages it is often useful to see request and response messages sent between a page and server. Viewing the content within messages allows you to see if the proper data is being passed as well as the size of the messages. Web Development Helper provides an excellent HTTP message logger feature that makes it easy to view data as raw text or in a more readable format.
To view ASP.NET AJAX request and response messages, the HTTP logger must be enabled by selecting HTTP à Enable HTTP Logging from the Web Development Helper menu. Once enabled, all messages sent from the current page can be viewed in the HTTP log viewer which can be accessed by selecting HTTP à Show HTTP Logs.
Although viewing the raw text sent in each request/response message is certainly useful (and an option in Web Development Helper), it is often easier to view message data in a more graphical format. Once HTTP logging has been enabled and messages have been logged, message data can be viewed by double-clicking on the message in the HTTP log viewer. Doing this allows you to view all headers associated with a message as well as the actual message content. Figure 7 shows an example of a request message and response message viewed in the HTTP Log Viewer window.
Figure 7: Using the HTTP Log Viewer to view request and response message data. (Click to view full-size image)
The HTTP Log Viewer automatically parses JSON objects and displays them using a tree view making it quick and easy to view the object’s property data. When an UpdatePanel is being used in an ASP.NET AJAX page, the viewer breaks out each portion of the message into individual parts as shown in Figure 8. This is a great feature that makes it much easier to see and understand what is in the message as compared to viewing the raw message data.
Figure 8: An UpdatePanel response message viewed using the HTTP Log Viewer. (Click to view full-size image)
There are several other tools that can be used to view request and response messages in addition to Web Development Helper. Another good option is Fiddler which is available for free at http://www.fiddlertool.com. Although Fiddler will not be discussed here, it is also a good option when you need to thoroughly inspect message headers and data.
Debugging with Firefox and Firebug
While Internet Explorer is still the most widely used browser, other browsers such as Firefox have become quite popular and are being used more and more. As a result, you’ll want to view and debug your ASP.NET AJAX pages in Firefox as well as Internet Explorer to ensure that your applications work properly. Although Firefox can’t tie directly into Visual Studio 2008 for debugging, it has an extension called Firebug that can be used to debug pages. Firebug can be downloaded for free by going to http://www.getfirebug.com.
Firebug provides a full-featured debugging environment that can be used to step through code line by line, access all scripts used within a page, view DOM structures, display CSS styles and even track events that occur in a page. Once installed, Firebug can be accessed by selecting Tools à Firebug à Open Firebug from the Firefox menu. Like Web Development Helper, Firebug is used directly in the browser although it can also be used as a stand-alone application.
Once Firebug is running, breakpoints can be set on any line of a JavaScript file whether the script is embedded in a page or not. To set a breakpoint, first load the appropriate page you’d like to debug in Firefox. Once the page is loaded, select the script to debug from Firebug’s Scripts drop-down list. All scripts used by the page will be shown. A breakpoint is set by clicking in Firebug’s grey tray area on the line where the breakpoint should go must like you would do in Visual Studio 2008.
Once a breakpoint has been set in Firebug you can perform the action required to execute the script that needs to be debugged such as clicking a button or refreshing the browser to trigger the onLoad event. Execution will automatically stop on the line containing the breakpoint. Figure 9 shows an example of a breakpoint that has been triggered in Firebug.
Figure 9: Handling breakpoints in Firebug. (Click to view full-size image)
Once a breakpoint is hit you can step into, step over or step out of code using the arrow buttons. As you step through code, script variables are displayed in the right-hand portion of the debugger allowing you to see values and drill-down into objects. Firebug also includes a Call Stack drop-down list to view the script’s execution steps that led up to the current line being debugged.
Firebug also includes a console window that can be used to test different script statements, evaluate variables and view trace output. It is accessed by clicking on the Console tab at the top of the Firebug window. The page being debugged can also be "inspected" to see its DOM structure and contents by clicking on the Inspect tab. As you mouse over the different DOM elements shown in the inspector window the appropriate portion of the page will be highlighted making it easy to see where the element is used in the page. Attribute values associated with a given element can be changed "live" to experiment with applying different widths, styles, etc. to an element. This is a nice feature that saves you from having to constantly switch between the source code editor and the Firefox browser to view how simple changes affect a page.
Figure 10 shows an example of using the DOM inspector to locate a textbox named txtCountry in the page. The Firebug inspector can also be used to view CSS styles used in a page as well as events that occur such as tracking mouse movements, button clicks, plus more.
Figure 10: Using Firebug’s DOM inspector. (Click to view full-size image)
Firebug provides a light-weight way to quickly debug a page directly in Firefox as well as an excellent tool for inspecting different elements within the page.
Debugging Support in ASP.NET AJAX
The ASP.NET AJAX library includes many different classes that can be used to simplify the process of adding AJAX capabilities into a Webpage. You can use these classes to locate elements within a page and manipulate them, add new controls, call Web Services and even handle events. The ASP.NET AJAX library also contains classes that can be used to enhance the process of debugging pages. In this section you’ll be introduced to the Sys.Debug class and see how it can be used in applications.
Using the Sys.Debug class
The Sys.Debug class (a JavaScript class located in the Sys namespace) can be used to perform several different functions including writing trace output, performing code assertions and forcing code to fail so that it can be debugged. It is used extensively in the ASP.NET AJAX library’s debug files (installed at C:\Program Files\Microsoft ASP.NET\ASP.NET 2.0 AJAX Extensions\v1.0.61025\MicrosoftAjaxLibra
The Sys.Debug class exposes several different functions that can be used to handle tracing, code assertions or failures as shown in Table 1.
Table 1. Sys.Debug class functions.
| Function Name | Description |
| assert(condition, | Asserts that the condition parameter is true. If the condition being tested is false, a message box will be used to display the message parameter value. If the displayCaller parameter is true, the method also displays information about the caller. |
| clearTrace() | Erases statements output from tracing operations. |
| fail(message) | Causes the program to stop execution and break into the debugger. The message parameter can be used to provide a reason for the failure. |
| trace(message) | Writes the message parameter to the trace output. |
| traceDump(object, | Outputs an object’s data in a readable format. The name parameter can be used to provide a label for the trace dump. Any sub-objects within the object being dumped will be written out by default. |
Client-side tracing can be used in much the same way as the tracing functionality available in ASP.NET. It allows different messages to easily be seen without interrupting the flow of the application. Listing 5 shows an example of using the Sys.Debug.trace function to write to the trace log. This function simply takes the message that should be written out as a parameter.
Listing 5. Using the Sys.Debug.trace function.
function BuildPerson() { var address = new XmlForAsp.Address($get("txtStreet").valu e, $get("txtCity").value, $get("txtState").value, $get("txtZip").value); var person = new XmlForAsp.Person(null, $get("txtFirstName").value, $get("txtLastName").value, address); Sys.Debug.trace("Person's name: " + person.get_firstName() + " " + person.get_lastName()); UpdatePerson(person); } If you execute the code shown in Listing 5 you won't see any trace output in the page. The only way to see it is to use a console window available in Visual Studio .NET, Web Development Helper or Firebug. If you do want to see the trace output in the page then you'll need to add a TextArea tag and give it an id of TraceConsole as shown next:
<textArea id="TraceConsole" rows="10" cols="50"></textArea> Any Sys.Debug.trace statements in the page will be written to the TraceConsole TextArea.
In cases where you want to see the data contained within a JSON object you can use the Sys.Debug class's traceDump function. This function takes two parameters including the object that should be dumped to the trace console and a name that can be used to identify the object in the trace output. Listing 6 shows an example of using the traceDump function.
Listing 6. Using the Sys.Debug.traceDump function.
function UpdatePerson(person) { //Dump contents of the person object to the trace output Sys.Debug.traceDump(person,"Per son Data"); alert("Person updated! " + person.get_firstName() + " " + person.get_lastName()); } Figure 11 shows the output from calling the Sys.Debug.traceDump function. Notice that in addition to writing out the Person object's data, it also writes out the Address sub-object's data.
In addition to tracing, the Sys.Debug class can also be used to perform code assertions. Assertions are used to test that specific conditions are met while an application is running. The debug version of the ASP.NET AJAX library scripts contain several assert statements to test a variety of conditions.
Listing 7 shows an example of using the Sys.Debug.assert function to test a condition. The code tests whether or not the Address object is null before updating a Person object.
Figure 11: Output of the Sys.Debug.traceDump function. (Click to view full-size image)
Listing 7. Using the debug.assert function.
function UpdatePerson(person) { //Check if address is null Sys.Debug.assert(person.get_add ress() == null,"Address is null!",true); alert("Person updated! " + person.get_firstName() + " " + person.get_lastName()); } Three parameters are passed including the condition to evaluate, the message to display if the assertion returns false and whether or not information about the caller should be displayed. In cases where an assertion fails, the message will be displayed as well as caller information if the third parameter was true. Figure 12 shows an example of the failure dialog that appears if the assertion shown in Listing 7 fails.
The final function to cover is Sys.Debug.fail. When you want to force code to fail on a particular line in a script you can add a Sys.Debug.fail call rather than the debugger statement typically used in JavaScript applications. The Sys.Debug.fail function accepts a single string parameter that represents the reason for the failure as shown next:
Sys.Debug.fail("My forced failure of script."); Figure 12: A Sys.Debug.assert failure message. (Click to view full-size image)
When a Sys.Debug.fail statement is encountered while a script is executing, the value of the message parameter will be displayed in the console of a debug application such as Visual Studio 2008 and you'll be prompted to debug the application. One case where this can be quite useful is when you can't set a breakpoint with Visual Studio 2008 on an inline script but would like the code to stop on particular line so you can inspect the value of variables.
Understanding the ScriptManager Control's ScriptMode Property
The ASP.NET AJAX library includes debug and release script versions that are installed at C:\Program Files\Microsoft ASP.NET\ASP.NET 2.0 AJAX Extensions\v1.0.61025\MicrosoftAjaxLibra
The ScriptManager control added to ASP.NET AJAX pages reads the compilation element's debug attribute in web.config to determine which versions of library scripts to load. However, you can control if debug or release scripts are loaded (library scripts or your own custom scripts) by changing the ScriptMode property. ScriptMode accepts a ScriptMode enumeration whose members include Auto, Debug, Release and Inherit.
ScriptMode defaults to a value of Auto which means that the ScriptManager will check the debug attribute in web.config. When debug is false the ScriptManager will load the release version of ASP.NET AJAX library scripts. When debug is true the debug version of the scripts will be loaded. Changing the ScriptMode property to Release or Debug will force the ScriptManager to load the appropriate scripts regardless of what value the debug attribute has in web.config. Listing 8 shows an example of using the ScriptManager control to load debug scripts from the ASP.NET AJAX library.
Listing 8. Loading debug scripts using the ScriptManager.
<asp:ScriptManager ID="ScriptManager1" runat="server" ScriptMode="Debug"></asp:ScriptManager> You can also load different versions (debug or release) of your own custom scripts by using the ScriptManager's Scripts property along with the ScriptReference component as shown in Listing 9.
Listing 9. Loading custom scripts using the ScriptManager.
<asp:ScriptManager ID="ScriptManager1" runat="server"> <Scripts> <asp:ScriptReference Path="~/Scripts/Person.js" ScriptMode="Debug"/> </Scripts> </asp:ScriptManager> Note: If you’re loading custom scripts using the ScriptReference component you must notify the ScriptManager when the script has finished loading by adding the following code at the bottom of the script:
if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded(); The code shown in Listing 9 tells the ScriptManager to look for a debug version of the Person script so it will automatically look for Person.debug.js instead of Person.js. If the Person.debug.js file is not found an error will be raised.
In cases where you want a debug or release version of a custom script to be loaded based upon the value of the ScriptMode property set on the ScriptManager control, you can set the ScriptReference control's ScriptMode property to Inherit. This will cause the proper version of the custom script to be loaded based upon the ScriptManager's ScriptMode property as shown in Listing 10. Because the ScriptMode property of the ScriptManager control is set to Debug, the Person.debug.js script will be loaded and used in the page.
Listing 10. Inheriting the ScriptMode from the ScriptManager for custom scripts.
<asp:ScriptManager ID="ScriptManager1" runat="server" ScriptMode="Debug"> <Scripts> <asp:ScriptReference Path="~/Scripts/Person.js" ScriptMode="Inherit"/> </Scripts> </asp:ScriptManager> By using the ScriptMode property appropriately you can more easily debug applications and simplify the overall process. The ASP.NET AJAX library's release scripts are rather difficult to step through and read since code formatting has been removed while the debug scripts are formatted specifically for debugging purposes.
Conclusion
Microsoft’s ASP.NET AJAX technology provides a solid foundation for building AJAX-enabled applications that can enhance the end user’s overall experience. However, as with any programming technology, bugs and other application issues will certainly arise. Knowing about the different debugging options available can save a lot of time and result in a more stable product.
In this article you’ve been introduced to several different techniques for debugging ASP.NET AJAX pages including Internet Explorer with Visual Studio 2008, Web Development Helper and Firebug. These tools can simplify the overall debugging process since you can access variable data, walk through code line by line and view trace statements. In addition to the different debugging tools discussed, you also saw how the ASP.NET AJAX library’s Sys.Debug class can be used in an application and how the ScriptManager class can be used to load debug or release versions of scripts.
Occasionally the debate will come as to when it's OK to use type inference in order to declare a variable. There appear to be three groups in this debate.
- Whenever it's possible
- Only when it's absolutely clear what the type is
- Never, type inference is evil
I fall into camp #1 and here are my reasons
- It does not reduce type safety. This doesn't allow for any late binding, type unsafe functions or the like. It simply lets the compiler chose the type for you.
- It will actually increase type safety in your code. The best example of this is the foreach statement on non-generic IEnumerable instances. These foreach statements are all technically unsafe because the compiler must do a cast of the Current member under the hood. This declaration looks no different than the type safe generic version of IEnumerable. Using var will force you to write an explicit cast.
foreach (SomeType cur in col)
foreach ( var cur in col.Cast<SomeType>())
- Maintains the principles of DRY. This is mostly true for cases where you have an explicit constructor on the RHS.
- For some types, this is a requirement in order to use the type (anonymous types for instance). I'm a big fan of consistency and since I must have some instances use type inference, I'd like to use them everywhere.
- Makes refactoring easier. I re-factor, a lot. I constantly split up or rename types. Often in such a way that refactoring tools don't fixup all of the problems. With var declarations I don't have to worry because they just properly infer their new type and happily chug along. For explicit type cases I have to manually update all of the type names.
- Less typing with no loss of functionality.
The best argument I've heard against type inference is that it reduces readability since you can't look at a variable and know it's type. True, but just hover over the declaration and the IDE will display the type. Yes this is not possible with a non-IDE editor but how often do you use one?
ASP.NET AJAX in Action
by Alessandro Gallo, David Barkol, and Rama Vavilala
View on Amazon
Introducing Microsoft ASP.NET AJAX
by Dino Esposito
View on Amazon
Professional ASP.NET 2.0 AJAX
by Matt Gibbs and Dan Wahlin
View on Amazon
LINQ Farm: LINQ to XML and Line Numbers
There are times when it is useful to know the line number of a node in an XML file. This information can be a helpful to users, particularly if you want to report an error. It can also be convenient to search for a node by line number, but that can, of course, be a very risky endeavor, as documents can be modified accidentally, and their line numbers changed without notice.
This post shows a few fundamentals about working with line numbers in a LINQ to XML program. The code shown in this post is taken from a project called XmlLineNumber. You can download this program from the LINQ Farm on Code Gallery.
Reporting a Line Number
Let’s begin our exploration by detailing a technique for reporting the number of a node that you have found in an XML file. To get started we need to use code from a class called XObject. As shown in Figure 1, XObject sits at the top of the LINQ to XML class hierarchy.
Figure 1: The core objects in the LINQ to XML class hierarchy
XObject implements an interface called IXmlLineInfo:
public interfaceIXmlLineInfo
{
int LineNumber { get; }
int LinePosition { get; }
bool HasLineInfo();
}
The eponymous LineNumber property of this interface is able to store the information we want. To enlist it in our service we need only call XDocument.Load with LoadOptions.SetLineInfo:
XDocument xml = XDocument.Load(fileName, LoadOptions.SetLineInfo);
If you load this XML file into memory using SetLineInfo from the LoadOptions enumeration, then line numbers will be associated with the nodes in your document. The file we are loading is called FirstFourPlanets.xml. It’s a sweet little file that looks like this:
<?xmlversion="1.0" encoding="utf-8"?>
<Planets>
<Planet>
<Name>Mercury</Name>
<Moons/>
</Planet>
<Planet>
<Name>Venus</Name>
<Moons/>
</Planet>
<Planet>
<Name>Earth</Name>
<Moons> <Moon>
<Name>Moon</Name>
<OrbitalPeriod UnitsOfMeasure="days">27.321582</OrbitalPeriod>
</Moon>
</Moons>
</Planet>
<Planet>
<Name>Mars</Name>
<Moons>
<Moon>
<Name>Phobos</Name>
<OrbitalPeriod UnitsOfMeasure="days">0.318</OrbitalPeriod>
</Moon>
<Moon>
<Name>Deimos</Name>
<OrbitalPeriod UnitsOfMeasure="days">1.26244</OrbitalPeriod>
</Moon>
</Moons>
</Planet>
</Planets>
Here is code that uses the IXmlLineInfo interface to report the line number of a node discovered through a standard LINQ to XML search:
XText phobos = (from x in xml.DescendantNodes().OfType<XText>() where x.Value == "Phobos" select x).Single(); var lineInfo = (IXmlLineInfo)phobos; Console.WriteLine("{0} appears on line {1}", phobos, lineInfo.LineNumber);
This code looks through all the descendants of the root node for nodes of type XText which are equal to the word Phobos. It uses the LINQ query operator Single to ensure that the query returns only a single node. If the query returned more than one result, the call to Single would raise an exception, which in this case is the behavior we want. The program then casts the result as an instance of IXmlLineInfo, and reports the line number to the user:
Phobos appears on line 24
Searching by Line Number
Let's now turn things around and show how to search through an XML file and look for a node by line number. If you glance at the FirstFourPlanets.xml file, you will see that line 21 looks like this:
<Name>Mars</Name>
Here is code from the XmlLineNumbers sample showing how to search for that node by line number:
XDocument xml = XDocument.Load(fileName, LoadOptions.SetLineInfo); var line = from x in xml.Descendants() let lineInfo = (IXmlLineInfo)x where lineInfo.LineNumber == 21 select x; foreach (var item in line) { Console.WriteLine(item); }
Note that the first line uses LoadOptions.SetLineInfo to ensures that line information is recorded when the document is loaded into memory.
The LINQ query shown here uses Descendants to iterate over the elements in the FirstFourPlanets.xml file. The where filter in the query checks to see if any of those elements has its line number set to 21. It happens that the 15th element returned by the call to Descendants fits that search criteria, and so that node, and that node alone, is found when we foreach over the results.
Notice the cast to convert the XElement nodes returned by the call to Descendants:
let lineInfo = (IXmlLineInfo)x This cast is necessary, since the actual fields of the IXmlLineInfo interface are not exposed by XElement.
Once again, I want to stress that reporting the line number of a node seems like a reasonable thing to do, but searching for an element by line number is usually not a good idea in production code. For unexplained reasons, code that was on line 532 has a way of migrating to line 533 when you least expect it. In any case, you now know enough to begin working with line numbers in a LINQ to XML program.
Download the source.
Я уже рассказывал о том, что для построения веб-сервисов, кроме наиболее популярного подхода SOAP, существует другой подход – REST. Очень удачной для реализации REST-сервисов является технология ADO.NET Data Services. Однако, для построения REST-сервисов мы также можем воспользоваться и Windows Communication Foundation. Давайте посмотрим каким образом.
Прежде чем рассматривать инструменты для построения REST-сервисов WCF, давайте вспомним отличительные черты таких сервисов. Любой веб-сервис на базе REST: 1) позволяет через Web (а именно поверх HTTP/HTTPS) предоставить доступ к данным; 2) каждый блок некоторой информации, предоставляемый через REST-сервис однозначно адресуется с помощью URI; 3) результатом работы такого сервиса будет некий XML документ (RSS, Atom, ..), т.е. feed и вспомогательные данные (бинарные, html, все что угодно).
Если к 1) и 3) пункту вопросов не возникает, то видно что 2) пункт явно не укладывается в идеологию WCF в том виде, в котором она существовала ранее. Т.е. если ранее мы могли как-то адресовать веб-сервисы, то на каждый URI нужно было описать публичный контракт и создать сервис. Однако, для REST-сервисов это критичный момент. Поэтому для реализации такой поддержки в составе WCF .NET Framework 3.5 появился целый HTTP API, который призван решить эти и другие проблемы.
В рамках HTTP API существуют такие важные классы как UriTemplate, UriTemplateMatch и UriTemplateTable. Именно этот набор классов позволяет осуществить маппинг конкретных URI на нужные операции. Несмотря на то, что эти объекты напрямую мы не используем, я думаю будет очень полезно для общего понимания посмотреть как они работают. Для этого давайте посмотрим следующий пример:
Uri address = new Uri(“http://localhost:8000”);
UriTemplate template = new UriTemplate(“{category}/{product}”);Uri boundUri = template.BindByPosition(address, “notebooks”, “lenovo-t61”);
Console.WriteLine(address.ToString()); // http://localhost:8000/notebooks/lenovo-t61Как видно, здесь мы задаем некий базовый URI и шаблон URI. Далее, используя полученный шаблон можно задать значение секций, которые определены в шаблоне. Как видим, в результате мы получаем URI вида “http://localhost:8000/notebooks/len
Как я уже говорил, эти объекты мы не используем напрямую, тем не менее они используются при маппинге URI на конкретную операцию.
Теперь, когда мы знаем как осуществляется маппинг, давайте рассмотрим каким образом можно построить REST-сервис на базе WCF. Для этого очень удобно пользоваться стандартным шаблоном при созданни проекта в VS2008 “Syndication Service Library”. Конечно, это не обязательное условие.
Построение публичного контракта. Для создания любого WCF-сервиса в первую очередь необходимо создать для него публичный контракт. REST-сервисы на базе WCF не исключение. Стандартный контракт в WCF для REST-сервиса выглядит следующим образом:
[ServiceContract]
[ServiceKnownType(typeof(Atom10FeedFormatter))][ServiceKnownType(typeof(Rss20FeedFormatter))]public interface IFeed1
{[OperationContract]
[WebGet(UriTemplate = "*")]SyndicationFeedFormatter CreateFeed();
// TODO: Add your service operations here}
В таком контракте, кроме стандартных атрибутов ServiceContract и OperationContract мы видим одно нововведение – атрибут WebGet. Именно с помощью этого атрибута мы можем указать какой URI соответствует какой операции. В приведенном примере все URI отображаются на единственную операцию – CreateFeed(). Давайте этот пример несколько модифицируем:
[ServiceContract]
[ServiceKnownType(typeof(Atom10FeedFormatter))][ServiceKnownType(typeof(Rss20FeedFormatter))]public interface IFeed1
{[OperationContract]
[WebGet(UriTemplate = "authors")]SyndicationFeedFormatter AuthorsFeed();
[WebGet(UriTemplate = "authors/{author}")] SyndicationFeedFormatter AuthorsFeed(string author);}
Теперь, в таком сервисе мы можем использовать два вида URI: “../feed1/authors” и “../feed1/authors/<имя автора>”. Причем при вызове того или иного URI, WCF автоматически определит какую операцию нужно вызвать, а во втором случае еще и передаст нужные параметры в метод (которые извлекаются из самого URI, помним объект UriTemplateMatch из HTTP API). Подобным образом мы можем создать нужное количество операций и определить для них те URI, которые нам необходимы.
Теперь давайте обратим внимание на тип возвращаемого операцией значения. В данном случае мы возвращаем некую ленту (feed). В поставке .NET 3.5 существуют два стандартных форматировщика – для RSS 2.0 и AtomPub 1.0. Однако, никто не мешает нам написать свои собственные форматировщики :).
Я уже говорил о том, что в рамках такого сервиса мы можем возвращать не только XML, но и вообще говоря любые данные, например, картинку. Для этого мы можем изменить контракт следующим образом:
[ServiceContract]
[ServiceKnownType(typeof(Atom10FeedFormatter))][ServiceKnownType(typeof(Rss20FeedFormatter))]public interface IFeed1
{[OperationContract]
[WebGet(UriTemplate = "authors")]SyndicationFeedFormatter AuthorsFeed();
[WebGet(UriTemplate = "authors/{author}")] SyndicationFeedFormatter AuthorsFeed(string author); [WebGet(UriTemplate = "authors/photo/{author}")] Stream AuthorPhoto(string author);}
В данном случае мы видим, что добавилась еще одна операция со своим URI, которая возвращает Stream. Внутри этого потока может быть что угодно, в т.ч. картинка.
Контракт готов, давайте перейдем к реализации самого сервиса. Собственно, сам сервис – это класс, реализующий наш публичный контракт. Здесь самое время поговорить об объектах SyndicationFeed и SyndicationItem – это объекты, являющются абстракциями ленты (feed) и ее содержимого. Наличие таких объектов позволяет нам не думать о конкретном формате ленты (RSS, Atom или еще что), а просто создать содержимое нашей ленты. Таким образом, метод AuthorsFeed() может выглядеть следующим образом:
public SyndicationFeedFormatter AuthorsFeed(){SyndicationFeed feed = new SyndicationFeed("Feed Title", "A WCF Syndication Feed", null);
List<SyndicationItem> items = new List<SyndicationItem>();items.Add(new SyndicationItem("Author1", "Author1. Age: 23.", null));
items.Add(new SyndicationItem("Author2", "Author2. Age: 26.", null));
feed.Items = items;
return new Rss20FeedFormatter(feed);
}
Как видно, здесь мы создаем ленту, наполняем ее содержимым и возвращаем конкретный форматировщик – в данном случае форматировщик RSS 2.0. Если мы хотим работать с AtomPub, можно несколько изменить реализацию метода:
public SyndicationFeedFormatter AuthorsFeed(){SyndicationFeed feed = new SyndicationFeed("Feed Title", "A WCF Syndication Feed", null);
// наполнение ленты содержимымreturn new Atom10FeedFormatter(feed);
}
Поскольку при реализации REST-сервиса мы имеем дело с HTTP, то мы можем оперировать с различными HTTP-сущностями, например HTTP-заголовками или GET-параметрами. Сделать это можно, используя объект WebOperationContext, который также входит в состав HTTP API. Таким образом, мы можем на основе значения GET-параметра выбирать нужный форматировщик:
public SyndicationFeedFormatter AuthorsFeed(){SyndicationFeed feed = new SyndicationFeed("Feed Title", "A WCF Syndication Feed", null);
// ...string query = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters["format"];
if (query == "atom")
{return new Atom10FeedFormatter(feed);
}
else {return new Rss20FeedFormatter(feed);
}
}
Точно также можно работать, например с HTTP-заголовками.
Однако, в рамках нашего REST-сервиса мы можем возвращать не только ленту, но и, как я уже упоминал, любые другие данные. Например изображение:
public Stream AuthorPhoto(string author)
{ MemoryStream result = new MemoryStream(); // заполнение потока WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg"; return result;}
Обратите внимание, в данном случае кроме того, что мы возвратили поток нужно установить значение HTTP-заголовка Content-Type. Это можно осуществить используя объект WebOperationContext. Подобным образом можно вернуть, например, некий html-код или что-то еще.
Мы посмотрели на то, каким образом мы можем предоставить доступ к данным в рамках нашего REST-сервиса. Однако, REST-подход предполагает не только получение данных, но и их модификацию. Для этого используются HTTP-методы POST, PUT и DELETE. Для того, чтобы реализовать это в рамках сервиса, необходимо пометить нашу операцию в рамках публичного контракта атрибутом WebInvoke, вместо WebGet. При этом потребуется указать какой метод используется (свойство Method) и шаблон URI, на который отображается наша операция. В остальном реализация метода зависит от семантики операции. Например, мы можем что-то изменить в нашем источнике.
Не смотря на большое количество текста, получившегося при написании поста, реализация REST-сервиса на базе WCF вовсе не сложное занятие. Заканчивая, хочется подвести небольшой итог. Если у нас есть некая объектая модель данных (будь то концептуальная модель Entity Framework или модель LINQ to SQL, либо что-то еще), то несомненно реализовать REST-сервис будет проще на базе ADO.NET Data Services. WCF Syndication имеет смысл использовать в тех сценариях, где данные не очень удобно представлять в виде объектных структур. Например, если мы хотим предоставить доступ к каким-то файлам в рамках файловой системы, удобнее будет построить REST-сервис на базе WCF. Т.о. используя WCF мы можем реализовывать более глубокие сценарии, нежели просто предоставление доступа к модели данных через Web.
Ну и напоследок. Вы можете посмотреть мой более подробный веб-каст на тему WCF Syndication на TechDays.ru. Кроме того, если тема вам интересна вы можете проголосовать за мои доклады на Платформе 2009, и конкретно за доклад про WCF Syndication, где я собираюсь рассказать о построении REST-сервисов на базе WCF чуть более глубже :).
Спасибо и удачи вам в построении ваших REST-сервисов :).
Сегодня отрыл в своих заметках «на будущее» интересную заметку по поводу работы вышеупомянутых функций в Microsoft SQL Server. Конечно же, многие знают эти моменты (те, кто всегда используют COALESCE могут дальше не читать :)) Однако мне приходилось переубеждать немало коллег, которые не любят COALESCE - «хуже читается и много буков». Пришло, видимо, время опубликовать – нужно же периодически напоминать про такие приколы, чтобы не забывали :)
Для начала, COALESCE, в отличие от ISNULL удовлетворяет стандарту ANSI. Не для всех довод весомый, но тем не менее…
Что касается сравнения производительности, отзывы разные (правда, разница в обе стороны небольшая), однако я как-то больше доверяю этому суждению.
И, собственно, есть еще одно весомое преимущество. Если передать первым аргументом нулевую строку с типом varchar(10), а вторым аргументом ненулевую строку с типом varchar(100), то результат обрежется до первых 10 символов.
Чтобы не быть многословным, приведу код, который вы просто можете запустить и посмотреть на результаты:
DECLARE @first varchar(2), @second varchar(4), @third int SELECT @first = NULL, @second = 'qwer', @third = 255 SELECT ISNULL(@first, @second), COALESCE(@first, @second), COALESCE(@second, @first) SELECT ISNULL(@first, @third), COALESCE(@first, @third) SET @third = NULL SELECT ISNULL(@third, @first) SELECT COALESCE(@third, @first)
using (var channelFactory = new ChannelFactory<IService1>(typeof(IService1).Name))
{
for (int i = 0; i < 100; i++)
{
var channel = channelFactory.CreateChannel();
channel.GetData(5);
Console.WriteLine(i + 1);
}
}
Впрочем количество одновременно доступных каналов можно изменить. Если сервис находится в вашем ведении (и написан на WCF), вы можете поменять следующие настройки в конфигурационном файле:
<behavior name="Throttled">
<serviceThrottling maxConcurrentCalls="100" maxConcurrentInstances="100" />
</behavior>
Ценой этого изменения будет увелечение ресурсов сервера, выделяемых пользователям сервиса. Понятно, что такой рост не может быть бесконечен, поэтому любой сервис будет стараться держать это значение как можно более низким.
Update: Важное замечание (спасибо alexey lavnikov) - конкретное поведение клиента и сервиса в значтильной степени зависит от используемого байндинга (привязки). Так, например, в случае использования basicHttpBinding или webHttpBinding клиент просто выведет все числа от 1 до 100. Выбор конкретного байндинга зависит от требований и имеет далекоидущие последствия.
Однако настройки сервиса, байндинга и используемые им ресурсы находятся за пределами данной серии постов.
Что для нас было важно отметить, так это что сервис имеет настройки ограничивающие клиентов. Если запустить два таких клиента, то исключение вы получите в два раза быстрее.
А теперь представьте, что этот код Вам не принадлежит. Этот код, пусть и не в таком наглядном виде написал Junior C# программист. Итак, система ушла на продакшн сервера с вашим кодом, который правильно использует сервис и кодом Junior'а, который является бомбой замедленного действия.
Готов ли Ваш код и ваше приложение выжить в таких условиях? Что увидят пользователи, когда сервис вдруг окажется недоступным? Как такое поведение отразится на количестве обслуживаемых пользователей?
Об этом в следующей части.



