navigation
 Monday, June 23, 2008
See a solution for a common problem encountered with the built-in ASP.NET membership controls
posted on June 23, 2008  #    by Adam Anderson  Comments [0]
 Monday, May 26, 2008
Read about a cool hack in Visual Studio 2008 SP1 that allows the designer to fall back on a hardcoded master page if it doesn't manage to locate the correct one.
posted on May 26, 2008  #    by John Waters  Comments [0]
 Friday, April 25, 2008
This week I needed a particular VisualStudio 2005 project template called "ASP.NET AJAX-enabled Web site" and I could not for the life of me get it to show up. Here are the steps I used to fix it.
posted on April 25, 2008  #    by Aaron Rhodes  Comments [0]
 Tuesday, April 15, 2008
After a Vista upgrade none of my .NET 3.5 web applications would run! Visual Studio gives a "Child nodes not allowed" error for the web.config file, but there is a simple solution - once you find it.
posted on April 15, 2008  #    by Rachel Hagerman  Comments [1]
 Friday, April 11, 2008
Passing Microsoft Exam 70-315 Web Applications with Visual C# and Visual Studio.NET - A recent exam-taker's experience and tips for success.
 |  | 
posted on April 11, 2008  #    by Rachel Hagerman  Comments [0]
 Monday, March 10, 2008
ControlParameters are a really nice way to declaratively define the behavior of DataSources, but often you need values that aren't directly in controls. Here is how to bind a ControlParameter so that it reads any page property you define.
posted on March 10, 2008  #    by Adam Anderson  Comments [1]
 Monday, February 25, 2008
With new technology making the web a viable option for more and more applications, we are now seeing the web browser take over for the traditional desktop. Developers making this transition, quickly learn about some of the key differences between the two paradigms. One of the issues they are often forced to deal with is Session expiration. Out of the box, ASP.NET and IIS typically allow only 20 minutes of idle time before the session expires. This can be configured, but knowing that the session expired, or redirecting to a particular page often comes in handy. One way to do this is to add a cookie during the Session_Start method of the global.ascx.cs file, and then check for that same cookie the next time a session is created. If the cookie is there, the session either timed out, or was reset.
posted on February 25, 2008  #    by Mike Dugan  Comments [0]
 Thursday, February 21, 2008
I was designing a load test against Active Focus the other day using TestComplete. I kept getting the error "Connection 0 of the task assigned to the virtual user VirtualUser1 was simulated partially. Only 3 of 41 requests were completed." in the test log.
posted on February 21, 2008  #    by Falafel Author  Comments [1]
 Monday, December 17, 2007
Three ways to access the query string as key-value pairs.
posted on December 17, 2007  #    by Adam Anderson  Comments [0]
 Tuesday, December 04, 2007
This technique is useful to show a page immediately upon request, then begin loading data after the page appears in the browser.
posted on December 4, 2007  #    by Adam Anderson  Comments [0]
 Tuesday, November 20, 2007

Falafel is partnering with Microsoft to offer this free half day seminar at the beautiful Saint Claire hotel in downtown San Jose, CA to celebrate the release of Visual Studio 2008, LINQ, WPF, WCF, WF and other exciting technologies.

ActiveFocus Hosting

Please join us on December 10th from 9:00 AM to 1:00 PM
Register on the Microsoft event site ASAP as space is limited.

Charlie Calvert, the C# Community Project Manager will be there to talk about LINQ and Lino Tadros will present the usefulness of the new technologies.
Hope to see you there!
 |  |  |  |  |  |  |  |  |  | 
posted on November 20, 2007  #    by Lino Tadros  Comments [0]
 Tuesday, November 06, 2007
Read about the problems I encountered and the final solution I arrived at. Source code inside.
posted on November 6, 2007  #    by Adam Anderson  Comments [20]
 Saturday, November 03, 2007
We will be in Las Vegas between Nov 5th and 8th exhibiting at booth # 832. Please stop by and say hello, we have a cool T-Shirt for you and some other goodies! We will be demonstrating our Project Productivity Management Solutions "ActiveFocus 2007" and we will also be showing a sneak peek at ActiveFocus 2008 due at the end of this year. If you can't find us in the booth, look in the Rum Bar at Mandalay Bay or the Craps table near by
posted on November 3, 2007  #    by Lino Tadros  Comments [0]
 Monday, September 17, 2007
