dotNoted

Icon

Observations of .Net development in the wild

ReferenceSource downloads!

Why isn’t this getting more attention?

http://referencesource.microsoft.com/netframework.aspx

Maybe I’m just out of it…

Filed under: .Net Basics

InternalsVisibleTo needs the whole public key in CLR v2.0 RTM

Hopefully, this post will help the search engines to set the record straight about the InternalsVisibleTo attribute for creating friend assemblies. A number of notable .Net voices (Oliver, JuvalJames World) used this attribute in pre-RTM code, when the public key token was used, but Microsoft changed it in the release.

In one post in particular, a commenter, Neil, was trying to say that PublicKeyToken isn’t available for InternalsVisibleTo – only PublicKey is. C# MVP Oliver Sturm counters by explaining that it seems pointless to use the whole public key, since it is so much longer to copy than the public key token. While this is true, he apparently was unaware of the change when he wrote this. It was changed in .Net 2.0 RTM. MSDN, after remaining inaccurate after release for some 9 months, now shows the correct syntax.

Update: David Kean also points this change out, and notes that it was changed in RC1, which if I recall correctly was released right after the PDC and right before the November RTM. David also has a nifty utility which generates the otherwise onerous attribute for you. Nice.

Filed under: .Net Basics

OdbcFactory.Instance.CreateDataSourceEnumerator does nothing

This method sounds cool – like it would enumerate ODBC sources on a machine.

However, it’s not overridden from its base class, DbProviderFactory, which is implemented like so:

public virtual DbDataSourceEnumerator CreateDataSourceEnumerator()
{
    return null;
}

Filed under: .Net Basics

How to return an empty IEnumerable using yield?

UPDATE:

IEnumerable<Foo> GetFooItems()
{
        yield break;
}

…is what I want.


Given a method that returns an IEnumerable, you can use the C# 2.0 “yield” statement to return the next item in the enumeration. What if you want to return an empty enumeration? The only way I’ve found to do this is the following:

    if (false)
          yield return null;

Any other ideas?

Filed under: .Net Basics

Another Connect Issue to Vote On!

There is a missing constant in the .Net framework. You are supposed to know that MouseEventArgs.Delta is expressed in increments of the constant WHEEL_DELTA, which is defined in WinUser.h. Sure, the MSDN docs have this value, but are we really supposed to hard code it when this statement also exists in the docs for the WM_MOUSEWHEEL message:

The delta was set to 120 to allow Microsoft or other vendors to build finer-resolution wheels in the future, including perhaps a freely-rotating wheel with no notches.

I suggested that the value be made available in the .Net framework (without having to write a C++/CLI class to compile in the value).

You can too… vote here: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=265810

Filed under: .Net Basics

What appear to be, by all observable accounts, hacks in the v2.0 BCL

I found this while reflectoring. It appears that certain generic types are preloaded in order to prime the JIT compiler, and reduce type allocation (setting up MethodTables and EEClasses) latency.

A reasonable thing to do, and probably testing of the framework found unsatisfactory results, so hacks were inserted, and clearly labeled. I wonder if a subsequent service pack will eliminate these?

Filed under: .Net Basics

Please vote for increasing the maximum path length (MAX_PATH) on Connect

Have paths larger than 260 characters? Most of us do these days. It’s scandalous that .Net 2.0 only supports 260 characters. Vote it up here: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=240812

They really do listen to these. Vote a 5 for important!

Filed under: .Net Basics

Getting more than 1000 results from a DirectorySearcher query

Ok, this isn’t exactly clear. Need to make a note of this so I don’t forget it. The DirectorySeacher only returns 1000 results when the defaults are used. This setting actually comes from an AD server, not the .Net stuff, or even the ADSI or LDAP protocol implementation which are under the covers. So, basically, it’s as good as hard-coded. ADSI helps out here, and we can take advantage of it, by just setting the DirectorySearcher.PageSize to a number besides 0. I like to set it to the DirectorySearcher.SizeLimit default which is 1000 (actually, it’s 0, but this means 1000). This actually makes ADSI make as many paged requests as needed to get the entire result set, not just the first SizeLimit records. The docs aren’t terribly clear on this, and I try to make repeated requests to the server until the resulting SearchResultsCollection’s Count property is less than the searcher’s PageSize property… which doesn’t work since ADSI has done this bit for me and now I’m sitting with all the results in the collection. Here’s how to get all the users (with a few properties) in the domain [in IronPython]:

import clr
from System import *
clr.AddReference("System.DirectoryServices")
from System.DirectoryServices import *
from System.Collections.Generic import *

searcher = DirectorySearcher()
searcher.PageSize = 1000

def GetDomainUsers():

  searcher.Filter = "(&(objectClass=user)(sAMAccountName=*)(!objectClass=computer))"
  searcher.PropertiesToLoad.Add("userPrincipalName")
  searcher.PropertiesToLoad.Add("userAccountControl")
  searcher.PropertiesToLoad.Add("sAMAccountName")
  l = List[SearchResult]()
  domainResults = searcher.FindAll()

  l.AddRange(domainResults)
  domainResults.Dispose() # Get rid of the unmanaged ADSI resources ASAP

return l

Filed under: .Net Basics

DirectoryInfo and Path rely on ancient technology – the sad story of MAX_PATH

NTFS is a very robust and well architected file system. I like it. I’ve looked at others, like WinFS (not really a core FS, just a layer on NTFS… but good technology idea nonetheless), ReiserFS 4 (my favorite, at least conceptually), XFS and JFS. NTFS plays in the same league with these higher performance creations from the previous age Unix heavyweights, including transactions (Vista and Longhorn), journaling, compression, encryption and a peerless access control system (in my experience). Along with all of this is support for paths which are 2^15 (32768) characters long. This beats the 260 chars of MS-DOS legacy.

Oddly, this is hardcoded into two places – Win32 and the CRT:

<WinBase.h> … #define MAX_PATH 260

<stdlib.h>      … #define _MAX_PATH 260 /* max. length of full pathname */

However, help is at hand… From the MSDN docs:

Note The C Runtime supports path lengths up to 32768 characters in length, but it is up to the operating system, specifically the file system, to support these longer paths. The sum of the fields should not exceed _MAX_PATH for full backwards compatibility with Windows 98 FAT32 file systems. Windows NT 4.0, Windows 2000, Windows XP Home Edition, Windows XP Professional, Windows Server 2003, and Windows Server 2003 NTFS file system supports paths up to 32768 characters in length, but only when using the Unicode APIs. When using long path names, prefix the path with the characters \? and use the Unicode versions of the C Runtime functions.

But, try creating a DirectoryInfo prefixed with \? … you’ll throw an exception since it contains an invalid path char (?). Too bad, since people are finally getting the hang of long file names… one more legacy to detract from the shininess of Vista.

I’ve opened a Connect issue… if you run into this, be sure to vote for it.

Filed under: .Net Basics

Code Generation in DataSet designer doesn’t change project namespace workaround

.Net adds a bunch of useful features, no doubt. Sometimes they trip over themselves though.
 
Take, for example, the "global" namepace. This allows you to create "namespaceless" code and probably has some benefits, though I wonder what they are (perhaps they aren’t necessarily for C#).
 
When you create an ASP.Net project, your code is placed in the "global" namespace. This is fine, because mostly you don’t care. However, it can cause problems. For instance, when you have an ASP.Net page called "Login", the generated class becomes "Login". In the code-gen which results in the classes that imlement your ASPX pages, there is no way to distinguish the Login class with the Login control which also exists in the global namespace. You get an error during runtime – "CS0030: Cannot convert type ‘ASP.login_aspx’ to ‘System.Web.UI.WebControls.Login’" and it shows the invalid cast which was generated: "((Login)(this)).AppRelativeVirtualPath = "~/Login.aspx";".
 
One of the ways you get around this is giving your code a namespace, which, in my estimation is a good thing to do to begin with – otherwise you will get runtime issues like these. And runtime issues are never good, especially when you can push those issues into designtime. This is where the problem noted in the title comes in. The DataSet designer isn’t aware of the namespace you give your code. There is no way to change the namespace of the project like in 2003. This is a step backward, VS folks.
 
The only real way around this is to put the DataSet in a separate project. I ended up doing this.

Filed under: .Net Basics