Web Q&A

ADO.NET Joins, HTML to XHTML, ASP.NET ViewState, and More

Edited by Nancy Michell

Q Back in ADO, Remote Data Service (RDS) allowed a developer to write a query to join tables, make changes to the data which was returned, and then send the changes back to the database with a simple call. In other words, it figured out which columns came from which table and made the changes to the right table. Does ADO.NET only support "smart" updates for queries of single tables, not queries involving joins?

Q Back in ADO, Remote Data Service (RDS) allowed a developer to write a query to join tables, make changes to the data which was returned, and then send the changes back to the database with a simple call. In other words, it figured out which columns came from which table and made the changes to the right table. Does ADO.NET only support "smart" updates for queries of single tables, not queries involving joins?

A Yes, that's the case. DataAdapter can send changes from a DataSet/DataTable to a back-end source if the DataTable is associated with a single base table. In all other cases, the user has to write custom Update, Delete, and Insert commands.

A Yes, that's the case. DataAdapter can send changes from a DataSet/DataTable to a back-end source if the DataTable is associated with a single base table. In all other cases, the user has to write custom Update, Delete, and Insert commands.

Keep in mind that the ADO cursor engine's updating logic for join queries was extremely simplistic. You had little control over the behavior, which was a problem for inserts and deletes against a joined recordset. In the ADO.NET world, breaking up the data into separate queries, storing the results in separate DataTables, and relating the data through a DataRelation gives you much more control over your updates as well as better performance.

Q How can I use a contentEditable DIV to capture user input on a Web page and then do a client-side XSLT transformation to convert the DIV's innerHTML into a Microsoft® Word XML document? The problem is that a contentEditable DIV exposes deprecated HTML (which is not valid XML) via its innerHTML property. So XSLT transformations are not possible without first converting the HTML. My preference would be to do this using client-side script, but I'd consider using server-side C# code, too.

Q How can I use a contentEditable DIV to capture user input on a Web page and then do a client-side XSLT transformation to convert the DIV's innerHTML into a Microsoft® Word XML document? The problem is that a contentEditable DIV exposes deprecated HTML (which is not valid XML) via its innerHTML property. So XSLT transformations are not possible without first converting the HTML. My preference would be to do this using client-side script, but I'd consider using server-side C# code, too.

A TidyCOM is a third-party library that you can call from client-side script or put on a server to use in your ASP.NET page.

A TidyCOM is a third-party library that you can call from client-side script or put on a server to use in your ASP.NET page.

Also, check out the following document for information about converting HTML to XHTML: Converting HTML documents to XHTML. InfoPath has a custom implementation that even cleans the HTML generated by Microsoft Office into something much cleaner.

Another option is to use Chris Lovett's SgmlReader 1.4 or the InfoPath™ SDK's html2XHTML COM DLL. (For more information on its usage, see Using the HTML to XHTML Conversion Tool.)

Q I have implemented a Web site that makes heavy use of ASP.NET ViewState to which my developers have added custom hidden variables. Now I'd like to move the view state from a hidden variable in the Web page to either a file or database on the server by using the SaveStateToPersistenceMedium and LoadPageStateFromPersistenceMedium methods. Are there any known performance issues with these methods?

Q I have implemented a Web site that makes heavy use of ASP.NET ViewState to which my developers have added custom hidden variables. Now I'd like to move the view state from a hidden variable in the Web page to either a file or database on the server by using the SaveStateToPersistenceMedium and LoadPageStateFromPersistenceMedium methods. Are there any known performance issues with these methods?

A Remember that view state operates on a per-page basis; Session is per user and Cache is per application. So, if a user opens a new window on a form from the file menu (File | New Window), he has two view states (one in each browser window). Each view state will behave independently, but there is only one session, which can lead to some problems. For instance, if you store view state on the server, you still need to have a reference to it on the client in a hidden field so that you can get back to the state of the controls when the form is posted back to the server. In this respect it would be similar to storing a session cookie on the client.

A Remember that view state operates on a per-page basis; Session is per user and Cache is per application. So, if a user opens a new window on a form from the file menu (File | New Window), he has two view states (one in each browser window). Each view state will behave independently, but there is only one session, which can lead to some problems. For instance, if you store view state on the server, you still need to have a reference to it on the client in a hidden field so that you can get back to the state of the controls when the form is posted back to the server. In this respect it would be similar to storing a session cookie on the client.

