Mobile Browser User-Agent Detector

While working on a project recently I needed to be able to determine if the user was coming to the ASP.Net site was using a mobile browser. In my particular case, the IsMobileBrowser property didn’t work so I created this code to do it for me, based on the information i gleamed from http://www.zytrax.com/tech/web/mobile_ids.html. Enjoy.

string[] arr = new string[]
{
"Windows CE",
"PlayStation Portable",
"PLAYSTATION 3",
"Symbian OS",
"SonyEricsson",
"Opera Mini",
"SIE",
"Vodafone",
"SEC",
"SAMSUNG",
"SCH",
"240x320",
"MobileExplorer",
"PalmSource",
"PalmOS",
"Smartphone",
"BlackBerry",
"iPhone"
};

foreach (string s in arr) {
if (Context.Request.UserAgent.ToLower().Contains(s.ToLower()))
Response.Redirect("/mobile.aspx");
}

PatternLayout Modifiers in Log4net

Log4net is an awesome library. For anyone who develops in .Net and doesn’t use it, I highly suggest you do. Code Project has a great article on how to use log4net for those who have not used it before.

But while I love the library as an awesome way to manage escalating logs within an application, it frustrated me trying to find a list of the default PatternLayout Modifiers. After some Googling I found it!

Conversion Character Effect
a Used to output the frienly name of the AppDomain where the logging event was generated.
c

Used to output the logger of the logging event. The logger conversion specifier can be optionally followed by precision specifier, that is a decimal constant in brackets.

If a precision specifier is given, then only the corresponding number of right most components of the logger name will be printed. By default the logger name is printed in full.

For example, for the logger name “a.b.c” the pattern %c{2} will output “b.c”.

C

Used to output the fully qualified class name of the caller issuing the logging request. This conversion specifier can be optionally followed by precision specifier, that is a decimal constant in brackets.

If a precision specifier is given, then only the corresponding number of right most components of the class name will be printed. By default the class name is output in fully qualified form.

For example, for the class name “log4net.Layout.PatternLayout”, the pattern %C{1} will output “PatternLayout”.

WARNING Generating the caller class information is slow. Thus, it’s use should be avoided unless execution speed is not an issue.

d

Used to output the date of the logging event. The date conversion specifier may be followed by a date format specifier enclosed between braces. For example, %d{HH:mm:ss,fff} or %d{dd MMM yyyy HH:mm:ss,fff}. If no date format specifier is given then ISO8601 format is assumed (ISO8601DateFormatter).

The date format specifier admits the same syntax as the time pattern string of the ToString.

For better results it is recommended to use the log4net date formatters. These can be specified using one of the strings “ABSOLUTE”, “DATE” and “ISO8601” for specifying AbsoluteTimeDateFormatter, and respectively ISO8601DateFormatter. For example, %d{ISO8601} or %d{ABSOLUTE}.

These dedicated date formatters perform significantly better than ToString.

F

Used to output the file name where the logging request was issued.

WARNING Generating caller location information is extremely slow. It’s use should be avoided unless execution speed is not an issue.

l

Used to output location information of the caller which generated the logging event.

The location information depends on the CLI implementation but usually consists of the fully qualified name of the calling method followed by the callers source the file name and line number between parentheses.

The location information can be very useful. However, it’s generation is extremely slow. It’s use should be avoided unless execution speed is not an issue.

L

Used to output the line number from where the logging request was issued.

WARNING Generating caller location information is extremely slow. It’s use should be avoided unless execution speed is not an issue.

m

Used to output the application supplied message associated with the logging event.

M

Used to output the method name where the logging request was issued.

WARNING Generating caller location information is extremely slow. It’s use should be avoided unless execution speed is not an issue.

n

Outputs the platform dependent line separator character or characters.

This conversion character offers practically the same performance as using non-portable line separator strings such as “\n”, or “\r\n”. Thus, it is the preferred way of specifying a line separator.

p

Used to output the level of the logging event.

P

