Internet Proxy Monitor

Wednesday, 09 September 2009 07:12 PM
by Coose

Our company enabled the Internet Explorer Proxy via group policy a while back to “improve performance”.  The improvement is about 10 times slower than it was before.  They insist that it is faster, but they are WRONG (yes Ken and Kevin…I’m talking about you).  Not only is it much slower, but the “bypass proxy on local addresses” doesn’t work right, so our WCF endpoints don’t work correctly without configuring them for the proxy (which we can only use message security if we do this).

[more Read on for my solution…]

Our group policy typically has these options disabled.  So it’s quite frustrating to need to turn that off for WCF.  Obviously FireFox fixed the problem for web browsing, but for WCF, this was still a problem.

So, I wrote a C# program to poll the Internet Options proxy settings, and notify me when the settings are changed, display an icon on the tray to remind me, and gives me a one-click option to toggle the proxy off when needed, then back on.  It’s not a terribly complicated program, but it demonstrates two interesting points:

  1. P/Invoke variable sized arrays
  2. WinForms application with NotifyIcon without having a Form at all by using a custom ApplicationContext.

So, to create a Formless Windows Forms Application, create a new Windows Forms Application, and remove the form.  Then create a new class deriving from ApplicationContext.  Add relevant code.  My proxy code looks like this:

    1 class ProxyMonitorApplicationContext : ApplicationContext

    2 {

    3     private Container _components;

    4     private NotifyIcon _notifyIcon;

    5     private ContextMenu _menu;

    6     private Timer _timer;

    7     private bool? _enabled;

    8 

    9     public ProxyMonitorApplicationContext()

   10     {

   11         this.InitializeContext();   

   12     }

   13 

   14     protected void InitializeContext()

   15     {

   16         _components = new Container();

   17 

   18         _menu = new ContextMenu(new MenuItem[] {

   19             new MenuItem(Resources.ToggleMenu, new EventHandler(this.Menu_ToggleClicked)),

   20             new MenuItem(Resources.ExitMenu, new EventHandler(this.Menu_ExitClicked))

   21             }

   22         );

   23 

   24         _notifyIcon = new NotifyIcon(_components);

   25         _notifyIcon.Visible = true;

   26         _notifyIcon.MouseClick += new MouseEventHandler(NotifyIcon_MouseClick);

   27         _notifyIcon.BalloonTipClicked += new EventHandler(NotifyIcon_BalloonTipClicked);

   28         _notifyIcon.ContextMenu = _menu;

   29 

   30         _timer = new Timer(_components);

   31         _timer.Enabled = true;

   32         _timer.Interval = Settings.Default.QueryInterval;

   33         _timer.Tick += new EventHandler(Timer_Tick);

   34 

   35         UpdateStatus(false);

   36     }

   37 

   38     protected override void Dispose(bool disposing)

   39     {

   40         if (disposing && (this._components != null))

   41         {

   42             this._components.Dispose();

   43             _notifyIcon.Dispose();

   44             _timer.Dispose();

   45             _menu.Dispose();

   46         }

   47         base.Dispose(disposing);

   48     }

   49 

   50     private void Timer_Tick(object sender, EventArgs e)

   51     {

   52         bool enabled = InternetOptionsProxy.IsProxyEnabled();

   53         if (_enabled != enabled)

   54         {

   55             UpdateStatus(true);

   56             ShowNotification();

   57         }

   58         _enabled = enabled;

   59     }

   60 

   61     void NotifyIcon_MouseClick(object sender, MouseEventArgs e)

   62     {

   63         if (e.Button == MouseButtons.Left)

   64         {

   65             UpdateStatus(false);

   66             ShowNotification();

   67         }

   68     }

   69 

   70     void NotifyIcon_BalloonTipClicked(object sender, EventArgs e)

   71     {

   72         ToggleStatus();

   73     }

   74 

   75     void Menu_ToggleClicked(object sender, EventArgs e)

   76     {

   77         ToggleStatus();

   78     }

   79 

   80     void Menu_ExitClicked(object sender, EventArgs e)

   81     {

   82         this.ExitThread();

   83     }

   84 

   85     private void ShowNotification()

   86     {

   87         _notifyIcon.BalloonTipTitle = (this._enabled.HasValue && this._enabled.Value)

   88             ? Resources.EnabledTitle

   89             : Resources.DisabledTitle;

   90         _notifyIcon.BalloonTipText = (this._enabled.HasValue && this._enabled.Value)

   91             ? Resources.EnabledMessage

   92             : Resources.DisabledMessage;

   93         _notifyIcon.BalloonTipIcon = (this._enabled.HasValue && this._enabled.Value)

   94             ? ToolTipIcon.Warning

   95             : ToolTipIcon.Info;

   96         _notifyIcon.ShowBalloonTip(Settings.Default.NotificationDuration);

   97     }

   98 

   99     private void ToggleStatus()

  100     {

  101         InternetOptionsProxy.EnableProxy((_enabled == null || _enabled.Value == false));

  102         UpdateStatus(false);

  103     }

  104 

  105     private void UpdateStatus(bool popupIfChanged)

  106     {

  107         bool enabled = InternetOptionsProxy.IsProxyEnabled();

  108         bool changed = _enabled != enabled;

  109         if (!changed) return;

  110 

  111         _enabled = enabled;

  112         if (changed && popupIfChanged)

  113         {

  114             ShowNotification();

  115         }

  116 

  117         _notifyIcon.Text = (this._enabled.HasValue && this._enabled.Value)

  118             ? Resources.EnabledTitle

  119             : Resources.DisabledTitle;

  120         _notifyIcon.BalloonTipTitle = _notifyIcon.Text;

  121         _notifyIcon.BalloonTipText = (this._enabled.HasValue && this._enabled.Value)

  122             ? Resources.EnabledMessage

  123             : Resources.DisabledMessage;

  124         _notifyIcon.Icon = new Icon(

  125             (this._enabled.HasValue && this._enabled.Value)

  126             ? Resources.ProxyEnabled :

  127             Resources.ProxyDisabled, new Size(16, 16)

  128         );

  129     }

  130 }

