# Monday, January 05, 2009

image
The best time to produce loads of code is when It’s cold outside …

Life | Misc
Monday, January 05, 2009 11:44:42 PM (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, December 24, 2008

That's all folks.

Wednesday, December 24, 2008 5:55:46 PM (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
# Saturday, December 06, 2008

I'm currently working on a project together with Jürgen Bayer (autor of the C# 2008 Codebook and the Visual C# 2008 Kompendium) that makes use of a lot of dependency injection. The configuration files are blown with fully qualified assembly names but how do you get them? Working for instance with custom providers for ASP.NET membership, ASP.NET profile or ASP.NET roles gets you in the same circumstances. In the past I fired up Red Gate's Reflector and loaded the needed assembly to copy the name. I like Reflector but that approach becomes pretty annoying. So I fired up my IDE and hacked down the following peace of code:

using System;
using System.Reflection;
using System.Windows.Forms;
using Microsoft.Win32;
 
namespace devcoach.Tools.AssemblyNameReader
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            // Install shell extension ...
            if (args == null || args.Length == 0)
            {
                using (var regkey =
                    Registry.CurrentUser.OpenSubKey("Software\\Classes", true))
                {
                    if (regkey == null) return;
                    using (var dllFileKey = regkey.CreateSubKey("dllfile"))
                    {
                        if (dllFileKey == null) return;
                        using (var shellKey = dllFileKey.CreateSubKey("shell"))
                        {
                            if (shellKey == null) return;
                            using (var readAsmNameKey =
                                shellKey.CreateSubKey("ReadAssemblyName"))
                            {
                                if (readAsmNameKey == null) return;
                                readAsmNameKey.SetValue(
                                        string.Empty,
                                        "Copy full name to clipboard...");
 
                                using (var commandKey =
                                   readAsmNameKey.CreateSubKey("command"))
                                {
                                    if (commandKey == null) return;
                                    commandKey.SetValue(
                                        "",
                                        string.Concat(
                                            "\"",
                                            Application.ExecutablePath,
                                            "\" \"%1\""));
                                }
                            }
                        }
                    }
                }
                return;
            }
 
            Assembly assembly = null;
            try
            {
                assembly = Assembly.LoadFile(args[0]);
            }
            catch(Exception){}
 
            if (assembly == null)
            {
                MessageBox.Show(
                    "Error loading assembly...",
                    "Error",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
                return;
            }
            var name = assembly.FullName;
            if (string.IsNullOrEmpty(name)) return;
 
            Clipboard.SetDataObject(name, true);
        }
    }
}

Now I can use the a right click on any assembly to copy its fully qualified name to my clipboard.

image

