David Findley's Blog

My little home in the cloud.

February 2007 - Posts

VS.NET Macro To Group and Sort Your Using Statements

I try to follow a coding standard for organizing my using statements. System.* goes at the top and then other namespaces grouped together like this:

        using System;
        using System.Collections.Generic;
        using System.Configuration;
        using System.Data;
        using System.Data.SqlClient;
        using System.Web;
        using System.Web.Script.Services;
        using System.Web.Services;
        using System.Web.Services.Protocols;

        using Microsoft;
        using Microsoft.CSharp;

        using MyCompany;
        using MyCompany.Web;

I finally got tired enough of keeping this all sorted out that I made a VS.NET macro to do it for me. This macro will take the current selection, parse it for using statements, group and sort them like the above example.

Here's the macro code:

    Dim _usingPattern As Regex = New Regex( _
        "\s*(?<using>using\s*(?<group>\w+)[^;]*);", _
        RegexOptions.IgnoreCase _
        Or RegexOptions.Multiline _
        Or RegexOptions.ExplicitCapture _
        Or RegexOptions.CultureInvariant _
        Or RegexOptions.Compiled _
    )

    Public Sub SortUsing()
        If Not DTE.ActiveDocument Is Nothing Then
            Dim sel As TextSelection = DTE.ActiveDocument.Selection

            If sel.Text.Contains(vbCrLf) Then
                If sel.ActivePoint Is sel.BottomPoint Then sel.SwapAnchor()
                sel.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstColumn, True)
                sel.SwapAnchor()
                sel.EndOfLine(True)

                Dim groups As New SortedList(Of String, List(Of String))()
                For Each match As Match In _usingPattern.Matches(sel.Text)
                    Dim u As String = match.Groups("using").Value
                    Dim g As String = match.Groups("group").Value

                    ' System usings sort at the top
                    If g = "System" Then g = "_" + g

                    Dim list As List(Of String)
                    If Not groups.TryGetValue(g, list) Then
                        list = New List(Of String)()
                        groups.Add(g, list)
                    End If
                    list.Add(u)
                Next

                Dim builder As New StringBuilder()
                For Each group As KeyValuePair(Of String, List(Of String)) In groups
                    If builder.Length > 0 Then builder.AppendLine()
                    group.Value.Sort()
                    For Each line As String In group.Value
                        builder.Append(line)
                        builder.AppendLine(";")
                    Next
                Next

                sel.DeleteLeft()
                sel.Insert(builder.ToString())
            End If
        End If
    End Sub
Posted: Feb 07 2007, 10:20 PM by findleyd | with 3 comment(s)
Filed under: ,
Fix ReturnUrl When Sharing Forms Authentication with Multiple Web Applications

Scenario: You have two web applications www.mydomain.com and login.mydomain.com. The login site provides a centralized login application and www contains any number of web applications that should use the auth ticket issued by the login site.