Essentially, just make an InitializeComponent method, to create an initialize the components that are typically sited on a Form, and be sure to override the Dispose method.

Then create a Program.cs or whatever class you like for the static Main method.  In the Application.Run method, pass a new instance of your context instead of the default form.

    1 [STAThread]

    2 static void Main()

    3 {

    4     Application.EnableVisualStyles();

    5     Application.SetCompatibleTextRenderingDefault(false);

    6     Application.Run(new ProxyMonitorApplicationContext());

    7 }

 

Now, we will P/Invoke methods to actually turn on and off the Internet proxy server.  So here’s the P/Invoke signatures that I used:

    1 internal static class NativeMethods

    2 {

    3     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]

    4     public class INTERNET_PER_CONN_OPTION_LIST

    5     {

    6         public int dwSize;

    7         [MarshalAs(UnmanagedType.LPWStr)]

    8         public string pszConnection;

    9         public int dwOptionCount;

   10         public int dwOptionError;

   11         public IntPtr pOptions;

   12     }

   13 

   14     [StructLayout(LayoutKind.Explicit, Size = 12)]

   15     public struct INTERNET_PER_CONN_OPTION

   16     {

   17         // Fields

   18         [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]

   19         [FieldOffset(0)]

   20         public int dwOption;

   21         [FieldOffset(4)]

   22         public IntPtr ptrValue;

   23     }

   24 

   25     public const int PROXY_TYPE_AUTO_DETECT = 8;

   26     public const int PROXY_TYPE_AUTO_PROXY_URL = 4;

   27     public const int PROXY_TYPE_DIRECT = 1;

   28     public const int PROXY_TYPE_PROXY = 2;

   29     public const int INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME = 8;

   30     public const int INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL = 9;

   31     public const int INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS = 7;

   32     public const int INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL = 6;

   33     public const int INTERNET_PER_CONN_AUTOCONFIG_URL = 4;

   34     public const int INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5;

   35     public const int INTERNET_PER_CONN_FLAGS = 1;

   36     public const int INTERNET_PER_CONN_PROXY_BYPASS = 3;

   37     public const int INTERNET_PER_CONN_PROXY_SERVER = 2;

   38     public const int INTERNET_OPTION_PER_CONNECTION_OPTION = 0x4b;

   39     public const int INTERNET_OPTION_REFRESH = 0x25;

   40 

   41     [DllImport("kernel32.dll")]

   42     public static extern IntPtr GlobalFree(IntPtr hMem);

   43     [DllImport("wininet.dll", SetLastError = true)]

   44     [return: MarshalAs(UnmanagedType.Bool)]

   45     public static extern bool InternetQueryOption(IntPtr hInternet, uint dwOption, INTERNET_PER_CONN_OPTION_LIST lpBuffer, ref int lpdwBufferLength);

   46     [DllImport("wininet.dll")]

   47     [return: MarshalAs(UnmanagedType.Bool)]

   48     public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, INTERNET_PER_CONN_OPTION_LIST lpBuffer, int dwBufferLength);

   49 }