Saturday, December 06, 2008 9:25:46 PM (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
# Friday, December 05, 2008

Kostja invited Michael and me to speak at the next event of the .net user group in Frankfurt (Germany). We'll show some real project implementations and tell stories from the technology and architecture trenches.

The event will be hosted at Microsoft in Bad Homburg. Further details can be found here...

Friday, December 05, 2008 3:06:07 PM (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, November 12, 2008

image 

The user group met today at netzkern, a company in Wuppertal specialized in .net development and SiteCore - thanks the venue and drinks! Thanks to Matthias for the pic!

This time we had "Sliverlight 2 in the real world" as a topic presented by Florian Kruesch. He presented new visual features as well as use cases and projects he's working on. Because he didn't touch the non-visual stuff like Isolated Storage he invited me to show something that I've build with the bits:

The "Silverlight Cache" for javascript - most commonly used to cache json returned by web services.

image

A lovely way to reduce traffic :-)

Wednesday, November 12, 2008 10:23:58 PM (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
# Monday, October 27, 2008

image

The first day of PDC is almost gone. I met my former Boss Clemens Vasters had a nice conversation during lunch with John Lam and "a guy with a blue shirt" that I'm not allow to cite here :-).

image

Micheal Willers, Ron Jacobs and I talked about SOA, Dublin, OSLO and the sometimes hard job trying to explain people the problems they will have in the feature (commonly known as archtecture :-P).

image

I was a bit disappointed by the "ASP.NET 4.0 roadmap" because I expected more "visions" and ideas -  Phil Haack showed mostly stuff that is available today (actually really today on codeplex...).

Monday, October 27, 2008 11:22:20 PM (W. Europe Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
# Monday, October 20, 2008

In reply to Scott Hanselmann's post on freeing up disc space I'd like to share a batch that I've written some time ago to clear different temp directories for instance before I run a backup. the referenced file "cleanup.txt" just contains the text "yes" (w/o quotes) to automate the cacls command.

 

@Echo off
for /f "tokens=3 delims=\" %%i in ("%USERPROFILE%") do (set user=%%i) 2>&1

@Echo on

del /F /S /Q "C:\Users\%user%\AppData\Local\Microsoft\WebsiteCache\*.*"
del /F /S /Q "C:\Users\%user%\AppData\Local\Microsoft\Windows\Burn\Burn\*.*"
del /F /S /Q "C:\Users\%user%\AppData\Local\Microsoft\Microsoft SQL Server Data\SQLEXPRESS\*.*"
del /F /S /Q "C:\Users\%user%\AppData\Local\Microsoft\Media Player\Transcoded Files Cache\*.*"
del /F /S /Q "C:\Users\%user%\AppData\Local\Temp\*.*"
rmdir "C:\Users\%user%\AppData\Local\Temp" /S /Q
mkdir "C:\Users\%user%\AppData\Local\Temp"

del /F /S /Q "C:\Users\%user%\AppData\Local\Microsoft\Team Foundation\1.0\Cache\*.*"
del /F /S /Q "C:\Users\%user%\AppData\Local\Microsoft\Windows\Temporary Internet Files\*.*"
del /F /S /Q "C:\Users\%user%\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.Outlook\*.*"
del /F /S /Q "C:\Users\%user%\AppData\Local\Microsoft\Windows\Temporary Internet Files\WebTempDir\*.*"
del /F /S /Q "C:\Users\%user%\AppData\Local\Microsoft\Windows\WER\ReportArchive\*.*"
del /F /S /Q "C:\Users\%user%\AppData\Local\Microsoft\Windows\WER\ReportQueue\*.*"
del /F /S /Q "C:\Users\%user%\AppData\Local\Microsoft\Microsoft SQL Server Data\SQLEXPRESS\*.*"

del /F /S /Q "C:\Users\%user%\AppData\Local\Microsoft\Media Player\Transcoded Files Cache\*.*"
rmdir "C:\Users\%user%\AppData\Local\Microsoft\Media Player\Transcoded Files Cache" /S /Q

del /F /S /Q "C:\Users\%user%\AppData\Roaming\Microsoft\Web Server Extensions\Cache\*.*"

rmdir  "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files" /S /Q
mkdir "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files"
cacls "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files" /g "System":F < "D:\Tools\cleanup.txt"
cacls "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files" /e /g "Administrators":F < "D:\Tools\cleanup.txt"
cacls "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files" /e /g "Network Service":F < "D:\Tools\cleanup.txt"
cacls "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files" /e /g "IISWPG":F < "D:\Tools\cleanup.txt"

del /F /S /Q "C:\Windows\Temp\*.*"
rmdir  "C:\Windows\Temp" /S /Q
mkdir "C:\Windows\Temp"
cacls "C:\Windows\Temp" /g "System":F < "D:\Tools\cleanup.txt"
cacls "C:\Windows\Temp" /e /g "Users":F < "D:\Tools\cleanup.txt"
cacls "C:\Windows\Temp" /e /g "Administrators":F < "D:\Tools\cleanup.txt"
cacls "C:\Windows\Temp" /e /g "Network Service":F < "D:\Tools\cleanup.txt"

del /F /S /Q "C:\Windows\Downloaded Program Files\*.*"

rmdir  "C:\MSOCache" /S /Q
rmdir "C:\SWSetup" /S /Q

pause

Life | Misc
Monday, October 20, 2008 3:33:20 PM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
# Saturday, October 18, 2008

What is life without security. In the last posts I told you how to do URLRewriting with the ASP.NET 3.5 RoutingEngine and how to pass query strings to the destination Web Form. In this post I'll add some authorization code to let ASP.NET Authentication mechanisms play well.

The first step is to figure out which authentication mechanism has taken place in the local configuration file. For the case of forms based authentication it would be nice to redirect to the configured login Web Form, for all other authentication mechanisms we can only throw a security exception and set a HTTP status code.

I only wanted this operation to be executed once and therefore I implemented as static and thread safe property with a backing field and a lock object:

private static string s_authenticationType;
private static object s_authenticationTypeLock = new object();
private static string AuthenticationType
{
    get
    {
        if (string.IsNullOrEmpty(s_authenticationType))
        {
            lock (s_authenticationTypeLock)
            {
                if (string.IsNullOrEmpty(s_authenticationType))
                {
                    var authenticationSectionObject =
                        WebConfigurationManager.GetSection(
                        "system.web/authentication");

                    var authenticationSection =
                        authenticationSectionObject
                            as AuthenticationSection;

                    if (authenticationSection != null)
                    {
                        s_authenticationType =
                            authenticationSection.Mode.ToString();
                    }
                }
            }
        }
        return s_authenticationType;
    }
}

 

Now its time to check the authorization on the target Web Form:

if (httpContext != null &&
    !UrlAuthorizationModule.CheckUrlAccessForPrincipal(
        VirtualPath,
        httpContext.User,
        httpContext.Request.HttpMethod))
{
    if (AuthenticationType.
        Equals("forms", StringComparison.OrdinalIgnoreCase))
    {
        VirtualPath = FormsAuthentication.LoginUrl;
        queryString =
            new StringBuilder(
                string.Concat(
                    "?ReturnUrl=",
                    requestContext.HttpContext.Server.UrlEncode(
                        requestContext.HttpContext.Request.RawUrl
                        )));
    }
    else
    {
        throw (new SecurityException());
    }
}

Next I will add a login Web Form to the site and drop a LoginControl to the form:

image

And add some code behind:

using System;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class login : Page
{
    protected void OnLoggingIn(object sender, LoginCancelEventArgs e)
    {
        //TODO: add some auth logic or use membership...
        FormsAuthentication.RedirectFromLoginPage(
            "lennybacon", 
            false);
    }
}

Authorization requires an authorization and therefore I enable ASP.NET forms based authentication that also is compatible to ASP.NET Membership in the configuration file:

<configuration>
  <system.web>
    <authentication mode="Forms"/>
...

 

I can configure the authorization settings for the destination Web Forms are also in the web.config file by adding location sections:

<configuration>
  ...
  <location path="Default2.aspx">
    <system.web>
      <authorization>
        <deny users="?"/>
      </authorization>
    </system.web>
  </location>
...

 

Running the web site and clicking the link to the route (/other) that targets the Default2.aspx results in showing up the login.aspx.

image

Notice that the address bar has not changed - the usual roundtrip for redirecting to the loginURL is also "rewritten" inside of ASP.NET.

 

This way the security is easily plugged into the RoutingHandler class - Cool stuff! 

Article | ASP.NET | C#
Saturday, October 18, 2008 8:56:33 PM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [1]  | 
# Thursday, October 16, 2008

In the last post I showed how to use the ASP.NET 3.5 Routing Engine for URLRewriting purposes. I want to go further in this post by adding the ability to add variables into a route path and forward and append query string variables to the destination Web Form request.

A route can contain one or more variables expressed by its {name}.

 
RouteTable.Routes.Add( 
    new Route(
        "articles/{id}", 
        new devcoach.Web.RoutingPageHandler()));

 

Inside of the RoutingHandler we can iterate through the variables by accessing them by the RouteData property on the parameter passing the RequestContext:

 

var queryString = new StringBuilder("?");
foreach (var aux in requestContext.RouteData.Values)
{
    queryString.Append(
        requestContext.HttpContext.Server.UrlEncode(aux.Key));
    queryString.Append("=");
    queryString.Append(
        requestContext.HttpContext.Server.UrlEncode(
            aux.Value.ToString()));
    queryString.Append("&");
}
queryString.Remove(queryString.Length - 1, 1);

 

The problem now is that the method CreateInstanceFromVirtualPath of the BuildManager class does not allow us to pass for instance a query string as a parameter (I had this discussion recently with Holger at the speakers party of the Basta! confrence):

 

var handler = 
    (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath(
        VirtualPath,
        typeof(Page));

 

Passing URL Parameters (a query string) to the instance of the page created from its virtual path we can use the good old RewitePath method (which should be familiar for everyone who has rewritten URLs with ASP.NET 2.0):

 

HttpContext.Current.RewritePath(
    string.Concat(
        VirtualPath,
        queryString));

var handler =
    (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath(
        VirtualPath,
        typeof(Page));

 

It feels a bit strange to use the old fashioned way of rewriting URLs just to pass a query string, but the routing handler will stay in control of the request and only the context  variables gets modified.

 Listening to: Elbow - Grounds for Divorce

Article | ASP.NET | C#
Thursday, October 16, 2008 5:26:29 PM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [2]  | 
# Wednesday, October 15, 2008

With ASP.NET MVC comes a component that is called the routing engine. In ASP.NET MVC it is responsible to assign a controller to an incoming request:

image

From an conceptional view the routing engine consists of two parts:

a) The RouteTable which stores the information which routes are defined

b) The UrlRoutingModule which finds matches to routes on incoming requests.

image

But the routing engine is not limited to MVC in its use. The ASP.NET 3.5 Routing Engine is a powerful instrument for URLRewriting.

Lets have a look how to use routing standalone or with classic ASP.NET (wow, now its already classic! Never dreamed that this would happen so fast... But hey, the .NET platform is nearly ten years old...):

1. First I added the HttpModule to you configuration file:

<httpModules>
  <add 
   name="urlRouting"   
   type="System.Web.Routing.UrlRoutingModule, 
         System.Web.Routing, 
         Version=3.5.0.0, 
         Culture=neutral, 
         PublicKeyToken=31BF3856AD364E35"/>

2. Second I created a routing handler by implementing the IRouteHandler interface which comes from System.Web.Routing. I've put a simple if-else together to route to different pages:

using System.Web;
using System.Web.Compilation;
using System.Web.Routing;

namespace devcoach.Web
{
    public class RoutingPageHandler 
        : IRouteHandler
    {
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
         var VirtualPath = pathData.VirtualPath.Contains("articles") 
                ? "~/Default.aspx" 
                : "~/Default2.aspx";

            var handler = (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath(
                VirtualPath,
                typeof(Page));

            return handler;
        }
    }
}
 

3. Third I registered the routes to the RouteTable from within the Global.asax file:

<%@ Import Namespace="devcoach.Web"%>
<%@ Import Namespace="System.Web.Routing"%>
<%@ Application Language="C#" %>
 
<script runat="server">  
static void RegisterRoutes()
{
    RouteTable.Routes.Add(
        new Route(
            "articles", 
            new RoutingPageHandler()));
            
    RouteTable.Routes.Add(
        new Route(
            "other", 
            new RoutingPageHandler()));        
}
void Application_Start(object sender, EventArgs e)
{
    RegisterRoutes();
} 
 
And here we go already:
image 
 
Basic URLRewiting in a few minutes. Quite neat, eh. Definitely worth a try... 
 
Now listening to: Flobots - Handlebars
Article | ASP.NET | C#
Wednesday, October 15, 2008 1:17:33 AM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [1]  |