Usable Asp.Net

Little things that make Asp.Net more usable

How to tell the page is in AJAX call

The way to tell if the page is in an AJAX call is to check the ScriptManager.IsInAsyncPostBack property.

Sounds trivial.

The only reason I am writting about that is the very common confusion with the Page.IsAsync property that has absolutely nothing to do with AJAX.

Reporting Errors in Login Control

Login control has a FailureText property that holds the text to display to the user when a login attempt fails.

What if you want to report errors before making an login attempt? For example, you may handle the LoggingIn event to check a "IsDeleted" flag on user record and, if it is set, provide an error "The user is inactive". How can you set the error text without making an login attempt?

This code will do that:

protected void LoggingIn(object sender, System.Web.UI.WebControls.LoginCancelEventArgs e)

{

string userName = this.Login1.UserName;

// validate the user

if (IsUserDeleted(userName))

{

// deleted, cancel login

e.Cancel = true;

// notify the user

(this.Login1.FindControl("FailureText") as System.Web.UI.WebControls.Literal).Text = String.Format("The user {0} is inactive", userName);

}

}

 

Customizing web.config for different environments

This is a very common scenario.

You develop your application in environment A. The production will run in environment B. There will be also a demo site in environment C and a test site in environment D. The environments may have different connection strings, account identities, custom application settings, whatever else you may or may not think of. You clearly need to give to every environment its own web.config file. Or modify the setting in run time depending on what environment the application is running in.

On other hand, your web.config includes sections common for all environments and you wouldn't like to maintain the same setting in four places. Another issue is that, when you publish the site, the development web.config is going to overwrite the target one that already has been customized for the target environment.

There is a simple solution with no coding involved. Make use of the configSource property for the sections you need to customize.

The configSource is basically the name of the include file in which the associated section is defined. Leave in the web.config only the sections common for all environments and take all variable sections out to separate files. For examle, the connectionString section in the web.config file will look like this: 

<connectionStrings configSource="SiteSettings\connectionStrings.config"/>

Note that the configSource is set to the physical location of the file relatively to the location of the web.config.The content of the connectionStrings.config will be:

<?xml version="1.0" encoding="utf-8" ?>

<!-- This file is an extension of the application web.config file. The root element must be <connectionStrings>.-->

<connectionStrings>

<add name="SiteSqlServer" connectionString="Integrated Security=SSPI;database=DbDemo;" />

</connectionStrings>

You can make separate config files for as many sections as you wish. Put them all in a single directory. In our case it is SiteSettings.

Now, in our example with four environments you would make four sets of section config files in four directories and deploy each one to the corresponding environment. It is important not to include any of the config section directories into your solution. This will ensure that you won't overwrite the correct settings on the target site with your development ones on every publishing.

Now you can modify the common sections of your web.config and publish it to all targets. The targets will keep their customized config sections intact.

 

Application Pool Identity on Win2003

This can be trivial for those fluent in IIS and Windows security. Not so for regular developers who need to impersonate their applications in IIS.

To get your application pool run under another user account, that user account needs to be a member of the IIS_WPG security group.

Hope this will save someone hours of work.

VS2008 freezes after builds

Recently my Visual Studio started freezing for 1-3 minutes after every build, no matter successful or not, debug or release. Save All operation also became very slow. This was extremely annoying. Eventually, I found the culprit. My solution .suo file grew quite big. I just deleted it and all delays gone.

Resetting ChangePassword control

If you try using the ChangePassword control for changing several passwords on the same page, you will notice that after confirming successful password change the control always shows the same success message and doesn't offer any text entry fields any more. The reason is that the control maintains an internal state machine and doesn't reset it properly after succes password changes. The state machine is controlled by internal property CurrentView that is not available for direct setting. But you can set it using reflection like this:

private void resetChangePasswordState(System.Web.UI.WebControls.ChangePassword cpControl)

{

System.Reflection.BindingFlags flags = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic |

System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static;

System.Type type = cpControl.GetType();

System.Reflection.PropertyInfo p = type.GetProperty("CurrentView", flags);

System.ComponentModel.TypeConverter converter = System.ComponentModel.TypeDescriptor.GetConverter(p.PropertyType);

object result = converter.ConvertFrom("ChangePassword"); p.SetValue(cpControl, result, null);

}

Posted: Oct 30 2007, 05:32 AM by egoldin | with 3 comment(s)
Filed under:
Data Entry: Use Enter as Tab

A simple javascript will make your Enter key work as Tab. It is useful in large tabular forms.

function enterToTab(){
  if (event.keyCode==13)
    event.keyCode=9;
  }

<input type="text" onkeydown="enterToTab()">

Note using onkeydown event. Onkeypress won't do the trick.

Posted: Jul 30 2007, 03:25 PM by egoldin | with 4 comment(s)
Filed under:
Detect Vista on client machine

If you need to know if client's browser runs on a Vista machine, run javascript
navigator.userAgent
or
navigator.appVersion
and search the returning string for "Windows NT 6.0". If it is there, you are on Vista.

Posted: May 21 2007, 07:15 AM by egoldin | with 2 comment(s)
Filed under:
Silverlight is coming: c# calls from javascript and more...

Soon you won't need to go to the server to treat your client-site javascript with some c# calls.  Watch this technology, it looks promising:

Silverlight.

Scott Guthrie:

Silverlight opens up a ton of opportunities to build significantly richer client experiences that run cross platform and cross browser. 
For .NET developers, it means that you can now write .NET code using any development language (VB, C#, Javascript, Python, Ruby and more) in the web-browser (using Silverlight), web-server (using ASP.NET), in desktop applications, and with mobile devices.  You'll be able to use great Visual Studio developer tools and Expression Studio designer tools to target each of these experiences.

Posted: May 08 2007, 10:28 AM by egoldin | with no comments
Filed under:
Table height:100%
Ever tried to get a <table> to take the whole browser height? Not a trivial task if you want to keep the browser in the Strict mode. Yes, removing

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

will do, but that's already the Quirks mode.

This css rule will work even in the Strict mode:

html, body, table#main {height: 100%}

 

Posted: Jan 03 2007, 06:45 AM by egoldin | with 9 comment(s)
Filed under:
How to get DataTable out of SqlDataSource

In many scenarios developers would like to combine the great simplicity of Asp.Net 2.0 declarative databinding with the same level of control over data as they get with good old traditional databinding. Sometimes the developers need to manipulate on the data in the datasource and thus to access it.

If the data come from a SQL Server database, you will use the SqlDataSource control. Setting the DataSourceMode property to DataSet will result in creating a DataSet object in the server memory. The object will be loaded with the data after running the Select method. The Select method returns a DataView populated with the rows returned from the database. Having obtained the DataView, you can easily convert it to a DataTable with the DataView.ToTable method.

In the case of declarative databinding the Select method is called automatically by controls that are bound to the SqlDataSource and it is not obvious where is your chance to catch the datasource, convert it to a DataTable and do something on it.

If you need to access the dataset prior to databinding, you don’t have any choice but to call the Select manually, which contradicts the whole idea of declarative databinding. Too bad.

In some scenarios however you can first databind and then operate on the DataTable. One example is when you need to save the table for postbacks. In this case you can catch the table in the ItemDataBound or RowDataBound event of the control bound to the SqlDataSource. The event reaches the DataView via the DataItem property exposed by the data items:

    bool firstTime = true;

    System.Data.DataTable dt;

    protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)

    {

        if (e.Row.RowType == DataControlRowType.DataRow)

            if (this.firstTime)

            {

                System.Data.DataView dv =

                     (e.Row.DataItem as System.Data.DataRowView).DataView;

                this.dt = dv.ToTable();

                this.Label1.Text = dt.Rows.Count.ToString();

                this.firstTime = false;

            }

    }

 

Posted: Dec 27 2006, 01:29 PM by egoldin | with 5 comment(s)
Filed under:
Programmatically determining the sqlDbType of a field

I found this remarkable info in a newsgroup post from David Sceppa from Microsoft:

You can build a SqlCommand to query the table and retrieve this schema information from the SqlDataReader through its GetSchemaTable method.  This method returns a DataTable of schema information. Each row in the DataTable corresponds to a column in the resultset for the original query. The DataTable of schema information includes columns for column name, data type, etc. There's a column called ProviderType that contains an integer, which you can cast to SqlDbType.

Here's some code that should help:

Visual Basic .NET:
  Dim strConn, strSQL As String
  strConn = "Data Source=(local)\NetSDK;Initial Catalog=Northwind;" & _
            "Trusted_Connection=Yes;"
  Dim cn As New SqlConnection(strConn)
  cn.Open()
  strSQL = "SELECT OrderDate FROM Orders"
  Dim cmd As New SqlCommand(strSQL, cn)
  Dim rdr As SqlDataReader
  rdr = cmd.ExecuteReader(CommandBehavior.SchemaOnly)
  Dim tbl As DataTable = rdr.GetSchemaTable()
  rdr.Close()
  cn.Close()
  Dim intOrderDateType As Integer
  intOrderDateType = CType(tbl.Rows(0)("ProviderType"), Integer)
  Dim typOrderDateType As SqlDbType
  typOrderDateType = CType(intOrderDateType, SqlDbType)
  Console.WriteLine("ProviderType = " & intOrderDateType)
  Console.WriteLine("SqlDbType = " & typOrderDateType.ToString())


Visual C# .NET:
  string strConn, strSQL;
  strConn = @"Data Source=(local)\NetSDK;Initial Catalog=Northwind;" +
             "Trusted_Connection=Yes;";
  SqlConnection cn = new SqlConnection(strConn);
  cn.Open();
  strSQL = "SELECT OrderDate FROM Orders";
  SqlCommand cmd = new SqlCommand(strSQL, cn);
  SqlDataReader rdr;
  rdr = cmd.ExecuteReader(CommandBehavior.SchemaOnly);
  DataTable tbl = rdr.GetSchemaTable();
  rdr.Close();
  cn.Close();
  int intOrderDateType;
  intOrderDateType = (int) tbl.Rows[0]["ProviderType"];
  SqlDbType typOrderDateType;
  typOrderDateType = (SqlDbType) intOrderDateType;
  Console.WriteLine("ProviderType = " + intOrderDateType);
  Console.WriteLine("SqlDbType = " + typOrderDateType.ToString());

Posted: Dec 20 2006, 03:34 PM by egoldin | with 6 comment(s)
Filed under:
OWC is retiring

For years OWC (stands for Office Web Components) has been serving to web developers as a power graphic engine. Free for non-interactive scenarios, it provides Excel-style charts.

Now it is on the way out. OWC is being deprecated and will not receive any functionality updates (http://blogs.msdn.com/excel/archive/2006/07/17/668544.aspx). Instead Microsoft will be offering a technology called Excel Services which is a part of Microsoft Office SharePoint Server 2007. It has been designed to scale and perform on a server. But it as not going to be a replacement for OWC from the functionality perspective and it is not free anymore.

Although technically nothing stop me from continuing using OWC in new projects and recommend it to others, I don't feel comfortable relying on a deprecated technology. Looks like I will rather need  to shop for a third party component.

 

Posted: Dec 19 2006, 04:17 PM by egoldin | with no comments
Filed under:
A foreword

The purpose of this blog is to share tips, tricks, patterns, thoughts on all aspects of asp.net development.

Stay tuned!