And a helper class to call the methods from a nicer .NET friendly API:

    1 internal static class InternetOptionsProxy

    2 {

    3     public static bool IsProxyEnabled()

    4     {

    5         NativeMethods.INTERNET_PER_CONN_OPTION_LIST list = new NativeMethods.INTERNET_PER_CONN_OPTION_LIST();

    6         NativeMethods.INTERNET_PER_CONN_OPTION[] options = new NativeMethods.INTERNET_PER_CONN_OPTION[5];

    7         options[0].dwOption = NativeMethods.INTERNET_PER_CONN_AUTOCONFIG_URL;

    8         options[1].dwOption = NativeMethods.INTERNET_PER_CONN_AUTODISCOVERY_FLAGS;

    9         options[2].dwOption = NativeMethods.INTERNET_PER_CONN_FLAGS;

   10         options[3].dwOption = NativeMethods.INTERNET_PER_CONN_PROXY_BYPASS;

   11         options[4].dwOption = NativeMethods.INTERNET_PER_CONN_PROXY_SERVER;

   12 

   13         list.dwSize = Marshal.SizeOf(list);

   14         list.pszConnection = null;

   15         list.dwOptionCount = options.Length;

   16         list.dwOptionError = 0;

   17 

   18         int len = Marshal.SizeOf(options[0]);

   19         IntPtr buffer = Marshal.AllocHGlobal((int)(len * options.Length));

   20         for (int i = 0; i < options.Length; i++)

   21         {

   22             Marshal.StructureToPtr(options[i], new IntPtr(buffer.ToInt64() + (i * len)), false);

   23         }

   24         list.pOptions = buffer;

   25         int lpdwBufferLength = Marshal.SizeOf(list);

   26 

   27         NativeMethods.InternetQueryOption(IntPtr.Zero, NativeMethods.INTERNET_OPTION_PER_CONNECTION_OPTION,

   28             list, ref lpdwBufferLength);

   29         for (int i = 0; i < options.Length; i++)

   30         {

   31             options[i] = (NativeMethods.INTERNET_PER_CONN_OPTION)Marshal.PtrToStructure(

   32                 new IntPtr(buffer.ToInt64() + (i * len)), typeof(NativeMethods.INTERNET_PER_CONN_OPTION));

   33         }

   34 

   35         Marshal.PtrToStringAnsi(options[0].ptrValue);

   36         Marshal.PtrToStringAnsi(options[3].ptrValue);

   37         Marshal.PtrToStringAnsi(options[4].ptrValue);

   38 

   39         int flags = options[2].ptrValue.ToInt32();

   40         NativeMethods.GlobalFree(options[0].ptrValue);

   41         NativeMethods.GlobalFree(options[3].ptrValue);

   42         NativeMethods.GlobalFree(options[4].ptrValue);

   43         Marshal.FreeHGlobal(buffer);

   44 

   45         bool enabled = (((flags & NativeMethods.PROXY_TYPE_AUTO_DETECT) > 0) ||

   46             (((flags & NativeMethods.PROXY_TYPE_AUTO_PROXY_URL) > 0) ||

   47             ((flags & NativeMethods.PROXY_TYPE_PROXY) > 0)));

   48 

   49         return enabled;

   50     }

   51 

   52     public static void EnableProxy(bool enable)

   53     {

   54         NativeMethods.INTERNET_PER_CONN_OPTION_LIST list = new NativeMethods.INTERNET_PER_CONN_OPTION_LIST();

   55         NativeMethods.INTERNET_PER_CONN_OPTION[] options = new NativeMethods.INTERNET_PER_CONN_OPTION[1];

   56         options[0].dwOption = NativeMethods.INTERNET_PER_CONN_FLAGS;

   57         options[0].ptrValue = enable ?

   58             new IntPtr(NativeMethods.PROXY_TYPE_AUTO_PROXY_URL |

   59                 NativeMethods.PROXY_TYPE_PROXY |

   60                 NativeMethods.PROXY_TYPE_DIRECT

   61             )

   62             : new IntPtr(NativeMethods.PROXY_TYPE_DIRECT);

   63 

   64         list.dwSize = Marshal.SizeOf(list);

   65         list.pszConnection = null;

   66         list.dwOptionCount = options.Length;

   67         list.dwOptionError = 0;

   68 

   69         int len = Marshal.SizeOf(options[0]);

   70         IntPtr hglobal = Marshal.AllocHGlobal((int)(len * options.Length));

   71         for (int i = 0; i < options.Length; i++)

   72         {

   73             Marshal.StructureToPtr(options[i], new IntPtr(hglobal.ToInt64() + (i * len)), false);

   74         }

   75         list.pOptions = hglobal;

   76 

   77         int dwBufferLength = Marshal.SizeOf(list);

   78         NativeMethods.InternetSetOption(IntPtr.Zero, NativeMethods.INTERNET_OPTION_PER_CONNECTION_OPTION,

   79             list, dwBufferLength);

   80         NativeMethods.InternetSetOption(IntPtr.Zero, NativeMethods.INTERNET_OPTION_REFRESH, null, 0);

   81         Marshal.FreeHGlobal(hglobal);

   82     }

   83 }