Here is an interesting thing I noted the other day. I have an ASP.Net 2.0 application, and in one of the forms, I store the search criteria that you enter on that page in an instance of my ScheduleSearchCriteria class:
posted on September 17, 2007  #    by John Waters  Comments [0]
 Monday, August 27, 2007
If you need to share resources across multiple pages you can use global resources as opposed to the local resources shown in the previous blog. Global resources are implemented using explicit binding, i.e. server tags like this one:
posted on August 27, 2007  #    by Noel Rice  Comments [0]
 Monday, August 20, 2007

ASP.NET 2.0 has a rich set of localization features built-in. Early in the ASP.NET 1x lifecycle we "rolled our own" using an HTTP handler that reflected for a [localize] tag, looked up the control name in a resource file and assigned the localized value.  I prefer out-of-the-box solutions though when available and the MS resource provider model approach provides enough flexibility to be worthwhile.

ASP.NET 2.0 Localization adds two new resource flavors: local and global resources.  Local resources are used for controls on a specific page. The resources are located in the ASP.NET App_LocalResources folder with the same name as the page you're localizing.  So, if you're translating default.aspx then your App_LocalResources might also contain default.fr-FR.resx with a French translation. Global resources are contained in App_GlobalResource and can be used anywhere in the application.

You bind resources to your controls using explicit or implicit expressions. Explicit expressions use an inline server syntax similar to the data binding syntax you're already familiar with.  Implicit expressions syntax use a "<meta>" tag in the control you're localizing to identify the resource.

Local Resources, Implicit Expressions

It all makes more sense in practice so here's a basic walk-though using local resources with implicit expressions:

  • Create an ASP.NET web application.
  • Add a TextBox control to the default form.
  • While you're on the page to localize (default.aspx in this case), select Tools |Generate local resources. This step has a number of effects. 
    • An App_LocalResources folder appears populated with "Default.aspx.resx". 
    • In the Source view, the ASP.NET markup page tag will have a Culture="auto" attribute added. The value of "auto" lets the application react to the browser language settings.
    • In the ASP.NET HTML markup for the control will have a "meta:resourcekey" attribute added:

      <asp:TextBoxID="TextBox1" runat="server" meta:resourcekey="TextBox1Resource1"></asp:TextBox>

      This identifies a single element in the ASP.NET HTML markup.  If there are other nested elements, each needs to be marked with a "meta:resourcekey" attribute before you can implicitly bind to them (as when you have BoundField elements within a GridView for example).  The general rule is, if the element is qualified with a namespace, it needs a "meta:resourcekey" attribute.

    • The properties are marked with an icon that show they are implicitly bound.

image

  • Double-click default.aspx.resx to edit the resource. This will contain resources for the page as a whole and for any controls on the page. The naming convention for resources is <resourcekey>:property name (you typically don't have to know that, but if localization support for a component is incomplete you can still add the "meta:resourcekey" tags by hand). Add text for the page title and TextBox Text property.

Resource for Default.aspx

  • Copy default.aspx.resx to default.aspx.fr-FR.resx.
  • Edit the values in the resource file to French translations.  You can use a tool like Google Translate to get a fair approximation of what the translation should look like. I wouldn't use it as a production tool though unless you want chuckles from the target audience (try translating to and from the target language a few times and you'll see what I mean). 

