I Prefer Jim Developer James Schubert shares his code and his thoughts.

26Jun/10

Learning WCF: IIS 7 won’t start service from web project

I'm following along with code in Learning WCF, attempting to quickly become an expert at building WCF Services from scratch. In Chapter 1, there is a project called IISHostedService. After making the quick modifications to the downloaded code, and running the application, IIS 7.0 (Windows 7, 64bit) doesn't serve the services, complaining about adding a MIME type. I thought this was rather fishy, because I've created WCF Services while in school under Windows XP and they ran fine.

It turns out that I didn't have WCF properly setup. To do so, you have to run

C:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\servicemodelreg -i

This will provide the following output (which is everything I was missing):

Microsoft(R) Windows Communication Foundation Installation Utility
[Microsoft (R) Windows (R) Communication Foundation, Version 3.0.4506.4926]
Copyright (c) Microsoft Corporation.  All rights reserved.

Installing: Machine.config Section Groups and Handlers (WOW64)
Installing: Machine.config Section Groups and Handlers
Installing: System.Web Build Provider (WOW64)
Installing: System.Web Compilation Assemblies (WOW64)
Installing: HTTP Handlers (WOW64)
Installing: HTTP Modules (WOW64)
Installing: System.Web Build Provider
Installing: System.Web Compilation Assemblies
Installing: HTTP Handlers
Installing: HTTP Modules
Installing: Protocol node for protocol net.tcp (WOW64)
Installing: TransportConfiguration node for protocol net.tcp (WOW64)
Installing: ListenerAdapter node for protocol net.tcp
Installing: Protocol node for protocol net.tcp
Installing: TransportConfiguration node for protocol net.tcp
Installing: Protocol node for protocol net.pipe (WOW64)
Installing: TransportConfiguration node for protocol net.pipe (WOW64)
Installing: ListenerAdapter node for protocol net.pipe
Installing: Protocol node for protocol net.pipe
Installing: TransportConfiguration node for protocol net.pipe
Installing: Protocol node for protocol net.msmq (WOW64)
Installing: TransportConfiguration node for protocol net.msmq (WOW64)
Installing: ListenerAdapter node for protocol net.msmq
Installing: Protocol node for protocol net.msmq
Installing: TransportConfiguration node for protocol net.msmq
Installing: Protocol node for protocol msmq.formatname (WOW64)
Installing: TransportConfiguration node for protocol msmq.formatname (WOW64)
Installing: ListenerAdapter node for protocol msmq.formatname
Installing: Protocol node for protocol msmq.formatname
Installing: TransportConfiguration node for protocol msmq.formatname
Installing: HTTP Modules (WAS)
Installing: HTTP Handlers (WAS)
Filed under: Blog No Comments
12Jun/10

Fairly Accurate JavaScript Browser Detection

I use jQuery for almost everything I do in JavaScript. The only real problem is that jQuery's browser name and version detection doesn't provide exactly what I want.

For instance, if I'm using Google Chrome 6.0.427.0, I wanted a script that would say "Hey, you're using Chrome 6.0.427.0".

I found such a script online and modified it to be a javascript object, so I thought I'd share. I didn't really do much to modify this code other than changing the comment style and a couple of other things. Below the code, there are link to download.

*browser_detection.js*

/**
 * Modifed from the source at http://www.javascripter.net/faq/browsern.htm
 */

function BrowserDetector()
{
  this.init();
}