This class does the P/Invoke work.

When the application is running, right clicking the tray icon allows toggling from a “proxy enabled” to “proxy disabled” state.

proxy3

When the proxy is enabled and traffic is going through the proxy, the icon shows red monitors.

proxy4

When the proxy is disabled and traffic is not going through the proxy, the icon shows blue monitors.

proxy2

Left-clicking the icon shows the status in a balloon tip.  Clicking the balloon will toggle the proxy status.

proxy1

Note: When enabling the proxy, it only turns on the currently configured proxy.  It will not configure or autoconfigure a proxy.  If there is no proxy configured, I don’t know what will happen.  I haven’t tried it.

Download the full project here or run a ClickOnce application directly here.

Comment on this
Development
| |

Correct Way to Override Object Equality

Wednesday, 12 August 2009 09:24 AM
by Coose

Sometimes different instances of an object can be considered equal.  Take for example a Point class:

class Point

{

    public int X { get; set; }

    public int Y { get; set; }

}

Two different instances of this object that have the same X and Y values should be considered equal objects.  What happens in the following snippet?

Point first = new Point() { X = 1, Y = 2 };

Point second = new Point() { X = 1, Y = 2 };

 

Console.WriteLine("The two points {0} equal", first == second ? "ARE" : "ARE NOT");

You get “The two points ARE NOT equal”.  Additionally:

List<Point> points = new List<Point>();

points.Add(new Point() { X = 1, Y = 2 });

 

Console.WriteLine("The list {0} contain (1,2)",

    points.Contains(new Point() { X = 1, Y = 2 }) ? "DOES" : "DOES NOT");

Gives you “The list DOES NOT contain (1,2)”, even though it really does.

The framework doesn’t know that we intended the two objects to be equal if the X and Y properties are equal.  The framework will consider the objects equal if it is the same object, not if it has the same properties.  But we can surely tell the framework that these are the “same” object if their properties are the same.  It’s pretty easy, but can turn out bad if you don’t do it correctly.

The steps to follow are:

  • Override the GetHashCode method.  This method helps “find” the object based on certain properties.
  • Implement IEquitable<T> interface.  This tells the framework if the objects are actually “equal”.
  • Override the object.Equals method.  This is the non-type specific equivalent of above.
  • Create a == operator, delegates to the object.Equals method.
  • Create a != operator, the inverse of the above.

Let’s break it down:

Override GetHashCode method.

The simplest way to do that is use the exclusive or operator (^) on the GetHashCode of each “unique” property.  So, for our Point class, even if there are other properties or fields, the two that define “uniqueness” of the object are X and Y, so the GetHashCode method becomes:

public override int GetHashCode()

{

    return X.GetHashCode() ^ Y.GetHashCode();

}

Yeah…that’s it.  More unique fields/properties? Just XOR (^) the GetHashCode of them, too.

Implement IEquitable<T>.

