SoftDev

C# And Visual Basic Generate Different Expression Trees


(This was pointed out to me by Frans Bouma and explained by Jon Skeet)


Imagine you have this set of classes:

public class A
{
public virtual string P
{
get { return "A"; }
}
}

public class B : A
{
}

public class C : B
{
public override string P
{
get { return "C"; }
}
}


And this class:

public static class Reporter
{
public static void Report<T>(T target, Expression<Func<T, string>> expression)
{
Console.WriteLine("Expression: {0}", expression);
Console.WriteLine("\tDeclaring Type: {0}", ((expression as LambdaExpression).Body as MemberExpression).Member.DeclaringType);
Console.WriteLine("\tInvocation Result: {0} for {1}", expression.Compile().Invoke(target), target.GetType());
Console.WriteLine();
}
}

The above class writes to the console the lambda expression, the declaring type of the property and the value of the property for the target and the target’s type.


Now, let’s look at what happens when used from this C# code:

Reporter.Report(new C(), (A a) => a.P);
Reporter.Report(new C(), (B b) => b.P);
Reporter.Report(new C(), (C c) => c.P);

Reporter.Report(new B(), (A a) => a.P);
Reporter.Report(new B(), (B b) => b.P);

Reporter.Report(new A(), (A a) => a.P);


The output will be:

Expression: a => a.P
Declaring Type: A
Invocation Result: C for C

Expression: b => b.P
Declaring Type: A
Invocation Result: C for C

Expression: c => c.P
Declaring Type: A
Invocation Result: C for C

Expression: a => a.P
Declaring Type: A
Invocation Result: A for B

Expression: b => b.P
Declaring Type: A
Invocation Result: A for B

Expression: a => a.P
Declaring Type: A
Invocation Result: A for A


On the other hand, if used from the equivalent Visual Basic code:

Reporter.Report(New C(), Function(a As A) a.P)
Reporter.Report(New C(), Function(b As B) b.P)
Reporter.Report(New C(), Function(c As C) c.P)

Reporter.Report(New B(), Function(a As A) a.P)
Reporter.Report(New B(), Function(b As B) b.P)

Reporter.Report(New A(), Function(a As A) a.P)


The output will be:

Expression: a => a.P
Declaring Type: A
Invocation Result: C for C

Expression: b => b.P
Declaring Type: A
Invocation Result: C for C

Expression: c => c.P
Declaring Type: C
Invocation Result: C for C

Expression: a => a.P
Declaring Type: A
Invocation Result: A for B

Expression: b => b.P
Declaring Type: A
Invocation Result: A for B

Expression: a => a.P
Declaring Type: A
Invocation Result: A for A


Why the differences? It’s because of each language’s specification and compiler:



  • The C# compiler will issue a virtual call to the virtual member in the class where it’s declared as virtual.

  • The Visual Basic compiler will issue a virtual call to the overriding member on the class that overrides it.

IIS/ASP.NET Cookieless Support Not Working As Expected

In one of the environments I work, cookies cannot be used because the pages run inside web browser controls running on a client application and cookies end up being shared by all browsers.

Fortunately, ASP.NET allows us to persist some cookies as part of the URL.

To persist the session state identifier cookie in the URL we just need to add the following configuration:

<configuration>
  <system.web>
    <sessionState cookieless="UseUri" />
  </system.web>
</configuration>

and you’ll get URLs like this:

http://localhost/Cookieless/(S(jcmwek3ja0lvdpbwoacpjirv))/default.aspx

The way IIS and ASP.NET do this is by IIS removing the section between parenthesis after the virtual directory path and adding the AspFilterSessionId HTTP header to the request. Than, ASP.NET picks it up and extracts the cookie.

I wrote this simple page to demonstrate this working:

<%@ Page Language="C#" AutoEventWireup="true" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <table>
            <tr>
                <td>Raw URL</td>
                <td><%= Request.RawUrl %></td>
            </tr>
            <tr>
                <td>Cookiless Cookies<br />AspFilterSessionId Request HTTP Header</td>
                <td><%= Request.Headers["AspFilterSessionId"] %></td>
            </tr>
            <tr>
                <td>Session ID</td>
                <td><%= Session.SessionID %></td>
            </tr>
        </table>
    </div>
    </form>
</body>
</html>

For the above URL, we'll get a page like this:

Raw URL /Cookieless/default.aspx
Cookiless Cookies