The fact is that with view state on the client there are as many view states as there are browser windows open. Assuming you use the session object to hold on to the view state for a page on the server, there is an implicit assumption that the user has only one copy of the page at a time in a session. Thus, with view state on the server, you get only one copy, which can potentially lead to problems. Since the view state may not correspond to what the user was seeing on their screen, all of the actions that depend on view state will start to fail. Change events may not fire correctly, the controls may be drawn differently, and so on.

The net result of this is that to do what you want, you'll still have to store a unique identifier in the page rendered to the client so that you can later associate the view state stored on the server with the same page on post back.

Q On a Web page served over HTTPS, the referenced style sheets and JavaScript files don't work. What am I doing wrong?

Q On a Web page served over HTTPS, the referenced style sheets and JavaScript files don't work. What am I doing wrong?

A The Knowledge Base article 825057 ("Internet Explorer Incorrectly Displays Web Pages") addresses the problem when the following conditions are true: the Advanced setting "Do not save encrypted pages to disk" is selected, the Web page uses the HTTPS protocol, and you have turned on HTTP compression for cascading style sheet (CSS) and JavaScript files on the Web server.

A The Knowledge Base article 825057 ("Internet Explorer Incorrectly Displays Web Pages") addresses the problem when the following conditions are true: the Advanced setting "Do not save encrypted pages to disk" is selected, the Web page uses the HTTPS protocol, and you have turned on HTTP compression for cascading style sheet (CSS) and JavaScript files on the Web server.

Generally, you should be able to hit CSS files and JavaScript files from HTTPS requests using either HTTP or HTTPS (as appropriate to your particular situation). You should turn off the compression to alleviate the problem.

Of course, if you have frames or popups that are trying to interact, then you probably have cross-site scripting errors as a result of the page having the document.domain of beta.dev.ms.com and the JavaScript files having a document.domain of dev.ms.com. The following article tells you how to get them to communicate by setting their domain properties to the same value: domain Property .

Q I have a main page with three sections: header, left menu, and content section. I'm developing a portal that will show content from multiple third-party sites. That content appears along with its own menus and headers. How can I pull in the content from those sites (ASPX pages) and use them within my framework without using frames or iframes?

Q I have a main page with three sections: header, left menu, and content section. I'm developing a portal that will show content from multiple third-party sites. That content appears along with its own menus and headers. How can I pull in the content from those sites (ASPX pages) and use them within my framework without using frames or iframes?

A You should have the third-party sites do one of two things: either provide the content in a manner that is easy for you to consume, such as through a Web service or even RSS Syndication, or ensure that the layout and structure of the pages won't change so you can use a regular expressions to screen scrape and parse out the desired content. With either a Web service or an RSS feed, the third-party can even use these distribution mechanisms internally on their own sites, further encouragement for them to provide the content in a nice easy format for everyone to consume.

A You should have the third-party sites do one of two things: either provide the content in a manner that is easy for you to consume, such as through a Web service or even RSS Syndication, or ensure that the layout and structure of the pages won't change so you can use a regular expressions to screen scrape and parse out the desired content. With either a Web service or an RSS feed, the third-party can even use these distribution mechanisms internally on their own sites, further encouragement for them to provide the content in a nice easy format for everyone to consume.

Q I have a lot of mission-critical applications written in ASP and Visual Basic® 6.0 and I'd like to have those apps consume ASP.NET Web services. How can these legacy applications interface with ASP.NET Web services?

Q I have a lot of mission-critical applications written in ASP and Visual Basic® 6.0 and I'd like to have those apps consume ASP.NET Web services. How can these legacy applications interface with ASP.NET Web services?

A Have a look at the following documents for help: "Integrating Web Services and COM Components", "SOAP-Toolkit 3.0" (deprecated by the .NET Framework), and "PocketSOAP" (OpenSource—MPL).

A Have a look at the following documents for help: "Integrating Web Services and COM Components", "SOAP-Toolkit 3.0" (deprecated by the .NET Framework), and "PocketSOAP" (OpenSource—MPL).

