Web Q&A

Get Authentication Type, Get Screen Resolution, and More

Edited by Nancy Michell

Q I have an authentication question: I'm using Windows® authentication for a Web site in one environment, and Passport authentication in another. If I check the following value to get the authentication type in Windows

HttpContext.Current.User.Identity.AuthenticationType 

sometimes an empty string is returned and sometimes "NTLM" is returned. Shouldn't it always return "NTLM"?

Q I have an authentication question: I'm using Windows® authentication for a Web site in one environment, and Passport authentication in another. If I check the following value to get the authentication type in Windows

HttpContext.Current.User.Identity.AuthenticationType 

sometimes an empty string is returned and sometimes "NTLM" is returned. Shouldn't it always return "NTLM"?

A This is by design. Once the client has an authenticated connec-tion, it does not need to send any credentials for subsequent requests on that connection. So if ASP.NET is pulling the data from the authentication header, then this header is not there. You can control this using the AuthPersistence setting in IIS. The AuthPersistence property specifies authentication persistence across requests on a connection using NTLM authentication.

A This is by design. Once the client has an authenticated connec-tion, it does not need to send any credentials for subsequent requests on that connection. So if ASP.NET is pulling the data from the authentication header, then this header is not there. You can control this using the AuthPersistence setting in IIS. The AuthPersistence property specifies authentication persistence across requests on a connection using NTLM authentication.

In IIS 6.0, when the AuthPersistSingleRequest flag is set to true and you are using NTLM authentication, IIS automatically reauthenticates every request, even requests that are coming over the same connection. Reauthenticating every request also occurs on all other authentication schemes. In IIS 5.0 and IIS 5.1, there are two other flags for the AuthPersistence property specifying persistence based on the existence of a proxy server. (See "AuthPersistence" in the MSDN Library for more information on this.)

Q On my Web site I need to have different menus for different user groups and hide or show menu options based on the user's group. I know that you can base a menu on a site map. Is there a way to do this programmatically for a session so that when a user logs in, the app determines the user's group and chooses an appropriate site map?

Q On my Web site I need to have different menus for different user groups and hide or show menu options based on the user's group. I know that you can base a menu on a site map. Is there a way to do this programmatically for a session so that when a user logs in, the app determines the user's group and chooses an appropriate site map?

A The site map providers will follow the security of the Web site if SecurityTrimmingEnabled="true" is set on the provider. The SecurityTrimmingEnabled setting indicates whether a site map provider filters site map nodes based on a user's role. This means that if you partition your Web site access based on roles, then the sitemap node visibility will respect the restrictions.

A The site map providers will follow the security of the Web site if SecurityTrimmingEnabled="true" is set on the provider. The SecurityTrimmingEnabled setting indicates whether a site map provider filters site map nodes based on a user's role. This means that if you partition your Web site access based on roles, then the sitemap node visibility will respect the restrictions.

Q I want to adapt my Web content (layout and picture resolution, for instance) based on the end user's screen resolution. How can I get a user's display settings?

Q I want to adapt my Web content (layout and picture resolution, for instance) based on the end user's screen resolution. How can I get a user's display settings?

A You can use the following script to get the screen resolution. Once you have the pixel count, you have the screen resolution:

<script language='javascript'>
function sendScreenInfo()
{
  FormID.scrWidth.value = window.screen.width;
  FormID.scrHeight.value = window.screen.height;
}
</script>

A You can use the following script to get the screen resolution. Once you have the pixel count, you have the screen resolution:

<script language='javascript'>
function sendScreenInfo()
{
  FormID.scrWidth.value = window.screen.width;
  FormID.scrHeight.value = window.screen.height;
}
</script>

Q I have an ASP.NET page that needs to access a repository of files located on another server within the same network. I tested my code using a Win32® application. However, when running the same code I get a "permission denied" exception because the IUSR_machinename account that ASP.NET uses does not have access to the server or folder where the repository is located. What is the best way to give read-only security access to the IUSR account so that it is able to read the data in the repository files?