BrowserDetector.prototype =
{
  nVer: navigator.appVersion,
  nAgt: navigator.userAgent,
  browserName: navigator.appName,
  fullVersion: '' + parseFloat(navigator.appVersion),
  majorVersion: parseInt(navigator.appVersion, 10),
  nameOffset: null,
  verOffset: null,
  ix: null,
  init: function ()
  { /* In MSIE, the true version is after "MSIE" in userAgent */
    if ((this.verOffset = this.nAgt.indexOf("MSIE")) != -1)
    {
      this.browserName = "Microsoft Internet Explorer";
      this.fullVersion = this.nAgt.substring(this.verOffset + 5);
    } /* In Opera, the true version is after "Opera" */
    else if ((this.verOffset = this.nAgt.indexOf("Opera")) != -1)
    {
      this.browserName = "Opera";
      this.fullVersion = this.nAgt.substring(this.verOffset + 6);
    } /* In Chrome, the true version is after "Chrome" */
    else if ((this.verOffset = this.nAgt.indexOf("Chrome")) != -1)
    {
      this.browserName = "Chrome";
      this.fullVersion = this.nAgt.substring(this.verOffset + 7);
    } /* In Safari, the true version is after "Safari" */
    else if ((this.verOffset = this.nAgt.indexOf("Safari")) != -1)
    {
      this.browserName = "Safari";
      this.fullVersion = this.nAgt.substring(this.verOffset + 7);
    } /* In Firefox, the true version is after "Firefox" */
    else if ((this.verOffset = this.nAgt.indexOf("Firefox")) != -1)
    {
      this.browserName = "Firefox";
      this.fullVersion = this.nAgt.substring(this.verOffset + 8);
    } /* In most other browsers, "name/version" is at the end of userAgent */
    else if ((this.nameOffset = this.nAgt.lastIndexOf(' ') + 1) < (this.verOffset = this.nAgt.lastIndexOf('/')))
    {
      this.browserName = this.nAgt.substring(this.nameOffset, this.verOffset);
      this.fullVersion = this.nAgt.substring(this.verOffset + 1);
      if (this.browserName.toLowerCase() == this.browserName.toUpperCase())
      {
        this.browserName = navigator.appName;
      }
    } /* trim the fullVersion string at semicolon/space if present */
    if ((this.ix = this.fullVersion.indexOf(";")) != -1)
    {
      this.fullVersion = this.fullVersion.substring(0, this.ix);
    }
    if ((this.ix = this.fullVersion.indexOf(" ")) != -1)
    {
      this.fullVersion = this.fullVersion.substring(0, this.ix);
    }

    this.majorVersion = parseInt('' + this.fullVersion, 10);
    if (isNaN(this.majorVersion))
    {
      this.fullVersion = '' + parseFloat(navigator.appVersion);
      this.majorVersion = parseInt(navigator.appVersion, 10);
    }
  }
}

Say you have two DOM elements, called *brower_name* and *browser_version*, you can use this script this way (using jQuery):


	jQuery(document).ready(function($){
		var browser_name = $('#browser_name');
		var browser_version = $('#browser_version');

		var browser = new BrowserDetector();
		browser_name.text(browser.browserName);
		browser_version.text(browser.fullVersion);
	});

Below are the files:
browser_detection.js [2.6 KB (2670 bytes)]
browser_detection.min.js [1.7 KB (1758 bytes)]
browser_detection.packed.js [1.2 KB (1263 bytes)]

Filed under: Blog No Comments
11Jun/10

Using DataAnnotation attributes to validate Membership password

As a follow-up to my post on DataAnnotations in ASP.NET Web Forms, I'd like to demonstrate yet another custom attribute. Although ASP.NET offers a CreateUserWizard, if your custom membership provider is way more complicated, you will probably be better off creating a control from scratch. If you go this route, you'll have to provide some of the functionality from the CreateUserWizard. Here is a simple attribute which checks *only* password complexity and builds an ErrorMessage without ever calling the CreateUser method.

This attribute can be added to a password property and validate against the *Default* Membership Provider.

Here is the code:


    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    public class MembershipPasswordRequiredAttribute : ValidationAttribute
    {
        public override bool IsValid(object value)
        {
            if (value == null || !(value is string) || string.IsNullOrEmpty(value.ToString()))
            {
                return false;
            }

            MembershipSection membershipConfig = (MembershipSection)WebConfigurationManager
                                                                    .GetSection("system.web/membership");
            var providerSettings = membershipConfig.Providers[membershipConfig.DefaultProvider];
            string minLength = providerSettings.Parameters["minRequiredPasswordLength"];
            string minAlpha = providerSettings.Parameters["minRequiredNonalphanumericCharacters"];

            if (string.IsNullOrEmpty(this.ErrorMessage) && !string.IsNullOrEmpty(minLength))
            {
                string message = String.Empty;
                message = String.Format("Password must be at least {0} characters in length", minLength);
                if (!string.IsNullOrEmpty(minAlpha))
                {
                    message = String.Format("{0} and contain at least {1} special character", message,  minAlpha);
                }

                this.ErrorMessage = message;
            }
                /* Validate against your provider and return true or false */
        }
    }

Usage:

[MembershipPasswordRequired]
internal string Password {get;set;}

The cool thing about this attribute is that you can decorate a property without specifying the ErrorMessage and it will build one dynamically from your default membership. Of course, you can change this up if you're using multiple providers by getting the key of the current provider. But, the project I'm working on will always only have one provider, so this is how I'll leave it.

A caveat: You can only set the ErrorMessage property once. If you try to assign to it more than once, you will receive an exception telling you this.

I won't post the code for validating against the provider, because there are a number of ways to do this. Probably the safest way to do so is to use regex validation and pull that property from the provider's parameters and just return whether the regex matches the string or not.

Anyway, I thought this was a pretty cool usage of DataAnnotations, and hooking it up on a custom CreateUser control was trivial with the DataAnnotation validator (from a few posts ago).

Filed under: Blog No Comments