AspFilterSessionId Request HTTP Header
S(jcmwek3ja0lvdpbwoacpjirv)
Session ID jcmwek3ja0lvdpbwoacpjirv

IIS strips these cookies even for serving static content like cascading stylesheets.

You can test this by creating a default theme. You can do this by adding a Default folder under the App_Themes folder and adding a Styles.css file to it:

body
{
    background-color: Yellow;
}
table, tr, td
{
    border: thin solid black;
}

and setting the theme as default using the following configuration:

<configuration> <system.web> <sessionState cookieless="UseUri" /> <pages theme="Default"/> </system.web> </configuration>

And you'll get a "pretier" page:

Raw URL /Cookieless/default.aspx
Cookiless Cookies

AspFilterSessionId Request HTTP Header
S(jcmwek3ja0lvdpbwoacpjirv)
Session ID jcmwek3ja0lvdpbwoacpjirv

If you have special needs for your session state identifiers, you can implement your own session identifier manager.

But if you want to use cookieless cookies, you only have one way to do it: extend the SessionIDManager class:

public class SessionIdManager : System.Web.SessionState.SessionIDManager
{
    public override string CreateSessionID(System.Web.HttpContext context)
    {
        string id = System.Guid.NewGuid().ToString("B");

        return id;
    }

    public override bool Validate(string id)
    {
        try
        {
            new System.Guid(id);
            return true;
        }
        catch
        {
            return false;
        }
    }
}

and configure the session state module to use it:

<configuration>
  <system.web>
    <sessionState cookieless="UseUri" sessionIDManagerType="SessionIdManager" />
    <pages theme="Default"/>
  </system.web>
</configuration>

And we'll end up with this nice page:

http://localhost/Cookieless/(S(%7b0861e55a-e29b-4b6f-825b-1e1d4c57f095%7d))/default.aspx

Raw URL /Cookieless/(S({0861e55a-e29b-4b6f-825b-1e1d4c57f095}))/default.aspx
Cookiless Cookies

AspFilterSessionId Request HTTP Header
 
Session ID {0861e55a-e29b-4b6f-825b-1e1d4c57f095}

OOPS! What happened here?

Looks like IIS was unable to transfer the cookies to the appropriate HTTP header but ASP.NET was able to find the requested resource. On the other hand, IIS couldn’t find the http://localhost/Cookieless/(S(%7b0861e55a-e29b-4b6f-825b-1e1d4c57f095%7d))App_Themes/Default/Styles.css.

This happens in these environments:

Operating System IIS ASP.NET
Windows XP Pro SP3 5.1 2.0 SP1, 3.5
Windows Server 2003 R2 6 2.0 SP1, 3.5
Windows Server 2008 7 2.0 SP1, 3.5

Fortunately, in IIS 7 you can have HTTP modules in integrated pipeline mode that are called for every resource requested to IIS.

Your module doesn’t even need to do nothing. It just needs to exist:

public class Module : System.Web.IHttpModule
{
    public void Dispose()
    {
    }

    public void Init(System.Web.HttpApplication context)
    {
    }
}

and be added to the configuration:

<configuration>
  <system.web>
    <sessionState cookieless="UseUri" sessionIDManagerType="SessionIdManager" />
    <pages theme="Default"/>
  </system.web>
  <system.webServer>
    <modules>
      <add name="Module" preCondition="integratedMode" type="Module" />
    </modules>
  </system.webServer>
</configuration>

And our “pretty” page is back:

Raw URL /Cookieless/default.aspx
Cookiless Cookies

AspFilterSessionId Request HTTP Header
S({0861e55a-e29b-4b6f-825b-1e1d4c57f095})
Session ID {0861e55a-e29b-4b6f-825b-1e1d4c57f095}

Is it just me, or there’s something definitely wrong here?

That’s why I opened this bug on Microsoft Connect

Other Ways For Making PathInfo And ASP.NET Themes Work Together

On my last post I wrote about a solution for the problem that arises when we try the use path infos and ASP.NET Themes and Skins together.

Raj Kaimal suggested rewriting all LINK HTML elements URLs to the correct URL as seen from the client. Something like this:

void HttpApplicationPreRequestHandlerExecute(object sender, System.EventArgs e)
{
    var httpApplication = sender as System.Web.HttpApplication;

    var httpContext = httpApplication.Context;

    var page = httpContext.CurrentHandler as System.Web.UI.Page;

    if ((page != null) && !string.IsNullOrEmpty(httpContext.Request.PathInfo))
    {
        page.PreRenderComplete += delegate(object source, System.EventArgs args)
        {
            var p = source as System.Web.UI.Page;

            foreach (System.Web.UI.Control headerControl in p.Header.Controls)
            {
                var link = headerControl as System.Web.UI.HtmlControls.HtmlLink;
                if (link != null)
                {
                    link.Href = p.ResolveUrl(link.Href);
                }
            }
        };
    }
}

With this approach you still have a problem (which mine didn’t solve) with post backs because the rendering of the ACTION of the HTML FORM is also broken.

Israel Aéce suggested the use of the BASE HTML element to re-base relative URLs. Something like this:

void HttpApplicationPreRequestHandlerExecute(object sender, System.EventArgs e)
{
    var httpApplication = sender as System.Web.HttpApplication;

    var httpContext = httpApplication.Context;

    var page = httpContext.CurrentHandler as System.Web.UI.Page;

    if ((page != null) && !string.IsNullOrEmpty(httpContext.Request.PathInfo))
    {
        page.PreRenderComplete += delegate(object source, System.EventArgs args)
        {
            page.Init += delegate(object source, System.EventArgs args)
            {
                var p = source as System.Web.UI.Page;

                var htmlBase = new System.Web.UI.WebControls.WebControl(System.Web.UI.HtmlTextWriterTag.Base);
                htmlBase.Attributes.Add("href", p.Request.Url.GetLeftPart(System.UriPartial.Authority) + p.Request.CurrentExecutionFilePath);
                p.Header.Controls.Add(htmlBase);
            };
        };
    }
}

This seems like the better solution except if your site sits behind several security perimeters and it is not possible to be sure what the domain is as seem from the client side, which was my problem to begin with.

But if you are thinking of calling Server.Execute, Server.TransferRequest or Server.TransferRequest, neither of these two solutions will work.

Making PathInfo And ASP.NET Themes Work Together


Updated on 2008.07.28 – The code was done in a hurry and, talking to my friend Luís, I noticed that I had forgotten to make a case insensitive comparison and that the code was not so obvious. So, I updated the code and added an explanation.


On my last post I wrote about the problem that arises when we try the use path infos and ASP.NET Themes and Skins together.


But most of the times you don’t care about the why you can’t. You just want to know how you can.


The way I see it, the right solution would be to render the URLs for the stylesheets rooted.


But since I can’t do that, the next best thing is the serve the wrongly addressed request properly.


But how can we do that?


The only way I could come up with, was an HTTP Module:

public class AppThemesModule : global::System.Web.IHttpModule
{
private const string LocalThemesFolderName = "/App_Themes/";
private static readonly int searchStartIndex;
private static readonly int minimumLenghtForSearch;

static AppThemesModule()
{
int searchStartIndex = System.Web.HttpRuntime.AppDomainAppVirtualPath.Length;

AppThemesModule.searchStartIndex = ((searchStartIndex == 1) ? 0 : searchStartIndex) + 2;

AppThemesModule.minimumLenghtForSearch = AppThemesModule.searchStartIndex + AppThemesModule.LocalThemesFolderName.Length;
}

#region IHttpModule Members

public void Dispose()
{
}

public void Init(System.Web.HttpApplication context)
{
context.BeginRequest += HttpApplicationBeginRequest;
}

#endregion

void HttpApplicationBeginRequest(object sender, System.EventArgs e)
{
System.Web.HttpApplication httpApplication = sender as System.Web.HttpApplication;

string path = httpApplication.Request.Path;
if (path.Length > searchStartIndex)
{
int appThemesStartIndex = path.IndexOf(AppThemesModule.LocalThemesFolderName, searchStartIndex, System.StringComparison.OrdinalIgnoreCase);
if (appThemesStartIndex > 0)
{
httpApplication.Context.RewritePath("~" + path.Substring(appThemesStartIndex));
}
}
}
}


The code starts by initializing the static read-only field searchStartIndex with the start index of the search for the /App_Themes/ pattern. If the length of the application’s virtual path is 1, that means that it’s the root of the site and search start index is 0 instead of 1; otherwise the search start index will be the length of the application’s virtual path. 2 is added because there is no need to start searching the path just after the application’s virtual path (if the pattern was found just after the application’s virtual path, no replacement would be needed).


Than, the static read-only field minimumLenghtForSearch is initialized with the minimum length of the path to search for the pattern. There is no need to search for the pattern on paths shorter than the search start index plus the length of the pattern because, if found, no replacement would be needed.