Q I have an ASP.NET page that needs to access a repository of files located on another server within the same network. I tested my code using a Win32® application. However, when running the same code I get a "permission denied" exception because the IUSR_machinename account that ASP.NET uses does not have access to the server or folder where the repository is located. What is the best way to give read-only security access to the IUSR account so that it is able to read the data in the repository files?

A You can try the following: let's assume your Web server name is websrv1 and the computer with files is filesrv1. On filesrv1 create a folder, share it, and grant both share and access permissions to "NT AUTHORITY\Network Service" and "YOURNETWORK\webserv1$" (the computer account).

A You can try the following: let's assume your Web server name is websrv1 and the computer with files is filesrv1. On filesrv1 create a folder, share it, and grant both share and access permissions to "NT AUTHORITY\Network Service" and "YOURNETWORK\webserv1$" (the computer account).

To grant access to the computer account you will have to click on the Object Types button and put a checkmark next to Computer. This is assuming your websrv1 is running Windows Server™ 2003. If it's running Windows XP you will have to change your Machine.config to run ASP.NET as the Network Service account instead of from an ASPNET account.

Note that your ASP.NET code runs under the Network Service account's permissions, not IUSR_machinename. IUSR_machinename is used to determine if the user has access to that page or not, but the page's code runs as Network Service under Windows Server 2003 or ASPNET under Windows XP. An application will run as Network Service only unless you have <identity impersonate="true"> in your Web.config file. If you do, the application runs under the user that is requesting the page (or IUSR_machinename if user is anonymous).

Q My app is downloading large Zip files from IIS to a client computer and is attempting to show a download progress indicator while this is running. I attempted to determine the data size by reading the Content-Length HTTP header using the HttpQueryInfo function. However, the server failed to report the file size. Is there a way to force IIS to always include the Content-Length header for this to work?

Q My app is downloading large Zip files from IIS to a client computer and is attempting to show a download progress indicator while this is running. I attempted to determine the data size by reading the Content-Length HTTP header using the HttpQueryInfo function. However, the server failed to report the file size. Is there a way to force IIS to always include the Content-Length header for this to work?

A Although many HTTP responses include the Content-Length header, it is not a required component of a response. Unless you have another mechanism for getting the data size, you will not be able to calculate progress if the Content-Length header is not included in the response. (See Knowledge Base article 234913, "How To Provide Download/Upload Progress Information when Using WinInet," for more information.)

A Although many HTTP responses include the Content-Length header, it is not a required component of a response. Unless you have another mechanism for getting the data size, you will not be able to calculate progress if the Content-Length header is not included in the response. (See Knowledge Base article 234913, "How To Provide Download/Upload Progress Information when Using WinInet," for more information.)

However, you may have something running on your machine that's affecting this because, without outside influence, IIS will treat a Zip file as a static file, and IIS always adds a Content-Length header to a static file response. Check the machine for filters (and if it's IIS 6.0, check it for wildcard script-mapped extensions). Also, check to see if .zip is script-mapped to some handler.

If there is something other than the static file handler sending the response (and because there is no Content-Length, you can infer that there is), then it's up to that code to decide whether the Content-Length is appropriate. That said, it is perfectly normal, and a necessary part of HTTP, that the client has to be able to deal with an absent Content-Length header. Why do you want to make your client noncompliant? If you have control over the server, it is very possible to ensure that you always have Content-Length. If you think about it, there are two general ways to send things between server and client:

  1. Server tells the client to expect a specified number of bytes.
  2. Server tells the client to keep reading until special STOP sequence arrives.

Clearly in the first case, the client knows total size and what it has read, so a percentage is doable. In the second case, the client has no idea of the total size and thus cannot do a percentage.