image

  • Run the application.  Assuming Internet Explorer as your browser, go to Tools | Options | Languages.  Select the "fr-FR" culture code, then refresh the page and Voila! (or "Blick dort!" or "sguardo là!".  Hmm, sure hope I'm not insulting anyone).

image

Slightly More Complex Scenarios

The same pattern works for more complex objects, such as GridView.  Notice there is a "meta:resourcekey" for the grid and also for each of the BoundField objects.

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="SqlDataSource1" meta:resourcekey="GridView1Resource1"> <Columns> <asp:BoundField DataField="ProductName" HeaderText="ProductName" meta:resourcekey="BoundFieldResource1" SortExpression="ProductName" /> <asp:BoundField DataField="UnitsInStock" HeaderText="UnitsInStock" meta:resourcekey="BoundFieldResource2" SortExpression="UnitsInStock" /> </Columns> </asp:GridView>

Again, you can bind to any resourcekey/property name combination:

image

And because the page Culture is set to "Auto", you can change the browser language settings and the translated text is displayed automatically:

image

 

The localization facilities built-in to ASP.NET 2.0 should save you some time if they fit your requirements.  If you need a heavier weight solution that uses a database (or other data store) instead of XML to store resources, check out this article by Jeff Modzel "ASP.NET 2.0 Custom SQL ResourceProvider".

posted on August 20, 2007  #    by Noel Rice  Comments [0]
 Sunday, August 12, 2007

I was configuring Custom Errors in the web.config of my ASP.Net 2.0 application, and set it up as follows:

<customErrors mode="remoteOnly" defaultRedirect="~/Error.aspx">
  <error statusCode="403" redirect="~/AccessDenied.aspx" />
  <error statusCode="404" redirect="~/Error404.aspx" />
</customErrors>

I had found the syntax on MSDN. To my surprise, the applicationm wouldn't start, it told me there was something wrong with the value of the mode attribute.

So I went back to MSDN and noticed I had looked at the .NET Framework 1.1 documentation. Clicking on the corresponding 2.0 documentation, I found it had changed to initial Caps:

<customErrors mode="RemoteOnly" defaultRedirect="~/Error.aspx">

Duh! I guess my chances of getting this right the first time were remote only...

posted on August 12, 2007  #    by John Waters  Comments [0]
 Tuesday, July 31, 2007

The other day I was trying to figure out why the ItemCommand associated with an ImageButton in a DataGrid had stopped firing and was surprised by why...

Here is the grid in action:

When I clicked on any of the ImageButtons in the grid, the page did post back, but the ItemCommand didn't fire. I experimented with binding the grid at different points in the page lifecycle, but that didn't help. I also tried switching from a DataGrid to a GridView, thinking such a drastic change might get rid of whatever oddity was going on. No such luck.

Finally, I noticed that the grid attribute EnableViewState was false. Originally, this grid had contained some template items with editable content, including text boxes, drop down lists and checkboxes, and ViewState was turned on. But I replaced that functionality with some client side logic using JavaScript and JSON web service calls, so I figured no viewstate was needed any more, and had turned it off. It wasn't until a few weeks later when someone clicked on these image buttons that the problem showed up.

So, long story short, I changed EnableViewState to true, and voila, it started to work again. It beats me why viewstate is needed for a command event to fire when an image is clicked (I could see the image.x and image.y variables in the postback even when it was turned off), somehow the event bubbling from the image click to the containing DataGrid's ItemCommand handler (RowCommand in the GridView) is dependant on viewstate being turned on. If anyone knows why I am all ears!

posted on July 31, 2007  #    by John Waters  Comments [0]
 Tuesday, July 24, 2007

So you have a cool asp.net application and everything is running great. You're running it under NET 2.0 and you're using a report server on the same machine. It may run great for months, and then out of nowhere your web application starts displaying the “Service unavailable” page. It does this until you do an iisreset. Where did this message come from? I recently had to find out for myself. My search lead me to the Event Viewer on the server and five warnings about various system failures that read something like this:

A process serving application pool 'ASP.NET V2.0' suffered a fatal communication error with the World Wide Web Publishing Service.

After the fifth warning I would get the following error:

Application pool 'ASP.NET V2.0' is being automatically disabled due to a series of failures in the process(es) serving that application pool.

After the iisreset, things would go OK, but eventually the above warning/error pattern would repeat. What was going on? Why five warnings, the single error, and then the “Service unavailable” page? Well, when you search for "Application pool 'ASP.NET V2.0' is being automatically disabled due to a series of failures", you get plenty of hits. There are plenty of ways to get these errors. What I ended up finding out was that my report server and my web application were using the same application pool. I would not think this would be a big deal, until I found this tab in the properties of the application pool within the IIS Manager.

Mystery solved. It was doing exactly what it was supposed to do. The Enable rapid-fail protection was enabled and I had gotten five failures within 5 minutes to cause the application pool to be disabled. Let's say your web application calls for a report from your reports server. If your reports server fails for some reason, you can also get a failure with your web application. Since they are both in the same application pool this is two strikes with one failure. A couple more of these and your application pool gets shut down. Lesson Learned. It's good practice to move the web application and reports servers into their own application pools.

posted on July 24, 2007  #    by Bary Nusz  Comments [0]
 Tuesday, July 17, 2007

There is a pattern to these errors.  Same asp.net source, same database, same IIS version, same Visual Studio version, same components version, but still some chunk of JavaScript is absent without leave. The actual error messages tend to be new each time, but at least the pattern is recognizable. The reason is that the missing JavaScript functions live in webresource.axd, webresource.axd is handled by an aspnet_isapi.dll, and chances are you are missing a mapping for "axd" in your IIS configuration for your web site. To fix:

  • In the IIS Microsoft Management Console snap-in, right-click the virtual directory and select Properties.
  • On the Virtual Directory tab click the Configuration button. 
  • On the Mappings tab of the Application Configuration dialog click the Add button. This brings you to the Add/Edit Application Extension Mapping dialog. Enter for the Executable the full path to aspnet_isapi.dll located in .NET framework directory.  In this case the path was C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll. Set the Extension to be ".axd".  Don't forget the dot or the dialog will not let you proceed. Uncheck the "Check that file exists" checkbox.
  • If the OK button doesn't become enabled, there's a weirdity here (in the tech support business we used to call these "issues", in the real world we call it a "bug").  Click the Executable textbox entry and the OK button should become enabled.

Cycle the website and try again.  Different flavors of this problem occur periodically, so tag this page for later and save yourself some pain.

posted on July 17, 2007  #    by Noel Rice  Comments [0]
 Sunday, July 15, 2007

A while back I was trying to figure out how to make F1 bring up a custom help window in our web application ActiveFocus. It is easy enough to trap a keypress and open a window showing the help, but to my frustration, after popping up the new window, the built in Internet Explorer help window popped up too!

I tried various variations of cancelling the kepress event, but nothing seems to work. This is for instance how I cancel Ctrl+F (which normally pops up IEs built in Find dialog, but I wanted it to show a custom search dialog instead) :

<script type="text/javascript">

function onKeyDownH(e)
{
  e = window.event;

  var ctrl = (e.ctrlKey) ? true : false;
  if (ctrl == true )
  {
    if ( e.keyCode == 70)
    {
      e.returnValue = false;
      e.keyCode = 0;
      ShowSearchPage();
    }
  }
}

function onloadH(e)
{
  document.onkeydown = onKeyDownH;
  return true;
}

window.onload = onloadH;

</script>

This cancelling approach by the way does work for other keypresses, just not F1, which has some kind of special internal handing. After much head scratching I finally stumbled across this simple solution:

<body onhelp="ShowHelp(); return false;">

Here, ShowHelp does the actual showing of the help window.

Simple, huh? If anyone knows how to make this cross browser compatible I am all ears!

posted on July 15, 2007  #    by John Waters  Comments [0]
 Sunday, July 01, 2007

Last week I needed to add some personalization features to our ActiveFocus application, and it seemed like the built in logic around the Profile class in ASP.Net 2.0 Personalization would do the trick. It's actually pretty neat. First, you "declare" your profile data in web.config, something like this:

<profile enabled="true">
  <providers>
    <clear/>
    <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ActiveFocus"       applicationName="/ActiveFocus"/>
  </providers>
  <properties>
    <group name="Grids">
      <add name="MainGridRows" type="System.Int16" />
      <add name="DetailGridRows" type="System.Int16" />
    </group>
    <add name="LastProject" type="System.Int32" />
  </properties>
</profile>

The Properties portion defines the profile data structure. You can use simple data types like System.Int16, nested types (like the Grids property), and your own data types. You can also declare how these types are to be serialized.

When you add a declaration like this to your project, Visual Studio 2005 generates a class for you that implements this data structure (more on how this actually needs a little help for it to work later!). The class basically wraps the HttpContext.Current.Profile object, which is of type ProfileBase. It adds accessors for the members you declared in the web.config file, and sub objects for nested types.

In runtime, the ProfileBase reads and writes it values to a column in the table aspnet_Profile. Here is what it looks like when an instance of the profile class above is written to that table:

UserId                               PropertyNames                                                          PropertyValuesString

7B07AE10-61A7-4DEE-AFF1-172BB42A5E95 Grids.DetailGridRows:S:0:1:Grids.MainGridRows:S:1:2:LastProject:S:3:1: 8202

The profile is tied to user using the UserID column, and the PropertyNames column determines what offset and length in PropertyValuesString each data item occupies. For instance, MainGridRows starts at offset 1 and is 2 characters (so the value is 20). You can use attributes in web.config to control how the properties are serialized.

In code, to access the profile, you just need to declare a property in your form that casts the Profile object of the current Page (or HttpContext.Current.Profile) to a WebProfile (this is the type name of the auto generated ProfileBase wrapper) :

protected WebProfile Profile
{
  get
  {
    return (WebProfile) this.Profile;
  }
}

Now you can read and write the Profile using this property:

tbRowsPerMainGrid.Text = Profile.Grids.MainGridRows.ToString();
tbRowsPerDetailGrid.Text = Profile.Grids.DetailGridRows.ToString();

Here is how you can save it back:

Profile.Grids.MainGridRows = Int16.Parse( tbRowsPerMainGrid.Text );
Profile.Grids.DetailGridRows = Int16.Parse( tbRowsPerDetailGrid.Text );
Profile.Save();

Pretty cool, huh?

Profile data can be stored for authenticated users, but it can also be stored for anonymous users and "upgraded" to an authenticated user if the anonymous user becomes an authenticated user.

So what is the catch with all this magic?

Well, it turns out that this handy dandy auto generating of wrapper classes is only done for Web Site Projects, not Web Application Projects (WAPs)! This is true even of the latest Visual Studio 2005 SP1. I tried doing this in the ActiveFocus WAP, and the compile failed miserably, there was no WebProfile class to be found. I figured this would be easy to Google, and indeed it was, and it turns out that there is a Visual Studio add in on gotdotnet that adds this capability to WAPs, but to my dismay I saw that the gotdotnet site is "being phased out", and the download is gone!

So I turned to my old colleague and friend Charlie Calvert at Microsoft, and he did some digging. He found this post at andornot.com, which references the original post by Scott Guthrie on scottgu.com, and helpfully provides the vanished download!

I downloaded the software and installed it, and now when I right clicked on the web.config node in the Solution Explorer, there was a menu option saying Generate WebProfile:

And what's more, it actually worked! ActiveFocus is now equipped with a user profile capability! Thanks for the help, all of you guys with helpful blogs above! Hopefully this blog will help you too.

posted on July 1, 2007  #    by John Waters  Comments [0]
 Friday, June 22, 2007

I have an ASP.Net 2.0 form that uses Teleriks RadServiceManager to call a web service in the same application. All was working fine, but when I deployed it to another machine, the web service calls failed. I checked the Event Log and found something like this:

 

Request format is unrecognized for URL unexpectedly ending in '/ArtifactSearch/'. 

 

Googling turned up this helpful article. Apparently, web service calls using HTTP GET and POST are disabled by default on 1.1 installations, and I guess that can linger in machine.config or somewhere, and even though my app was a 2.0 app, it inherited these settings. You can enable the calls by adding this to the <system.web> section of your apps web.config: 

 

<webServices>

  <protocols>

    <add name="HttpGet"/>

    <add name="HttpPost"/>

  </protocols>

</webServices>

 

That did the trick for me!

posted on June 22, 2007  #    by John Waters  Comments [0]
 Wednesday, June 20, 2007

Today I worked on an AJAX application that uses JSON over xmlhttp to provide a quick search feature in our product ActiveFocus. Here you can see it in action: as you type in the searchbox, each time a key is pressed, the search string is sent to the server, a freetext search is done against the database, the results are returned in a JSON array, and then rendered as a HTML table:

Originally, this was hand coded in JavaScript at a very low level, using an ASP.Net 2.0 page on the server side to create and return the JSON object. The task at hand was to convert this to a more high level approach using Teleriks RadServiceManager to call a ASP.Net 2.0 Web Service, which returns a standard .NET type that is automatically converted to a JSON object.

In my Search Web Service, I return an array of SearchResultRows:

public struct SearchResultRow
{
  public int ID;
  public string ArtifactType;
  // ...
}

[WebMethod(EnableSession = true)]
public SearchResultRow[] ArtifactSearch( string searchKey)
{
  //…

This was amazingly straight forward. On the client side, when the callback returns, you can access the array through JSON indexing, something like this:

function CallSearch( searchKey )
{
  Search.ArtifactSearch(
    searchKey,
    SearchServiceCompleteCallback, SearchErrorCallback);
}


function SearchServiceCompleteCallback(ResponseAsJSON, ResponseAsXml, ResponseAsText)
{
  var Results = ResponseAsJSON;
  for( i=0; i < Results.length; i++)
  {
    // …
 

After debugging it in FireFox/FireBug (highly recommended! See article by my colleague Noel), I switched back to Internet Explorer 7.0 to test it there, confident that all was well. At first, the search behaved just like it should. But when I typed a search phrase that narrowed the search down to just one record in the returned array, I suddenly found that the table of results did not get displayed at all. It would display two or more results, but not one!

Intrigued, I switched back to FireBug to debug the mystery. But in FireFox, a one row array worked just fine. I could inspect the value of Results and see the JSON encoding, and verify that it was correct. So, I switched back to IE, this time using the VS 2005 IDE Script Debugger, which is pretty primitive compared to FireBug, but I had no choice.

Now, when I went to inspect Results, I found something very strange. When two or more records were returned, the JSON looked just like the FireFox version:

But when the call only returned one row, the JSON object had a different layout! Instead of a JSON  array of SearhResultRow records, there was an inner object named the same thing as the type of the array elements (SearchResultRow), which contained the field values for that one record!

Go figure!

At this point I had spent way too much time debugging and needed to get the job done, so I just added a check to see if the singleton format was present and handled the two different cases in seprate branches of the if statement, which did the trick.

However, I am curious as to whether this is a bug or not. Clearly, it is the same code running both server side and client side, yet in the two main browser versions, the JSON objects differ for one record arrays.

Let me know if you have any input! If not, maybe at least this blog will save you some debugging time…

posted on June 20, 2007  #    by John Waters  Comments [0]
 Friday, June 15, 2007

I just spent some quality time with Firefox and Firebug trying to figure out why my client-side validators weren't preventing a postback when invalid data was entered. The symptoms were puzzling: when I entered invalid data and then attempted to submit the form, the validators would appear briefly, but then the page would post anyway!

A little debugging revealed that the button I was clicking called the JavaScript function WebForm_DoPostBackWithOptions, which called Page_ClientValidate, which called ValidationSummaryOnSubmit. This function looped through a list of validation summaries named Page_ValidationSummaries and then performed operations on each list element, which naturally meant accessing its properties.

ValidationSummaryOnSubmit doesn't test each summary in the list to ensure that the summary is not null before attempting to access its properties, so if a null reference finds its way into this list, an error occurs, which causes the entire call chain to terminate abnormally, in this case resulting in a failure to prevent the form from posting.

A little more debugging followed, and I located where the Page_ValidationSummaries list is initialized, and found which reference was returning a null value. It was a validation summary in the footer of a DataGrid, and the DataGrid's ShowFooter property was false. This of course meant that all of the controls within the footer were never rendered to the client, but the code that generated the list of summaries was including the reference anyway.

The solution to the problem was clearly to find a way to get the generated script to exclude the summary when the footer wasn't visible. I tinkered with a few alternatives, ultimately settling on this one: set the summary's Enabled property to be databound to the expression:

Enabled='<%# DataBinder.Eval( Container.NamingContainer, "ShowFooter" ) %>'

Within templated controls such as a DataGrid, Container refers to the DataGridItem of the current row. DataGrids are naming containers for DataGridItems, so accessing Container.NamingContainer gives a reference to the DataGrid. Eval then uses reflection to find the ShowFooter property of the grid and assign it to the Enabled property of the contained ValidationSummary. My testing showed that with this expression, the summary no longer appeared in the Page_ValidationSummaries initialization list when the footer was hidden, and client-side validation prevented postbacks again. Problem solved!