Used to output the an event specific property. The key to lookup must be specified within braces and directly following the pattern specifier, e.g. %X{user} would include the value from the property that is keyed by the string ‘user’. Each property value that is to be included in the log must be specified separately. Properties are added to events by loggers or appenders. By default no properties are defined.

r

Used to output the number of milliseconds elapsed since the start of the application until the creation of the logging event.

t

Used to output the name of the thread that generated the logging event. Uses the thread number if no name is available.

u

Used to output the user name for the currently active user (Principal.Identity.Name).

WARNING Generating caller information is extremely slow. It’s use should be avoided unless execution speed is not an issue.

W

Used to output the WindowsIdentity for the currently active user.

WARNING Generating caller WindowsIdentity information is extremely slow. It’s use should be avoided unless execution speed is not an issue.

x

Used to output the NDC (nested diagnostic context) associated with the thread that generated the logging event.

X

Used to output the MDC (mapped diagnostic context) associated with the thread that generated the logging event. The key to lookup must be specified within b

races and directly following the pattern specifier, e.g. %X{user} would include the value from the MDC that is keyed by the string ‘user’. Each MDC value that is to be included in the log must be specified separately.

%

The sequence %% outputs a single percent sign.

Using C# to "Snip" Long URLs

There are a number of URL shortening services out these days, so it seems such a shame that developers do not more often use them to make URLs more manageable for users.

One particular service is called “Snipr” and they make it very easy to use their service with a simple soft API. Here is the code to Snip your URLs down to size:

private static string GetSniprURL(string url) {
  url = HttpUtility.UrlDecode(url);
  url = HttpUtility.HtmlDecode(url);
  url = "http://snipr.com/site/snip?r=simple&link=" + HttpUtility.UrlEncode(url);

  HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
  request.Method = "GET";

  using (StreamReader response = new StreamReader(request.GetResponse().GetResponseStream())) {
     string responseData = response.ReadToEnd();
     return responseData.Trim().Trim('\r').Trim('\n');
  }
}

Unit Testing Events With Anonymous Delegates

I’ve been ramping up the amount of unit testing I’ve been doing lately, and whenever I had to do unit tests I would create the normal event handler and do the assertion in the handler.

But the problem with this approach is that (in my opinion) it can be really messy with a whole bunch of handlers for each event thrown in each test. Anonymous delegates get around this get around this because the handler can be done inline with the actual test.

[Test]
public void SettingValueRaisesEventTest() {
bool eventRaised = false;
Parameter param = new Parameter("num", "int", "1");
param.ValueChanged +=
delegate(object sender, ValueChangedEventArgs e) {
Assert.AreEqual("42", e.NewValue);
Assert.AreEqual("1", e.OldValue);
Assert.AreEqual("num", e.ParameterName);
eventRaised = true;
};

param.Value = "42"; //should fire event.

Assert.IsTrue(eventRaised, "Event was not raised");
}

In general, I try not to use anonymous delegates, especially when the delegate contains a lot of code. I think they can become confusing and hard to read. But this is a situation in which I think using an anonymous delegate is particularly handy.

A Good URL Regular Expression

(^|[ \t\r\n])((ftp|http|https|gopher|mailto|news|nntp|telnet|wais|
file|prospero|aim|webcal):(([A-Za-z0-9$_.+!*(),;/?:@&~=-])|%
[A-Fa-f0-9]{2}){2,}(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*(),;
/?:@&~=%-]*))?([A-Za-z0-9$_+!*();/?:~-]))

Regular Expressions are magical. Up until now I always discarded them as being to “geeky”, meaning I don’t consider it my life’s biggest goal to be typing (/?[]\w) all day long.

Regular expression that validates URLs not URL domains. One that doesn’t allow spaces in the domain name and where the domain can be suffixed with the port number. It also supports ~/ paths, and sub folders.

Should parse the URL below:
http://hh-1hallo.msn.blabla.com:80800/test/test/test.aspx?dd=dd&id=dki

But not:
http://hh-1hallo. msn.blablabla.com:80800/test/test.aspx?dd=dd&id=dki

I hope that this helps people.