The SOAP Toolkit makes consuming Web services very easy even without relying on the .NET Framework. However, all you really need is the ability to build an XML string that conforms to the SOAP spec and send it over HTTP to the client. You can even do this using client-side script using the MSXML parser which has been built into Microsoft Internet Explorer for several versions. See Knowledge Base article 555057 ("How to Call a .NET Web Service from Client Side JavaScript Using Internet Explorer and MSXML"). If you need to support additional browsers, you can even cover Netscape 6.0 and up using its native support (though you need to do a couple of overrides of the supplied behavior to make your code look less ugly). If you can build a string and send it over HTTP, then you can consume a Web service. The easiest solution will depend on where you need to consume them. You could arguably just create an assembly to encapsulate the Web service call and expose it via COM interop. It all depends on your priorities and constraints.

Another available option is to use the Web service behavior that is explained at WebService Behavior . The page states that the WebService behavior enables methods that are implemented on Web services to be called from client-side script in a Web page using Internet Explorer 5.0 and later. In order to attach a WebService behavior to a page, you must first download the WebService HTC file and put a copy in the same directory as the pages that use the behavior.

Q I'm developing an ASP.NET Web tool for my team. I am using Server.Transfer to handle page reposts (using a new query). However, I get a view state corruption error if I leave the page idle for more than 20 minutes and try to resubmit. As I understand, view state should be kept on the client side and shouldn't have a timeout, right? I used Response.Redirect too, but the problem doesn't go away. I have set the default of "shutdown worker processes after being idle for 20 minutes" on IIS.

Q I'm developing an ASP.NET Web tool for my team. I am using Server.Transfer to handle page reposts (using a new query). However, I get a view state corruption error if I leave the page idle for more than 20 minutes and try to resubmit. As I understand, view state should be kept on the client side and shouldn't have a timeout, right? I used Response.Redirect too, but the problem doesn't go away. I have set the default of "shutdown worker processes after being idle for 20 minutes" on IIS.

A Do you happen to have an idle timeout set on your worker process? You are most likely autogenerating your validation key, which means that when you create a ViewStateMac, append it to the end of your view state, and send it to your client, it will only be valid for that instance of the AppDomain. Once the AppDomain restarts, a new validation key is generated and your POST will result in ASP.NET believing the view state is invalid since the ViewStateMACs do not hash the same. To mitigate the problem, remove the idle shutdown and hardcode your validation key.

A Do you happen to have an idle timeout set on your worker process? You are most likely autogenerating your validation key, which means that when you create a ViewStateMac, append it to the end of your view state, and send it to your client, it will only be valid for that instance of the AppDomain. Once the AppDomain restarts, a new validation key is generated and your POST will result in ASP.NET believing the view state is invalid since the ViewStateMACs do not hash the same. To mitigate the problem, remove the idle shutdown and hardcode your validation key.

Q How can I disable the Back button so my Web visitors don't get the page-expired warning?

Q How can I disable the Back button so my Web visitors don't get the page-expired warning?

A Unless you are hosting the WebBrowser control, you can't effectively stop the use of the Back button. See Knowledge Base article 811603 ("Use the Forward Button and the Back Button for WebBrowser Control in Visual Basic .NET") if you need more info on using the control.

A Unless you are hosting the WebBrowser control, you can't effectively stop the use of the Back button. See Knowledge Base article 811603 ("Use the Forward Button and the Back Button for WebBrowser Control in Visual Basic .NET") if you need more info on using the control.

You can implement an Internet Explorer restriction if you have total control of the client base and if Internet Explorer is your only browser, of course. See Knowledge Base article 823057 ("The Restrictions that are Available to Internet Explorer 6.0 SP1") for more information. If you launch your page in a new window each time, the Back button on that page will be unavailable. You can also script the new window to have no toolbars.

Q What are the best practices for designing a browser-based interface for use with a number of commercial business solutions exposed by Web services, all of which share a common architecture and processing model? Do I create specific interfaces for each solution or just one? How do I address the need to authenticate against the same Web site using Windows® integrated security and forms-based authentication for the public domain?

Q What are the best practices for designing a browser-based interface for use with a number of commercial business solutions exposed by Web services, all of which share a common architecture and processing model? Do I create specific interfaces for each solution or just one? How do I address the need to authenticate against the same Web site using Windows® integrated security and forms-based authentication for the public domain?

A The single request method approach is not a great idea, although there are plenty of instances where it has been successfully used. At a minimum it would be better to have one or more methods per logical grouping (customer info, account info, and so forth).

A The single request method approach is not a great idea, although there are plenty of instances where it has been successfully used. At a minimum it would be better to have one or more methods per logical grouping (customer info, account info, and so forth).