Besides registering the module, you’ll have to configure your virtual directory so that all the files to be served out of the themes are handled by a StaticFileHandler.

PathInfo And ASP.NET Themes: Why Can’t They Work Together?

If you ever worked with ASP.NET Themes and Skins, you know that stylesheet links are added to the head section of the HTML document.

The rendered URL to these stylesheets is always relative to location of the page being requested.

So, for a request to:

http://MySite/Section/Default.aspx

you'll get:

<link href="../App_Themes/Default/Styles.css" type="text/css" rel="stylesheet" />

which will make the web browser request for:

http://MySite/App_Themes/Default/Styles.css

and it all works fine.

Well, it works fine until you need to navigate to:

http://MySite/Section/Default.aspx/PathInfo

You'll get the same stylesheet reference and the browser will request for:

http://MySite/Section/Default.aspx/App_Themes/Default/Styles.css

This happens because the web browser has no knowledge of what PathInfos are. It only accounts for the number of forward slashes (/).

I've filed a bug on Microsoft Connect about this.

Make The HttpValueCollection Class Public And Move It To System.DLL

I find the System.Web.HttpValueCollection class very useful in a wide number of situations that involve composing HTTP requests or any other need to represent name/value collection as a string (in an XML attribute, for example).

As of now (.NET Framework 3.5 SP1 Beta), the only way to create an instance of the System.Web.HttpValueCollection class is using the System.Web.HttpUtility.ParseQueryString method.

I’d like to see it public and available in a more generic assembly like System.DLL to be available on every type of .NET application (Windows Client applications, Windows Service applications, Silverlight applications, Windows Mobile applications, etc.).

If you agree with me, vote on my suggestion on Microsoft Connect.

BEWARE: System.Web.HttpValueCollection Parsing Is Not Reversible

If you run this code:

System.Collections.Specialized.NameValueCollection queryString = System.Web.HttpUtility.ParseQueryString("noKey&=emptyKey&A=Akey");

queryString will actually have the running type of System.Web.HttpValueCollection.

What's great about this class is that its ToString method output is the collection's content in a nice URL encoded format.

As with its base class (NameValueCollection), there’s a difference between a null string and an empty string key and the parsing treats query string parameters with no parameter specification as having a null string key and parameters with an empty string key having an empty string parameter key.

So, when call ToString on the instance returned by System.Web.HttpUtility.ParseQueryString method you would expect to get the parsed string (or, at least, one that would be parsed into the equivalent collection), right? But what you’ll get instead is this: noKey&emptyKey&A=Akey.

I’ve filed a bug into connect. If you think this is important and must be corrected, please vote.

Isolator 4.3 Released!

Today Typemock released version 4.3 of Typemock Isolator. Download it from here.

What’s new?

  • Support for Ivonna. For those of you who develop ASP.Net applications, Ivonna is a great tool, built on top of Isolator’s platform, to simplify writing tests for ASP.NET.
  • Typemock.Integration.Packs namespace APIs added to support license management through Isolator, the way Ivonna does.
  • As announced when it was released, version 4.2 was the last version of Isolator to support .NET 1.1. Version 4.3 only supports the 2.0 runtime and its Visual Studio counterparts: VS2005 and VS2008.
  • For 64 bit machines, now there’s a single installer. (don’t forget to uninstall both previous 32 and 64 installers prior to installing 4.3.)
  • RecorderManager.GetMockOf(instanceRef) and MockManager.GetMockOf(instanceRef). To retrieve the mock controller object based on a reference to the instance. (more...).

