ASP.Net
Microsoft Content Management Server (MCMS) and Team Foundation Server (TFS) in Visual Studio 2005 don't play nice together. Since MCMS is a dead-end product, I don't expect there will be an actual fix.
The KB Article fix (sort of).
Stefan's workaround. Essentially you need to use them separately, TFS with Visual Studio and a standalone version of the MCMS Template Explorer.
I deployed a site today that has some code in the Global.asax event handlers. I let Visual Studio 2008 add the file to my project when I created it, and it put the code directly in the file inside <script runat="server"> tags. I went with it. So when I deployed the file, none of the events fired. Ever. The lesson is: Don't put your code in the global.asax file. Apparently this problem is by design. There is a vague KB Article on this problem, but the solutions aren't all that helpful, I didn't want to pre-compile, and the first solution made no sense at all. A little searching and I found one good solution: put a class that inherits HttpApplication in the App_Code folder as described here. What I don't understand is why Visual Studio adds the file that way if it isn't going to work on an xcopy deployment. Microsoft seems to go out of their way to protect us from ourselves so often that I am surprised the IDE does something intentionally that won't work.
I have a web project (the original 2005 web project type, not a web application project) and had a problem getting files copied to the bin directory. Essentially, one of the library projects referenced by the web project has an XML file in the project output, but when the solution is built, the XML file in the bin directory of the library project is not pulled into to the bin directory of the web project. Of course, a post-build event seemed like the thing to do, but web projects don't have support for that.
A little digging and I found this post by Scott Guthrie that describes a "Build Helper Project". You simply add an empty class library project to your solution. You then use the build events in the empty project use to add build events to your web project. You just make sure the project build order is correct so the events get called when you need them.
On a new server install, you can copy over the files for your web app and mysteriously get 404 errors. It's a simple configuration in IIS. By default the server is configured not to allow ASP.NET. You simply need to enable this in the IIS management console:

Yahoo posted a list of rules for improving the performance of your web site, along with a new FireFox-based tool for diagnosing your site's performance, called YSlow.
Their number one rule is to reduce the number of HTTP requests, and this only makes sense. I'll bet most of us ASP.NET developers are well aware of output caching, and how to do this in code. But what about those static files, like images and scripts? Well, there is an IIS setting for that. It's easy to do, and the payoff can be big if you have a very graphic-intense site. Here's what you do for IIS 6:
- Open the IIS Management console
- Find the directory containing your images (static content only)
- Right click the directory, and choose Properties.
- Click the HTTP Headers tab.
- Check the Enable Content Expiration check box.
- Click the Expire After radio button, and choose an interval.
- Click the OK button. Done!
The downside is that you won't get the payoff for the first time a user visits the site, but other pages using the same resources will be much snappier. Be aware that caching dynamically created content this way can cause some strange issues, so take care as to what you cache. As always, test it well before you release it and you will be rewarded.
We had code in an ASP.NET page trying to call the Commerce Server Profiles web service that resides on the same physical box. The credentials we used were appropriately configured for Commerce Server using AzMan. For some reason, the code was failing with a 401: Unauthorized error. No matter what credentials we used, no luck. But if you ran the code from another box, it worked fine. Same credentials pointing to the service on that box, no errors.
Turns out the hosts file had an entry for the DNS name we were using, and mapped that name to 127.0.0.1, the loopback address. This was the gotcha. Apparently there is a loopback security feature that causes this behavior. There is a support article describing the effect. Essentially it is a security check to keep certain kinds of attacks at bay. The article suggests registry changes to disable it, but we took a different route. In the short term, if the calling code accessed the web service via IP address (NOT 127.0.0.1) instead of DNS name the problem was circumvented. Meanwhile the network guru is working to get the actual DNS resolution to work.
We all spend lots of time delving into the technical aspects of our work, but don't forget who we are creating all these wonderful apps for. You need to design your apps to work for the users, not create apps that the users need to work to use.
Required Reading: Four Modes of Seeking Information and How to Design for Them
This post in the ASP.Net forums has been the best method for me to make a single-sign on work across different sites in the same domain.
You have to set the machine key in the web.config of all sites even on the same physical box.
Learn how to leverage Active Directory in your .Net apps:
The .NET Developer's Guide to Identity
I just learned about a FREE .Net training event being held in Ann Arbor, MI on May 13th, 2006: Day of .Net! Check out the agenda at the site.
It is a one-day event advertised as a One Day Conference on all things .NET by Developers for Developers. Lots of great speakers, starting with Mark Miller of Mondays fame, and lots of great local .Net experts, including great guys like Aydin Akcasu, Nino Benvenuti, Dustin Campbell, Jason Follas, Dave Giard, Charles Stacy Harris III, Darrell Hawley, Jim Holmes, Josh Holmes, John Hopkins, Greg Huber, Paul Kimmel, Alex Lowe, Drew Robbins, Martin Shoemaker, and Bill Wagner.
I am working on an ASP.Net app that usesWindows authentication for users. I have a certain section of the app, the "Administration" set of pages that I want to exclude from certain roles of users. This is easy using a web.config file, but the unauthorized users get an ugly default 401.2 error page. I would like to have a custom page for that, and surpisingly there was not a ton of information out there on how to do it. In fact, more often than not the answer was "It can't be done."
I did find an acceptable answer in the forums at aspfree.com. Essentially the solution is to handle the Application_EndRequest event in the global.asax and check the status code and authentication of the user. Here is my version:
void Application_EndRequest(object sender, EventArgs e)
{
if (Response.StatusCode == 401 && Request.IsAuthenticated && Request.Url.AbsoluteUri.Contains("Administration"))
{
Response.ClearContent();
Server.Execute("../NoAccess.aspx?id=Administration");
}
}
I don't believe this method will work with Forms Authentication, I ran across plenty of posts saying that it works differently.
I attended a terrific meeting tonight of GANG, the Great Lakes Area .Net user Group, based in the Detroit-area. The main presenter was Jason Beres who gave an excellent presentation on ASP.Net tricks, many of them utilizing Javascript. One of my favorites came up in discussion and I agreed to post the code snippet here.
I have used this techniqe mainly on classic ASP pages as a way to populate secondary dropdown lists before ASP.Net and control-based postbacks came along. It still works with ASP.Net... BUT...the secondary listbox is not in the Viewstate so it's value isn't set properly when accessing the control in server code on the postback where you handle the data. The secondary list's selected value is still in the Request.Form collection though. It is still a great technique to use to fetch data from the server without reloading the page.
The technique is IE-only as it uses an ActiveX object (XMLHTTP) in the Javascript. It also uses the XML DOM to parse the response from the server. In this example the server is an ASP page, but it could easily be a web service as well with the addition of one a little more code. This code is related to a previous post where I used VBA to enable Excel to be a web service client.
Here is the Javascript function:
/* Purpose: Fill secondary list boxes with content
Arguments: oItem - the primary dropdownlist object
sFieldName - The name of the field filling the secondary list
oDestination - the secondary list object
Returns: None, fills list box using MSXML*/
function fillSecondary(oItem, sFieldName, oDestination)
{
var nValue = oItem[oItem.selectedIndex].value;
var xmlHTTP = new ActiveXObject("Microsoft.XMLHTTP");
xmlHTTP.open("POST", "./listboxesXML.asp", false);
xmlHTTP.send('<' + sFieldName + '>' + nValue + '
var xmlDOM = new ActiveXObject("Microsoft.XMLDOM");
xmlDOM.loadXML(xmlHTTP.ResponseText);
if (xmlDOM.parseError != 0)
{
alert("Error occurred: " + xmlDOM.parseError.reason);
return false;
}
var oNode = xmlDOM.documentElement.firstChild;
var n=0;
if(oNode != null)
{
//Clear out the secondary list box, it might already have items
oDestination.length = 0;
while (oNode != null)
{
oDestination[n] = new Option(oNode.text, oNode.attributes(0).text);
n++;
oNode = oNode.nextSibling;
}
if(n==1)
oDestination.selectedIndex = 0;
}
}
In the HTML on the page, add an OnChange handler to the primary dropdown list to call the Javascript when the user changes the value:
A list Item
The classic ASP page (listboxesXML.asp) called by the Javascript looks like this:
Dim xmlDOM 'XML DOM object
Dim oRS 'Recordset for child records
Dim sXML 'XML String returned to browser
Dim oNode 'DOM node containing data for searching
Dim sType 'The type/name of the unknown child node
set xmlDOM = Server.CreateObject("MSXML2.DOMDocument")
xmlDOM.async = false
xmlDOM.Load Request
xmlDOM.setProperty "SelectionLanguage", "XPath"
if xmlDOM.parseError = 0 then
'Select the request node
set oParent = xmlDOM.selectSingleNode("request")
'Get the child of the request node
set oNode = oParent.firstChild
'Store the child's value
sSearchValue = oNode.Text
'Store the child's name
sType = oNode.nodeName
set oRS = Server.CreateObject("ADODB.recordset")
'Fetch the appropriate data into the recordset using sType to tell which
' secondary list we should be fetching, in this case it is called “secondarytype“
'ADO Code should be here, removed for brevity
if not oRS.EOF then
'Build a response XML string
sXML = ""
while not oRS.EOF
sXML = sXML & "<" & sType & " id=""" & oRS.Fields(0).Value & """>"
sXML = sXML & Server.HTMLEncode(ors.Fields(1).Value) & " oRS.MoveNext
wend
sXML = sXML & ""
oRS.Close
else
sXML = ""
sXML = sXML & "<" & sType & " id=""0"">"
sXML = sXML & "None listed sXML = sXML & ""
oRS.Close
end if
set oRS = nothing
Response.Write sXML
else
Err.Raise 1, "ParseError", "There was a parse error in the request."
end if
This can be very tricky to debug if you have any problems. Try looking at the xmlHTTP.ResponseText in an alert in the Javascript function to see any 500 errors generated by the server.
Basically, the repeater ignores the GroupName attribute and gives each radiobutton in each row a unique name so they no longer operate as a group. This is an acknowledged bug by Microsoft.
A short, elegant solution posted on the Usenet.
A free control to solve the same problem.
I posted about a similar problem previously with checkboxes and the Repeater, but it was a very different solution than the two I found here.
An ASP.Net site we created is having infrequent problems with logins using forms authentication. Essentially what happens is that the user attempts to login and is successful, but then is redirected back to the login page immediately. So it looks like an infinite loop of logins. We have been able to deduce that the cookie is related to the problem. If the user deletes their cookies in IE the problem goes away. The problem is very intermittent, so it is very difficult to reproduce. It is not generating 500 errors or errors in the logs. From extensive Googling, the best I can come up with is the fact that we allowed the cookie to persist across sessions, and the problem is related to that. So I changed the createPersistentCookie parameter to false:
FormsAuthentication.SetAuthCookie(nResult.ToString, False)
Of course, solving the problem is only a wait-and-see in this case, since I can't reproduce the problem directly. I thought our login code was pretty straightforward, letting ASP.Net do as much of the work as possible.
Imports System.Web.Security.FormsAuthentication
....
....
'txtEmail, txtPassword are textboxes on the form, lblMessage is a label control
Public Sub Login_Click(ByVal snd As System.Object, ByVal e As System.EventArgs) _
Handles LoginButton.Click
Dim NotRegistered As String = " is not a registered email address. “ & _
“Please use the Create A Profile link to register."
Dim nResult As Integer
If Page.IsValid Then
Dim sPassword As String
sPassword = HashPasswordForStoringInConfigFile(txtPassword.Text, "sha1")
nResult = LoginResult(txtEmail.Text, sPassword) 'Validate against the database
If nResult = -1 Then 'Not a registered user, display error message
lblMessage.Text = txtEmail.Text & NotRegistered
ElseIf nResult = -2 Then 'Bad password, set error message
lblMessage.Text = "The password for " & txtEmail.Text & _
" is incorrect"
ElseIf nResult > 0 Then 'Registered user, nResult is their ID number
If Request.QueryString("ReturnUrl") <> "" Then 'Redirect to requsted page
RedirectFromLoginPage(nResult.ToString, False)
Else 'Go to My Jobs by default
SetAuthCookie(nResult.ToString, False)
Response.Redirect("../MyJobs/My_Jobs.aspx")
End If
End if
End If
End Sub
I used a repeater for the first time in my app, and in this instance it is essentially a list of people with checkboxes to the left of their names so the user can select one or more of them and perform an operation (like delete, etc.). When using a datagrid, this is really easy because you can bind the person's ID as a hidden column, making it very easy to retrieve the primay key. This is not the case with the repeater or datalist as far as I can tell. To top that off, the asp:checkbox control does not have a value attribute where I could store the primary key, like the HTML version. But I needed the asp:checkbox functionality, not the HTML checkbox.
Again, this seemed like a common problem so I decided to perform a Google search. No good solution jumped out at me, until I read this thread from microsoft.public.dotnet.framework.aspnet.webcontrols. It is basically a guy griping about the lack of a value property for the asp:checkbox and a MS Rep apologizing for it. At this point I realized neither of these guys in the thread were “thinking in .Net” (and neither was I when I started my search). Everything is now object-oriented. If a class does not have a feature you need, add it! So that is what I did, and it works great:
Public Class RepeaterCheckBox
Inherits CheckBox
Property Value() As String
Get
Return CType(ViewState("value"), String)
End Get
Set(ByVal Input As String)
ViewState("value") = Input
End Set
End Property
End Class
The important thing to remember here is to make sure the value is going into viewstate so it persists.