Tuesday, February 06, 2007

Last time I have posted my observations on the Remember Password feature of Microsoft SQL Server Management Studio. Today it got even worse! Not only MSSMS forgets my password on a random basis, It prevents me from logging in with a correct password! Yeah I have written about it last time, but this time I have entered the right password - 100% sure of that, and despite dozens of connect attempts it always said that login or password is incorrect! So I have retyped the exact same password and voila, after second connect attempt it worked.

Now. I know that there is SQL Server 2005 service pack comming out soon, but does anyone know if the login window will be fixed? Come on! Its only a UI with few imputs! How hard can it be?

Tuesday, February 06, 2007 11:29:32 AM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 
 Saturday, February 03, 2007

There are couple of folders that have a special meaning in ASP.NET. Those folders include folders like App_Code where you usually put your code or App_Themes where you put themes. There is also an App_Data folder which "Contains application data files including MDF files, XML files, as well as other data store files" (MSDN).

From App_Data folder description it is obvious that it is where you should put your data. But how to do it? I have searched high and low for a methods or properties that help interact with this directory. The reason is because I don't like hard-coding strings in my code and I would have to hard-code at least one: "~/App_Data". I thought that since there are method to get the location of temp directory:

System.IO.Path.GetTempPath(); 

Or even to get the system direcotry:

Environment.SystemDirectory 

There should be a way to get the App_Data directory.

Apparently I was wrong. Unfortunately. There is no Strongly Typed method or property to get to the location of App_Data directory!

I have found 2 places in code where "App_Data" appears as a string (that's why I'm pretty sure there are no properties or methods). One place is a GetDataDirectory method in an internal System.Web.DataAccess.SqlConnectionHelper class and the other is in a SetUpDataDirectory method in a System.Web.HttpRuntime class.

My guess is that the first one is used for Membership Provider that by default uses Microsoft SQL Express database and App_Data directory to store the mdf files. The other one is probably not used at all - I have found no code that calls that method! 

When I have looked inside those methods I have found one thing that they have in common. Both set some data object in an AppDomain via:

AppDomain.CurrentDomain.SetData("DataDirectory"...) 

So I have made a test and used on one of my pages:

string dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory") as string; 

And of course it worked as expected. Unfortunately we cannot (or should not) use this kind of code since it is a dirty hack that relies on internal implementation of some internal classes and it also requires us to hard-code a string. So what's the benefit? The only one is that now I'm pretty sure, that there is no way to interact with App_Data folder using BCL so I will no longer have to search for it on the Internet - thing that I have done countless times.

kick it on DotNetKicks.com

Saturday, February 03, 2007 3:18:21 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [1]  | 
 Wednesday, January 31, 2007

During my investigation of how and what of AutoGenerateColumns in GridView in my recent articles, I had a need to check if a type is a Nullable type. I have used reflector to search for a siutable method, but I haven't found one. What I have found though was a strange class: System.Internal. It is internal so it is not accessible outside its assembly, but nevertheless I find it worth mentioning because of its contents.

The class has 3 methods that make me think:

  • CommonlyUsedGenericInstantiations_HACK()
  • NullableHelper_HACK<T>()
  • SZArrayHelper_HACK<T>()

Just by looking at the names I can tell that there is something about them, that is not your usual BCL code :-)

When I have looked inside the first one of those methods I have found a lot of code that only instanties Generic type objects such as List<T> where T is bool, int, Guid etc. The second method on the other hand calls Compare<T> and Equals<T>.

Why is that? In my opinion, all the operations there are perfoemed to improve performance of some code. By doing the operations in a batch, once, at some point in time, we do not risk the JIT compiler compiling every generic class and every generic method on demand later. If this really helps or is useful? I don't know, but MS has done it and I usually do not believe in "random code". Maybe there are some performance considerations in some scenarios that require the HACK approach? I haven't been able to find a place in the BCL that uses the System.Internal class.

kick it on DotNetKicks.com

Wednesday, January 31, 2007 2:37:13 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 

In my last article on IsBindableType, I have desribed, why AutoGenerateColumns does not work for Nullable types. Now I present a solution for this problem.

In order for your GridView, FormView, or DetailsView to autogenerate the field for your Nullable<T> property you have to subclass the control you are using: say GridView and override the IsBindableType method. In this overriden method, you have to add a check to see if a type is Nullable. This can be done in a following way according to Yitzhak Gootvilig's post:

public static bool IsNullableType(Type type)
{
    return type.IsGenericType && 
      type.GetGenericTypeDefinition() == typeof(Nullable<>); }

Just put this code in some kind of reusable library since I have a feeling that ASP.NET controls will not be the last place you will need it :-)

A full implementation of IsBindableType after the additional check will then look more or less like this:

public override bool IsBindableType(Type type)
{            
    return NullableHelper.IsNullableType(type) 
      || base.IsBindableType(type); }

This simple hack has to be repeated for each of the *View controls. Fortunately it is not a common scenario where you have the AutoGenerateColumns property set to true :-).

kick it on DotNetKicks.com

Wednesday, January 31, 2007 1:50:07 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 

Today I have encountered a strange problem with GridView's AutoGenerateColumns property. The problem was that not all columns were generated automatically. It would not be a surprise if it happened for complex types such as my own, but I have noticed that simple (in my opinion) types such as Nullable<Guid> were also not generated! So I went investigating.

After a while of hacking and slashing through the GridView's code I have found the reason. It appears that columns are only auto-generated for properties whose type is a bindable type. What does that mean? Who decides if a type is bindable or not? I have continued my investigation and...

After a while I have found that there is a method on a GridView control called IsBindableType which looks like this:

public virtual bool IsBindableType(Type type)
{
      if ((!type.IsPrimitive && (type != typeof(string))) && 
      ((type != typeof(DateTime)) && (type != typeof(decimal)))) { return (type == typeof(Guid)); } return true; }

Apparently this method decides that Nullable<Guid> (or Nullable<int> for that matter) is not a bindable type! Because of this, you will not see properties of such a type automatically rendered in a GridView!

Being curious I have asked myself: why such a method is defined on a GridView control? Is it not a more general issue to decide if a type is bindable or not? So I went investigating even further.

I have found that there are 5 IsBindableType methods defined in System.Web.UI.WebControls namespace:

  • AdRotator
  • BaseDataList
  • DetailsView
  • FormView
  • GridView

Of those 5, DetailsView, FormView and GridView have exactly the same implementation. BaseDataList has slightly different:

public static bool IsBindableType(Type type)
{
      if ((!type.IsPrimitive && (type != typeof(string))) 
      && (type != typeof(DateTime))) { return (type == typeof(decimal)); } return true; }

Notice the static modifier! AdRotator on the other hand has exactly the same implementation as the BaseDataList but here the method is an instance method and is private!

So, we have basically 5 places in code, each of which implements the same logic, some do it differently and none does it correctly :-(.

kick it on DotNetKicks.com

Wednesday, January 31, 2007 1:28:45 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, January 24, 2007

Today I have found a funny example of how to ensure the checkbox is not visible:

<input id="chkIsDirty" type="checkbox" readonly style="DISPLAY: none;
VISIBILITY: hidden; BACKGROUND-COLOR: transparent" size="0" runat="server"
name="chkIsDirty">

I have emphasized the important elements. I wonder if it is also hidden by the style sheets and maybe in the code via the runat="server" attribute :-)

Wednesday, January 24, 2007 3:23:10 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [3]  | 
 Tuesday, January 16, 2007

In most of the ASP.NET projects I have been working on, I have needed a way to easily navigate to any page in the solution. To accomplish this I usually created some kind of User Control with links to all pages. If the project was small I usually entered the links by hand. For bigger projects I have used a Repeater control and filled it with data from the file system.
The method used to get the data from the file system looks more or less like this:

public string[] GetAllPages()
{
    int applicationFolderNumberOfCharacters = HttpRuntime.AppDomainAppPath.Length;
    List<string> pages = new List<string>();
    string[] files = Directory.GetFiles(
      HttpRuntime.AppDomainAppPath, "*.aspx", SearchOption.AllDirectories); return Array.ConvertAll<string, string>(files, delegate(string file) { return "~/" +
         file.Substring(applicationFolderNumberOfCharacters).Replace(@"\", "/"); }); }

On the Page or User Control the Repeater I use looks as follows:

<asp:Repeater ID="Links" runat="server">
   
<ItemTemplate>
      
<a runat="server" href='<%# Container.DataItem %>'><%# Container.DataItem%></a><br />
   
</ItemTemplate>
</
asp:Repeater>

If you put it on the Master Page, you will get access to every page from every page, which is great during development. Just don't forget to remove it from the production code.

kick it on DotNetKicks.com

Tuesday, January 16, 2007 7:38:57 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 

Today Mads shows us a not well known class that is called a Triplet. He also asks a question: how you would use it. Fortunately I have seen this class before so here is what I have learned:

Triplet is used in the same way as a Pair class - mostly in the LoadViewState and SaveViewState methods. Generally if you are saving view state in your control you not only have to store your data, but also the data returned by the call to the base.SaveViewState method. This is where the Pair class or the Triplet come in handy since given two (three) fields, one is used for the base control's state and the other can be used by your state. Similarly, when loading the state in the LoadViewState method you get your own state from one of the fields, and pass the other to the base class'es LoadViewState method. You have to remember to pass the same field you have used in the SaveViewState method or the things will go nasty ;-).

Triplet is used when Pair is not enough. If Triplet is not enough, you have to create your own class.

I hope this sheds some light on the topic.

Tuesday, January 16, 2007 6:55:47 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 
 Friday, January 12, 2007

The "as" operator as described in MSDN is an operator: "Used to perform conversions between compatible reference types". We have to keep this in mind when coding. Often it is just easier (and it looks nicer too) to use an "as" operator instead of a cast, or when we want to handle the DBNull value returned from the database like in the following scenario:

string s = reader["Name"] as string;

instead of

string s = (string)((reader["Name"] is DBnull) ? null : reader["Name"]);

Assuming that the name column can be null in the database.

When we use it we accept that something could be of incompatible type such as Name column being of numeric type return. What happens then? What happens if the column type has changed? In the scenario above, we will always get a null reference, which in a worst case scenario we will discover very late in project.

Of course in some situations it is just what we need. What I have found however is that misusing the "as" operator can often lead to unexpected NullReferrenceException exceptions being thrown (or worse yet nothing wrong happens at first). If you find that happening it may mean that you are using "as" operator as a shortcut where an ordinary cast would be in place. Using a cast often causes bugs to appear sooner in the development life cycle which is always a nice thing. So basically a rule of thumb is to always think twice whether to use a cast or an "as" operator.

kick it on DotNetKicks.com

Friday, January 12, 2007 12:17:26 AM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [3]  | 

Since the beginning of my adventure with .NET I have always asked myself one question: why do we need the DBNull type? Is a simple null reference not enough?
MSDN says that DBNull "Represents a nonexistent value". From a logical point of view - this one sentence explains why a null reference cannot be used - because it is a null reference and not a lack of value. But is it enough to introduce a type that causes a lot of trouble?

DBNull is typically used in ADO.NET when returning data from the database. If one column does not have a value in the database, it will be represented as a DBNull object. That is something altogether different from what I would expect at the domain level. When working with objects when there is a Client object, and I ask for his Name then if the name is not there I expect to get null in return. It is very natural to me and probably to most of the developers. When we need to interact with data layer that is where most of the problems with DBNull kick in.

Consider a simple example of a Client's Name property which is of a String type. In your code you accept a situation when the Name is null which may mean that it has never been set. When you save such a Client to a database using a simple Insert call, everything works OK. (it was in fact my data access library that handled null inserts by changing them to DBNulls) You check the database and the data is in fact there and the Name is "null". When next time you try to get the Client from the database, you have to read all the columns and put the values into your object like in the following example:

Client c = new Client();
c.Id = (Guid)row["Id"];
c.Name = (string)row["Name"];
...

This will result in an InvalidCastException exception being thrown with a message "Unable to cast object of type 'System.DBNull' to type 'System.String'." That is of course because null values from the database are represented as DBNull objects.

Typical solution for this problem is to check the column for DBNull before casting or using an "as" operator which you have to be carefull with as I describe in another post.

Whichever way you choose, what you get is an overly complicated code that does a simple thing!

I don't think that the sentence from MSDN that describes the purpose of DBNull is a good excuse for introducing DBNull type. I don't think that returning null instead of DBNull would cause any loss of information. What I think is that DBNull should have never been introduced because it makes developer's work harder without adding any real value. Additionally ADO.NET is inconsistent in that it allows saving a null referrence to a database but does return DBNull instead. Because of the fact that I don't like to deal with DBNulls, in my data access library, I'm always replacing it with a null reference so I never get it to propagate to the upper layers. That way I get a better separation from a database level stuff.

BTW: If anyone has something to say in defense of the DBNull I woulreferenced gladly hear it.

kick it on DotNetKicks.com

Friday, January 12, 2007 12:08:55 AM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [8]  |