Bug fixes:

  • Fixes to DLINQ support. LINQ Queries with data tables now work better, for example with GroupBy.
  • Static constructors in Natural Mocks are now invoked correctly.
  • A bug that caused an exception to be thrown when mocking interfaces ("Method XX in type IMyInterface has no matching overload that returns TypeMock.Mock+a) was fixed.
  • A bug that caused an exception to be thrown when the mocked object was overriding Equals was fixed.
  • A bug that caused failure in mocking explicit interface with the same name was fixed.
  • A bug occurring im multithreading scenarios in VerifyWithWait was fixed.
  • A bug that causes NullReferenceException to be thrown when using Auto Deploy was fixed.

See also:

Why Use Random Values For Unit Testing

On a previous post I introduced a library for generating random values for purposes of unit testing.

I received a few comments and questions on my blogs [^][^][^][^].

Simon says that he’d “generally want every instance of the test I run to be repeatable on *every* run” and he’d “inclined to use the data source functionality in VSTS Unit Tests”. I couldn’t agree more.

Hugo pointed me to Pex. Looks nice. I’ll have to take a deeper look at it.

Other commenters were worried that in the case of a test failing to pass they were unable to reproduce the conditions of the test and thus would be unable to understand why the test had failed. As I see it, all data used in a failed test should be in the test output (at least, the data that made the test fail). Being it predictable data or random data.

I guess that most of the comments “against” my idea were due to the fact that I didn’t explain it well. I’ll try to do a better job now.

I use these random values when the value itself is not important, what’s important is its uniqueness.

Imagine you have  Costumer class where it’s enough to tell that the costumer is the same in any two given instances if the costumer ID is the same. In order to test the comparison code, I don’t need any particular reproducible set of values. I just need them to be different or the same depending on the test.

Imagine I have some code that needs to access the database with the connection string in a specific connection string settings element. I don’t care what the connection string is because I won’t be really accessing the database (this is really easy to accomplish with Isolator).

I hope I’ve explained myself better this time.

Replacing Loaded Assemblies

Recently I’ve been asked if it would be possible to replace the assemblies loaded by a .NET Windows Service application while it was running like with ASP.NET. Like with ASP.NET, an application start and end events where needed.

The solution is quite simple. The Windows Service application is just a loader that has no references to the loaded assemblies that might change have an assembly with an entry point that acts as the start event. This assembly must be loaded in a new AppDomain with ShadowCopyFiles set. The end event is handled by handling the DomainUnload event of the AppDomian where the running assembly is loaded.

If you want to have the running assembly and its referenced assemblies unloaded and reloaded whenever a change occurs in the assembly files, a FileSystemWatcher could be used, although I would prefer to override such behavior in ASP.NET, not copy it.

An assembly loader can be as simple as this:

class Program
{
    private static Thread thread = null;
    private static AppDomain appDomain = null;

    static void Main(string[] args)
    {
        while (true)
        {
            Console.WriteLine();
            Console.WriteLine("Options:");
            if (appDomain == null)
            {
                Console.WriteLine("    L - Load");
            }
            else
            {
                Console.WriteLine("    U - Unload");
            }
            Console.WriteLine("    X - Exit");

            switch (Console.ReadKey().KeyChar)
            {
                case 'l':
                case 'L':
                    thread = new Thread(Load);
                    thread.Name = "Runner";
                    thread.Start(args);
                    while (appDomain == null) ;
                    break;
                case 'u':
                case 'U':
                    Unload();
                    break;
                case 'x':
                case 'X':
                    Unload();
                    return;
            }
        }
    }

    private static void Load(object obj)
    {
        string[] args = obj as string[];

        AppDomainSetup appDomainSetup = new AppDomainSetup();
        appDomainSetup.ApplicationBase = args[0];
        appDomainSetup.PrivateBinPath = args[0];
        appDomainSetup.ShadowCopyFiles = "true";

        appDomain = AppDomain.CreateDomain("Runner", AppDomain.CurrentDomain.Evidence, appDomainSetup);

        appDomain.ExecuteAssemblyByName("ConsoleApplication", AppDomain.CurrentDomain.Evidence, new string[0]);
    }

    private static void Unload()
    {
        AppDomain.Unload(appDomain);
        appDomain = null;
        thread = null;
    }
}

The loader receives the path for the assembly to run and its name and loads it.

And the assembly to run as simple as this:

class Program
{
    static readonly DateTime dateTime = DateTime.Now;

    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.DomainUnload += delegate
        {
            Console.WriteLine();
            Console.WriteLine("Unloading: {0}", dateTime);
        };

        System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();

        Console.WriteLine("Loading: {0}", dateTime);
        Console.WriteLine("Assembly: {0}", assembly.FullName);
        Console.WriteLine("Location: {0}", assembly.Location);

        FileInfo fileInfo = new FileInfo(assembly.Location);
        Console.WriteLine("Location Dates: CreationTime={0}, LastWriteTime={1}, LastAccessTime={2}",
            fileInfo.CreationTime, fileInfo.LastWriteTime, fileInfo.LastAccessTime);

        while (true)
        {
            Console.Write('.');
            Thread.Sleep(100);
        }
    }
}

With this “system” you can replace the running assembly and load or unload it whenever you want to.