The auth ticket can be setup to be shared across the two 3rd level domains no problem. The problem with this setup is that when the user requests a page on www and gets redirected to login the ReturnUrl query string parameter contains a relative path. As far as I know there are not any extensibility points on the FormsAuthenication or FormsAuthenticationModule classes that you can use to fix this. A quick and dirty fix is to use the EndRequest event in your global.asax like this:

 

   1:      protected void Application_EndRequest(object sender, EventArgs e)
   2:      {
   3:          string redirectUrl = this.Response.RedirectLocation;
   4:          if (!string.IsNullOrEmpty(redirectUrl))
   5:          {
   6:              this.Response.RedirectLocation = Regex.Replace(redirectUrl, "ReturnUrl=(?'url'.*)", delegate(Match m)
   7:              {
   8:                  string url = HttpUtility.UrlDecode(m.Groups["url"].Value);
   9:                  Uri u = new Uri(this.Request.Url, url);
  10:                  return string.Format("ReturnUrl={0}", HttpUtility.UrlEncode(u.ToString()));
  11:              }, RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
  12:          }
  13:      }

The basic idea is to intercept the redirect and process the returnurl query string parameter with a regex. This could also be wrapped up in it's own HttpModule. It's kind of cheezy I know but it seems to work.

Posted: Feb 06 2007, 11:01 AM by findleyd | with 1 comment(s)
Filed under:
A VS.NET Macro to Generate Machine Keys.

I needed to create a new machine key for an asp.net site. I found a couple of command line utils out on the web that would create a new key but I thought it would be easier to just have it avail in VS.NET. So, I threw together this little macro that will generate the machine key and insert it. Just run the macro while you have you web.config open in VS.NET. If you already have a machinekey it will find it and replace it. If not it will just add it right after the <system.web> node. It should do the proper indents and everything too.

   1:  Imports System
   2:  Imports EnvDTE
   3:  Imports EnvDTE80
   4:  Imports System.Diagnostics
   5:   
   6:  Public Module AspNetUtils
   7:   
   8:  #Region "Helper Code"
   9:   
  10:      Dim _rng As New System.Security.Cryptography.RNGCryptoServiceProvider()
  11:   
  12:      Private Function GetRandomData(ByVal size As Integer) As Byte()
  13:          Dim randomData(size) As Byte
  14:          _rng.GetBytes(randomData)
  15:          Return randomData
  16:      End Function
  17:   
  18:      Private Function ToHex(ByVal data() As Byte) As String
  19:          Dim sb As New System.Text.StringBuilder()
  20:          For i As Integer = 0 To data.Length - 1
  21:              sb.AppendFormat("{0:X2}", data(i))
  22:          Next
  23:          Return sb.ToString()
  24:      End Function
  25:   
  26:      Private Sub WriteNewMachineKey(ByVal sel As TextSelection)
  27:          sel.Insert("<machineKey")
  28:          sel.NewLine()
  29:          sel.Insert(String.Format("validationKey='{0}'", ToHex(GetRandomData(63))))
  30:          sel.NewLine()
  31:          sel.Insert(String.Format("decryptionKey='{0}'", ToHex(GetRandomData(23))))
  32:          sel.NewLine()
  33:          sel.Insert("decryption='SHA1'")
  34:          sel.NewLine()
  35:          sel.Insert("/>", vsInsertFlags.vsInsertFlagsContainNewText)
  36:          sel.Unindent()
  37:          sel.Collapse()
  38:      End Sub
  39:   
  40:  #End Region
  41:   
  42:  #Region "Macros"
  43:   
  44:      Public Sub GenerateMachineKey()
  45:          If Not DTE.ActiveDocument Is Nothing AndAlso DTE.ActiveDocument.Name.ToLower() = "web.config" Then
  46:              Dim sel As TextSelection = DTE.ActiveDocument.Selection
  47:   
  48:              If sel.FindPattern("\<machineKey((:b|\n)*:i=:q)*(:b|\n)*/\>", vsFindOptions.vsFindOptionsFromStart Or vsFindOptions.vsFindOptionsMatchInHiddenText Or vsFindOptions.vsFindOptionsRegularExpression) Then
  49:                  ' Replace an existing <machineKey /> element
  50:                  sel.Delete()
  51:                  WriteNewMachineKey(sel)
  52:              ElseIf sel.FindText("<system.web>", vsFindOptions.vsFindOptionsFromStart Or vsFindOptions.vsFindOptionsMatchInHiddenText) Then
  53:                  ' insert the new machineKey just after the <system.web> element
  54:                  sel.Collapse()
  55:                  sel.NewLine()
  56:                  WriteNewMachineKey(sel)
  57:              Else
  58:                  ' no <system.web> element found so just collapse the current selection and insert
  59:                  ' the new key at the cursor location
  60:                  sel.Collapse()
  61:                  WriteNewMachineKey(sel)
  62:              End If
  63:          End If
  64:      End Sub
  65:   
  66:  #End Region
  67:   
  68:  End Module
LearnExpression.com is live.

We recently launched our video tutorial site for Expression Web Designer. Dustin, our resident graphic artist is pumping out the video tutorials as well as designing the site using the tool. It's good to have some how to vids from a designers point of view. Watch this site throughout 2007 as he continues to expand the content.

Posted: Feb 02 2007, 06:34 PM by findleyd
Filed under:
More Posts