As mentioned. if you are truly accessing a static file (such as https://server/file.htm), IIS will send Content-Length. The fact that you are not seeing Content-Length indicates that you need to look for another source of the problem.

Q I have a large DataGrid (60,000 items). There are two buttons that do other tasks not related to the DataGrid. After rendering the page and the DataGrid, if I click either button I get the following error:

Server Error in '/AdminTools' Application. 
Maximum request length exceeded. 

I set EnableViewState to False on the control, but that didn't help. In the Web.config I set <httpRuntime maxRequestLength="512000"/>, which fixes it, but that's rather clumsy and won't continue to work as the DataSet continues to grow. Is there a better solution?

Q I have a large DataGrid (60,000 items). There are two buttons that do other tasks not related to the DataGrid. After rendering the page and the DataGrid, if I click either button I get the following error:

Server Error in '/AdminTools' Application. 
Maximum request length exceeded. 

I set EnableViewState to False on the control, but that didn't help. In the Web.config I set <httpRuntime maxRequestLength="512000"/>, which fixes it, but that's rather clumsy and won't continue to work as the DataSet continues to grow. Is there a better solution?

A In a Web scenario, 60,000 items is too much data to display. Having so many items will cause a variety of problems including slow performance (even when the bandwidth is high), lots of data in view state (fortunately you have disabled it), and running up against the request limit. Of course, the request limit is a security feature and controlling it helps prevent denial of service (DoS) attacks in which large amounts of data are sent.

A In a Web scenario, 60,000 items is too much data to display. Having so many items will cause a variety of problems including slow performance (even when the bandwidth is high), lots of data in view state (fortunately you have disabled it), and running up against the request limit. Of course, the request limit is a security feature and controlling it helps prevent denial of service (DoS) attacks in which large amounts of data are sent.

Possible solutions include the use of paging for the DataGrid and the use of stored procedures. Then you can return only the number of rows that you are going to display per page.

Q I have recently tried tweaking the Internet Explorer disk quota setting and I am seeing some weird behavior. I just tried setting the quota to 1MB (Tools | Internet Options | Settings button on general tab) and then downloaded several files that are each at or greater than 1MB. Each of these files is successfully written to the cache. I was expecting that when the quota was reached, the existing entries would be purged in some way. Is my assumption incorrect?

Q I have recently tried tweaking the Internet Explorer disk quota setting and I am seeing some weird behavior. I just tried setting the quota to 1MB (Tools | Internet Options | Settings button on general tab) and then downloaded several files that are each at or greater than 1MB. Each of these files is successfully written to the cache. I was expecting that when the quota was reached, the existing entries would be purged in some way. Is my assumption incorrect?

A Everything that Internet Explorer renders or downloads goes into the cache. If you set the boundary at 1MB it will exceed that temporarily rather than fail. However, after the session ends—when WININET receives the "INTERNET_OPTION_END_BROWSER_SESSION" message, which does not mean that the IEXPLORE.EXE process or the calling process has exited—the limit will be imposed.

A Everything that Internet Explorer renders or downloads goes into the cache. If you set the boundary at 1MB it will exceed that temporarily rather than fail. However, after the session ends—when WININET receives the "INTERNET_OPTION_END_BROWSER_SESSION" message, which does not mean that the IEXPLORE.EXE process or the calling process has exited—the limit will be imposed.

Q I want to manage an org chart using a tree view. When the user creates a new group, she should be able to choose which parent group the new group would belong to and be able to switch the display order in the parent group. A Windows Explorer-style folder view lets you manage folders in the tree view but does not let you choose the display order. I don't need drag and drop, but I do want to be able to change the display order.

Q I want to manage an org chart using a tree view. When the user creates a new group, she should be able to choose which parent group the new group would belong to and be able to switch the display order in the parent group. A Windows Explorer-style folder view lets you manage folders in the tree view but does not let you choose the display order. I don't need drag and drop, but I do want to be able to change the display order.

A Tree View controls can be problematic unless users either know the data hierarchy intimately or the data hierarchy uses commonly defined terms which the majority of your users can successfully use to navigate. Larger directories are easier to scan if they are in a logical order—you're granting users the right to create an illogical order, which could make retrieval of that information more difficult later (if they forgot where they put it).

A Tree View controls can be problematic unless users either know the data hierarchy intimately or the data hierarchy uses commonly defined terms which the majority of your users can successfully use to navigate. Larger directories are easier to scan if they are in a logical order—you're granting users the right to create an illogical order, which could make retrieval of that information more difficult later (if they forgot where they put it).

However, if you proceed with a tree view, a good place to define the parent is in the interface where you invoke the "new group" command. This prevents the overhead of naming a new item and simultaneously choosing its position in the hierarchy. Only allow the repositioning of a group at the moment the new group command is issued or after the new group command is completed. Drag and drop seems like the best metaphor for positioning, but if you want an alternative, consider an interaction metaphor that gets away from direct manipulation of the object and makes the position a property. Perhaps you can display a property sheet for the object independent of the treeview control.

Q I want to convert a batch of HTML files into plain text using a regular expression. Any suggestions?

Q I want to convert a batch of HTML files into plain text using a regular expression. Any suggestions?

A If you're going to parse the text with a regular expression, you should use the Scripting.FileSystemObject to read the file, then manipulate the text with your regular expression. If you want to locate nodes in the doc and are sure the HTML is well formed, using the XML ActiveX® object is a good bet—load the document and use XPath expressions. Of course, when do you ever see a well-formed HTML document? The code in Figure 1 will give you access to the Document Object Model (DOM). Have the browser navigate to your files, not the paths you see here, then use Request/Response/Page, and so on.

A If you're going to parse the text with a regular expression, you should use the Scripting.FileSystemObject to read the file, then manipulate the text with your regular expression. If you want to locate nodes in the doc and are sure the HTML is well formed, using the XML ActiveX® object is a good bet—load the document and use XPath expressions. Of course, when do you ever see a well-formed HTML document? The code in Figure 1 will give you access to the Document Object Model (DOM). Have the browser navigate to your files, not the paths you see here, then use Request/Response/Page, and so on.

Figure 1 Accessing the DOM

var tagREADYSTATE = 
{
   READYSTATE_UNINITIALIZED   : 0 ,
   READYSTATE_LOADING         : 1 ,
   READYSTATE_LOADED          : 2 ,
   READYSTATE_INTERACTIVE     : 3 ,
   READYSTATE_COMPLETE        : 4
}

var ieInst = null;

try {
   ieInst = WScript.CreateObject("InternetExplorer.Application");
   ieInst.navigate("https://www.money.msn.com");
   while(tagREADYSTATE.READYSTATE_COMPLETE != ieInst.ReadyState) 
   { 
       WScript.Sleep(10);
   }
   var htmDOMDocument = ieInst.document;
   WScript.Echo(htmDOMDocument.getElementsByTagName(
       "title")(0).innerText);
}
catch(e) {
   WScript.Echo(e.description);
}
finally {
   if(null != ieInst)
   {
      ieInst.Quit();
   }
}
WScript.Quit(0);

Figure 1 Accessing the DOM

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

Thanks to the following Microsoft developers for their technical expertise: Kashif Alam, Dmitriy Belenko, Joe Bergeron, Gaylon Blank, Mike Bolser, Jason Brown, Mike Burdick, Greg Bybee, Danny Chen, Jon Cole, Pierre Louis Coll, Brian Combs, Courtney Crawford, Jeff Davis, Sean Everhart, Christophe Fiessinger, Ravi Gopinath, Mick Hakobyan, Anand Hegde, Mike Hestness, Wade Hilmo, Drew Leaumont, Yunus Mohammed, Bernard O'Flynn, Dustin Rector, Miguel Filipe Santos, Stefan Schackow, Fyodor Soikin, Takeshi Tanaka, Abdallah Toutoungi, and David Wang.