In building sites with the same requirement, one of two scenarios is usually the case. The easy one is where there is a separate IIS-based intranet for internal users, and a DMZ server running IIS for external users. There you have separate servers and separate authentication models, so it's straightforward.

It sounds like you're involved in the more complex case in which you have the same server for both groups of users. A successful approach in this scenario is to set up the site to require domain credentials, but then change the 401 error handling in IIS to point to your page of choice (since the 401 is one of the few errors that you apparently can't trap programmatically), and have that page redirect to the forms login page (since the page at which you point the 401 error must be HTML, not ASP).

This allows the internal users to access the site with their domain credentials and not require a login, while the external users are shown a login page, all from the same site. The Active Directory® Application Mode (ADAM) can be used for the public domain authentication store, which will work quite well .

If you are writing an ASP.NET Web app (not a Web service), then creating a solution that combines forms-based authentication and Windows integrated authentication isn't that hard. To do so, you'll need to write an HttpModule that uses the supplied Forms and Windows modules and then set it all up in the config file.

When you are finished, Thread.CurrentPrincipal will be either a GenericPrincipal or a WindowsPrincipal (depending on how the user was authenticated), and the current identity's AuthenticationType lets you know how the user was authenticated.

Q I have an ASP.NET Web site and I'm getting script errors when I have cache breakers in my ASPX files. Sample cache-breaker code looks like the following:

<script language="javascript" type="text/javascript" src="blah.js?<%=System.DateTime.Now %>"> </script>

I run into this script error when the ASPX page is requested repeatedly on the same browser session. How can I include such cache-breaking code in order to avoid proxies caching my pages over an extended period of time?

Q I have an ASP.NET Web site and I'm getting script errors when I have cache breakers in my ASPX files. Sample cache-breaker code looks like the following:

<script language="javascript" type="text/javascript" src="blah.js?<%=System.DateTime.Now %>"> </script>

I run into this script error when the ASPX page is requested repeatedly on the same browser session. How can I include such cache-breaking code in order to avoid proxies caching my pages over an extended period of time?

A If you have an idea of how often this file will change, or has changed over the last month, you could just tell IIS to set the expiration header on the file for a predetermined amount of time. If the file does not change on a regular schedule this may not work.

A If you have an idea of how often this file will change, or has changed over the last month, you could just tell IIS to set the expiration header on the file for a predetermined amount of time. If the file does not change on a regular schedule this may not work.

If you want to prevent proxies from caching this file for an extended period of time, you can configure IIS to set the expiration date for a relative time in the future (such as three days from the time being requested). Proxies (and clients) should not rerequest the file until that three-day period has elapsed (or the user explicitly requests a fresh copy).

When using just the date of the file, some proxies will maintain a history of how many times they requested the file and how many times it has changed during that period. They will then apply that knowledge and only request the file when their best guess has told them that it may have new content.

Other clients will request the file with a "If-Modified-Since" header, but they will send a request every time. The server will either send the file or send a "304 Not Modified" response, telling the client to used their cached copy. You could also change the JavaScript file to an ASPX file and return a "304 Not Modified" from the ASPX code when you don't have any changes to send to the client. Before you proceed, however, you should note that manually setting the Cache-Control header is a bit harder than letting IIS do it, which is what it does when you manipulate the "Enable Content Expiration" setting on the dialog shown in Figure 1.

Figure 1 Manipulating the Expiration Setting

Figure 1** Manipulating the Expiration Setting **

Incidentally, this is the same dialog you'd use to manually add the Cache-Control header. For more information on this, see Caching ASP.NET Pages.

Got a question? Send questions and comments to  webqa@microsoft.com.

Thanks to  the following Microsoft developers for their technical expertise: Jay Allen, Kawarjit Bedi, Andrew Blair-Stanek, Harold Campos (Intl Vendor), Todd Carter, Ulrich Dallmann, Doug DeFonzo, Nathan Dolly, Russ Helfand, Ken Henderson, CJ Huang, Mark Ingalls, Chris Jackson, David Koronthaly, Vijay Kurup (Infosys Technologies Ltd), Karlen Lie, Brian MacKay, John Mann, Alan Melia, David Sceppa, Willy-Peter Schaub, Aaron Sethi, Norman Sequeira, Vittal Setty (Infosys Technologies Ltd), Ranjiv Sharma, Ken Stanfield, Devdatta Waghdhare, Dennis Wang, Phil Winstanley (Business Guest), Victus Wong, and Tsan Zheng.