There’s only one method: public bool Equals(T other).  This is a three step process:

  1. If the other is null, it’s not equal (obviously this is not null).
  2. If the other is this, it’s obviously equal.
  3. If all “unique” properties are equal, it’s equal.

public bool Equals(Point other)

{

    if (object.ReferenceEquals(other, null)) return false;

    if (object.ReferenceEquals(other, this)) return true;

    return this.X == other.X && this.Y == other.Y;

}

Make sure to use the object.ReferenceEquals to not get into an infinite loop/stack overflow.

Again, other “unique” fields/properties are compared here as well.

Override object.Equals.

This is the non-type specific implementation of the above step, so we compare the types, then call the overload Equals(T) above.

public override bool Equals(object obj)

{

    Point other = obj as Point;

    if (object.ReferenceEquals(other, null)) return false;

    return this.Equals(other);

}

That’s all for that.

Create a == operator.

This is a really simple step, as this operator just calls the object.Equals method.

public static bool operator == (Point x, Point y)

{

    return object.Equals(x, y);

}

Create a != operator.

An even simpler step: just return the inverse of the == operator.

public static bool operator != (Point x, Point y)

{

    return !(x == y);

}

That’s it.  Now the object is compared correctly by the framework.

So, running the original test code:

Point first = new Point() { X = 1, Y = 2 };

Point second = new Point() { X = 1, Y = 2 };

 

Console.WriteLine("The two points {0} equal", first == second ? "ARE" : "ARE NOT");

 

List<Point> points = new List<Point>();

points.Add(new Point() { X = 1, Y = 2 });

 

Console.WriteLine("The list {0} contain (1,2)",

    points.Contains(new Point() { X = 1, Y = 2 }) ? "DOES" : "DOES NOT");

 

Console.ReadLine();

Results in:

The two points ARE equal
The list DOES contain (1,2)

The full Point class is:

class Point : IEquatable<Point>

{

    public int X { get; set; }

    public int Y { get; set; }

 

    public override int GetHashCode()

    {

        return X.GetHashCode() ^ Y.GetHashCode();

    }

 

    public bool Equals(Point other)

    {

        if (object.ReferenceEquals(other, null)) return false;

        if (object.ReferenceEquals(other, this)) return true;

        return this.X == other.X && this.Y == other.Y;

    }

 

    public override bool Equals(object obj)

    {

        Point other = obj as Point;

        if (object.ReferenceEquals(other, null)) return false;

        return this.Equals(other);

    }

 

    public static bool operator == (Point x, Point y)

    {

        return object.Equals(x, y);

    }

 

    public static bool operator != (Point x, Point y)

    {

        return !(x == y);

    }

}

 

And that’s it.

Enjoy.  Or don’t.  Whatever.

Comment on this
Development
|

Another Password Regular Expression

Thursday, 16 July 2009 02:00 PM
by Coose

It’s out there thousands of times.  And here it is again.  The thing I couldn’t find in my Googling for a good regular expression was the “3 of 4 conditions”.  There was “all of 3” or “all of 4”, but I couldn’t find “3 of 4”.

So, here’s what I came up with:

^.*(?=.{10,})((?=.*[a-z])(?=.*[A-Z])(?=.*\d)|(?=.*[a-z])(?=.*[A-Z])(?=.*\W)|(?=.*[a-z])(?=.*\d)(?=.*\W)|(?=.*[A-Z])(?=.*\d)(?=.*\W)).*$

  • At least 10 characters
  • At least 3 of the following conditions
    • Lowercase alpha character
    • Uppercase alpha character
    • Number
    • Non-alphanumeric character

How it works:

Let’s start by looking at the regular expression required for ALL of the 4 conditions listed above:

^.*(?=.{10,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*\W).*$

Broken up, the expression says this:

^ The beginning of the text…
.* …has zero or more of any characters…
(?=.{10,}) …where is followed by any character at least 10 times…
(?=.*[a-z]) …and where is followed by any character zero or more times which is followed by a lowercase letter…
(?=.*[A-Z]) …and where is followed by any character zero or more times which is followed by a uppercase letter…
(?=.*\d) …and where is followed by any character zero or  more times which is followed by a digit
(?=.*\W) …and where is followed by any character zero or more times which is followed by a non-word character…
.* …and is followed by any character zero or more times…
$ …then the text ends.

So, let’s break down the example input: this.IS.a.t34t.

^ Matches the betting of the text.
.* Matches anything zero or more times. (Call this “Match 0”)  In this case, it matches the entire text.
(?=.{10,}) Makes “Match 0” match all but the last 10 characters.  The expression up to this point is ^.*(?=.{10,}), which matches: this.IS.a.t34t.  It matches anything (Match 0) where there are 10 of any character to the right (“to the right” is a zero-width positive lookahead).
(?=.*[a-z]) Makes sure that “Match 0” is followed by anything or nothing, then a single lowercase character.  this.IS.a.t34t.  “Match 0” is still the red “this”, and the noncapturing lookahead is the blue “a”.
(?=.*[A-Z]) Makes sure that “Match 0” is followed by anything or nothing, then a single uppercase character. this.IS.a.t34t.  “Match 0” is still the red “this”, and the noncapturing lookahead is the blue “I”.
(?=.*\d) Makes sure that “Match 0” is followed by anything or nothing, then a single digit. this.IS.a.t34t.  “Match 0” is still the red “this”, and the noncapturing lookahead is the blue “3”.
(?=.*\W) Makes sure that “Match 0” is followed by anything or nothing, then a single non-word character.  this.IS.a.t34t.  “Match 0” is still the red “this” and the noncapturing lookahead is the blue “.”.
.* Now here’s a twist.  this.IS.a.t34t. “Match 0” is still the red “this” and the second “anything” match (“Match 1”) is the blue “.IS.a.t34t”.
$ …then the text ends.

To demonstrate a little bit, let’s name the matches.  So our expression becomes:

^(?'match_0'.*)(?=.{10,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*\W)(?'match_1'.*)$

Visualizing this:

Regular Expression Test Bench

So you can see that the first match is grouped and named “match_0” and the second match is grouped named “match_1”.

Ok.  If you’re still with me, that is how we make it match all of the aforementioned conditions.  Now how do we make it match 3 of the 4?  There is no simple declarative mechanism for “3 of 4”, so I used a combination. 

A combination of 3 of 4 items is only 4, so there’s not that much to do.  Remember, we need a combination, in which order is not important. We don’t care about order, just existence.  The formula for the number of items in a combination is

(n!)/(r!(nr)!)

where n is the number of items to choose from (4) and r is the number chosen (3). So (4!) / (3!(4 – 3)!) is 24 / 6 = 4.  There are only 4 combinations in a “3 of 4” scenario: (lowercase, uppercase, digit), (lowercase, uppercase, non-alphanumeric), (lowercase, digit, non-alphanumeric), and (uppercase, digit, non-alphanumeric).

As an aside: if the order of the options is important, it is called a permutation.  The formula for a permutation is

n! / (n – r)!

which gives us 24 / 1 = 24 permutations.  Since we need to use alternation in our regular expression, that’s a lot of typing: (lowercase, uppercase, digit) (lowercase, uppercase, non-alphanumeric) (lowercase, digit, uppercase) (lowercase, digit, non-alphanumeric) (lowercase, non-alphanumeric, uppercase) (lowercase, non-alphanumeric, digit) (uppercase,lowercase, digit) (uppercase,lowercase, non-alphanumeric) (uppercase, digit,lowercase) (uppercase, digit, non-alphanumeric) (uppercase, non-alphanumeric,lowercase) (uppercase, non-alphanumeric, digit) (digit,lowercase, uppercase) (digit,lowercase, non-alphanumeric) (digit, uppercase,lowercase) (digit, uppercase, non-alphanumeric) (digit, non-alphanumeric,lowercase) (digit, non-alphanumeric, uppercase) (non-alphanumeric,lowercase, uppercase) (non-alphanumeric,lowercase, digit) (non-alphanumeric, uppercase,lowercase) (non-alphanumeric, uppercase, digit) (non-alphanumeric, digit,lowercase) (non-alphanumeric, digit, uppercase).

So our expression to require all four conditions is:

^.*(?=.{10,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*\W).*$

Which states that each of the lookaheads must be true, (10 chars)(lower)(upper)(digit)(non-alphanumeric).  What we want is to make a statement like, “10 characters and at least 3 of my 4 conditions”, which with combinations becomes, “10 characters and at least one of my combinations.”  So it would look more like (10 chars)((c1)|(c2)|(c3)|(c4)).

Now replacing with our real regular expression syntax, our final expression is:

^.*(?=.{10,})((?=.*[a-z])(?=.*[A-Z])(?=.*\d)|(?=.*[a-z])(?=.*[A-Z])(?=.*\W)|(?=.*[a-z])(?=.*\d)(?=.*\W)|(?=.*[A-Z])(?=.*\d)(?=.*\W)).*$

With the first combination in red, the second combination in blue, the third combination in orange, and the fourth combination in green.

In my next post, I’ll post my Regular Expression Test Bench.  There are a few of these online also, but I needed one with better visualization.  I needed to see the matches and captures, and highlight each of them in the text independently on demand.  Here is a screenshot of the app.  It’s being deployed as a Click-Once app, so I’ll post the URL soon. :)

Regular Expression Test Bench

Comment on this
Development
|

Standard Bindings Custom Binding Equivalents

Tuesday, 02 June 2009 06:19 PM
by Coose

Ever wanted to know the CustomBinding equivalent of a standard binding?  Use this tool to see them.

[More Click here to see the tool]



How’s it done?

Create the binding and save with the ServiceContractGenerator.  That writes to a config file.  Then I read it back.

So I created a web user control with a combo, literal and a button:

<asp:DropDownList ID="BindingList" runat="server">

    <asp:ListItem Text="BasicHttpBinding" Value="System.ServiceModel.BasicHttpBinding" />

    <asp:ListItem Text="CustomBinding" Value="System.ServiceModel.Channels.CustomBinding" />

    <asp:ListItem Text="MsmqIntegrationBinding" Value="System.ServiceModel.MsmqIntegration.MsmqIntegrationBinding" />

    <asp:ListItem Text="NetNamedPipeBinding" Value="System.ServiceModel.NetNamedPipeBinding" />

    <asp:ListItem Text="NetPeerTcpBinding" Value="System.ServiceModel.NetPeerTcpBinding" />

    <asp:ListItem Text="NetTcpBinding" Value="System.ServiceModel.NetTcpBinding" />

    <asp:ListItem Text="WSDualHttpBinding" Value="System.ServiceModel.WSDualHttpBinding" />

    <asp:ListItem Text="WSHttpBinding" Value="System.ServiceModel.WSHttpBinding" />

    <asp:ListItem Text="WS2007HttpBinding" Value="System.ServiceModel.WS2007HttpBinding" />

    <asp:ListItem Text="WSFederationHttpBinding" Value="System.ServiceModel.WSFederationHttpBinding" />

    <asp:ListItem Text="WS2007FederationHttpBinding" Value="System.ServiceModel.WS2007FederationHttpBinding" />

</asp:DropDownList>

<asp:Button ID="GoButton" runat="server" Text="Evaluate"

    onclick="GoButton_Click" />

<br />

<pre><asp:Literal runat="server" ID="BindingMarkup" /></pre>

And in the button handler:

protected void GoButton_Click(object sender, EventArgs e)

{

    Assembly asm = Assembly.Load("System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");

    Type t = asm.GetType(BindingList.SelectedValue);

    Binding b = Activator.CreateInstance(t) as Binding;

 

    string configFile = Server.MapPath("~/App_Data/__bindings.config");

 

    Configuration machineConfig = ConfigurationManager.OpenMachineConfiguration();

    ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();

    fileMap.ExeConfigFilename = configFile;

    fileMap.MachineConfigFilename = machineConfig.FilePath;

    Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);

    config.NamespaceDeclared = true;

 

    ServiceContractGenerator gen = new ServiceContractGenerator(config);

    string sectionName, configName;

    gen.GenerateBinding(new CustomBinding(b.CreateBindingElements()), out sectionName, out configName);

    config.Save();

 

    XmlDocument doc = new XmlDocument();

    doc.LoadXml(File.ReadAllText(configFile));

 

    StringBuilder xml = new StringBuilder();

    using (XmlWriter writer = XmlWriter.Create(xml, new XmlWriterSettings() { Indent = true, IndentChars = "  ", NewLineChars = Environment.NewLine, NewLineOnAttributes = true }))

    {

        doc.Save(writer);

    }

 

    this.BindingMarkup.Text = HttpUtility.HtmlEncode(xml.ToString());

    File.Delete(configFile);

}

Comment on this
Development
|

Custom Compiled Cassini from Visual Studio

Friday, 17 April 2009 01:13 PM
by Coose

In my previous post, I described compiling a custom version of Cassini that could listen to external requests, not just loopback.  Now, I want to use that version of Cassini to debug from Visual Studio.  The problem is that the command lines are different.  Visual Studio uses Webdev.WebServer.exe, and issues argument in the format

/port:1234 /path:c:\temp /vpath:/test

Cassini expects arguments in the format

apppath port virtroot

So, in main.cs, I have modified the Main function as so:

   50 public MainForm(String[] args) {

   51     //_portString = "80";

   52     //_virtRoot = "/";

   53     //_appPath = string.Empty;

   54 

   55     // look for arguments in the form of /port:1234, or /path:"abcdefg" or /vpath:/

   56     foreach (string arg in args)

   57     {

   58         if (arg.StartsWith("/port:", StringComparison.OrdinalIgnoreCase)) _portString = arg.Substring(6).Trim();

   59         if (arg.StartsWith("/path:", StringComparison.OrdinalIgnoreCase)) _appPath = arg.Substring(6).Trim();

   60         if (arg.StartsWith("/vpath:", StringComparison.OrdinalIgnoreCase)) _virtRoot = arg.Substring(7).Trim();

   61     }

   62 

   63     try {

   64         if (string.IsNullOrEmpty(_appPath) && args.Length >= 1) _appPath = args[0];

   65         if (string.IsNullOrEmpty(_portString) && args.Length >= 2) _portString = args[1];

   66         if (string.IsNullOrEmpty(_virtRoot) && args.Length >= 3) _virtRoot = args[2];

   67     }

   68     catch {

   69     }

   70 

   71     InitializeForm();

   72 

   73     if (string.IsNullOrEmpty(_appPath)) {

   74         appDirTextBox.Focus();

   75         return;

   76     }

   77 

   78     Start();

   79 }

Now, the application will accept command line arguments in either form.

I copy this cassini-v35.exe to C:\Program Files\Common Files\microsoft shared\DevServer\9.0 and rename it webdev.webserver.exe (making a backup of the old webdev.webserver.exe of course), and now I can launch my custom Cassini from Visual Studio.

Comment on this
Development
| |

This header must be modified using the appropriate property

Friday, 17 April 2009 08:03 AM
by Coose

When adding headers to a HttpWebRequest or HttpWebResponse, you may have come across the error “This header must be modified using the appropriate property.”  Some headers are restricted from simply setting via the headers collection.

[more Click to read more…]

Server Error in '/' Application.

This header must be modified using the appropriate property.
Parameter name: name

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ArgumentException: This header must be modified using the appropriate property.
Parameter name: name

Source Error:

Line 35: { Line 36: HttpWebRequest request = (HttpWebRequest)WebRequest.Create(target); 
Line 37: request.Headers.Add(context.Request.Headers);
Line 38: using (StreamReader reader = new StreamReader(context.Request.InputStream))
Line 39: {

Source File: C:\temp\RequestProxy.cs    Line: 37

Stack Trace:

[ArgumentException: This header must be modified using the appropriate property. Parameter name: name] System.Net.WebHeaderCollection.ThrowOnRestrictedHeader(String headerName) +5370110 System.Net.WebHeaderCollection.Add(String name, String value) +32 System.Collections.Specialized.NameValueCollection.Add(NameValueCollection c) +108 Sfx.Web.Handlers.RequestProxy.ProcessRequest(HttpContext context) in C:\temp\RequestProxy.cs:37 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +181 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75


Version Information: Microsoft .NET Framework Version:2; ASP.NET Version:2

 

You can see above that copying the headers collection from one request into another is going to cause the problem.  The following is a list of request and response headers that must be set via properties instead of headers collection.  These properties will be translated to headers on the wire:

 

Header

Restricted on Request

Restricted on Response

Accept true – use .Accept property false
Connection true – use .Connection property false
Content-Type true – use .ContentType property false
Content-Length true – use .ContentLength property true – use .ContentLength property
Date true false
Expect true – use .Expect property false
Host true false
If-Modified-Since true – use .IfModifiedSince property false
Keep-Alive false true
Proxy-Connection true – use .Proxy property false
Range true false
Referer true – use .Referer property false
Transfer-Encoding true – use .TransferEncoding property true
User-Agent true – use .UserAgent property false
WWW-Authenticate false true

Comment on this
Development