# 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]  | 
# Wednesday, October 08, 2008

Yep, this is a note to myself :-)

image

Life | Misc
Wednesday, October 08, 2008 3:08:24 PM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, July 24, 2008

I was searching for a colleague's blog in a "legacy search engine" ;-)... and found a page in Kay Giza's blog which linked "Niel Gräf" to somewhere. It wasn't his blog, It was a linked "Live Search":

http://search.live.com/results.aspx?mkt=de-de&FORM=TOOLBR&q="Nils+Gräf"&FORM=TOOLBR

Kay please don't take it personal... What we see is a foreign page calling into Live without encoding the URL properly. That is what every non technical publisher will do - because they do not know better!

1) Clicking the link will open Live.com and will also show show results - If you have German language settings:

image

But if you click on "Next Page" to brows the results:

image

2) If you have en-US settings you'll get nothing:
image

So what happens here?

1) Live.con does not encode the user input properly when using it to format links - that's bad!

2) Live.com strips out special characters - not nice.

Hope there will be improvement soon :-)

Thursday, July 24, 2008 11:32:39 AM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
# Tuesday, July 15, 2008

In his last post Jeff Atwood summarized really really nice the discussions I have (and had over the last year) while helping customers on large scaling web sites, service-oriented back-ends or just the plain old data access topic.

Thanks Jeff!

All others: Go read!

Tuesday, July 15, 2008 1:14:12 PM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
# Tuesday, June 10, 2008

I really enjoyed reading Nicks post here.

[...]

  • If you take a group of well-meaning and intelligent engineers,
  • and you give them a process that looks like a normal software development process**, and you train them on it, and they believe that this process works...
  • and you add SOA...
  • you get JaBOWS (Just a Bunch of Web Services).

    [...]

    Many companies out there trying to get on the SOA road fail by believing a tool can lead the way.

    We at devcoach use to say: SOA is not about engineering or architecture. It's a mind setting.

    Therefore a tool can at maximum support you on the long road towards service orientation.

  • Tuesday, June 10, 2008 9:54:40 AM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  |