Pex 0.7

I've been so busy over the last couple of weeks that I completely missed the release of Pex 0.7 as announced by Nikilai.

The team also released a draft document on Parameterized Unit Test Patterns which is a pretty good read.

If you do Unit Testing in the .NET space then you need to have a look at Pex.

No go and Test.

Posted by Pieter | with no comments
Filed under: , , ,

RPO v1.0 Released

What is the RPO?

The RPO (Runtime Page Optimizer) speeds up ASP.NET and SharePoint websites. Its simple. We automated 8 of the guidelines set out in Yahoo's "Best practices for speeding up your site" and checked these with the creators of YSlow to make sure the RPO gives you the fastest website ever. Try the RPO now from www.getrpo.com.

Technical background

The RPO (Runtime Page Optimizer) is a software component for IIS 6/7 web servers  that speeds up ASP.NET and SharePoint websites significantly.  The component works at runtime - with no development changes, no extra hardware and performs these optimizations:

  • Combination. Combines JS files, CSS files reducing HTTP requests. It can optionally  combine JPEGs and GIFs into CSS sprites to reduce the number of images.  This significantly decreases the roundtrips between browser and server reducing page load time
  • Compression. Minifies and gzip compresses resources, decreasing page load times and data traffic
  • Caching. Increases speed through caching - automatically setting far future expires on the browser, caching optimized resources on the server, with full control over when both caches are refreshed
  • Browser aware. Works with all versions of IE, FF, Opera, Chrome and Safari - optimizations are automatically turned on/off to meet the browser's capability
  • Framework support. Supports ASP.NET 2.0+, AJAX, SharePoint 2007, DotNetNuke, EPiServer
  • Fast set up. No extra hardware required,  no CDN maintenance, no browser software, zero impact installation - component is a single DLL installed on a web server
  • You decide how fast your pages load. Out-of-the-box the RPO will speed up websites at level-4 optimization. For even greater speed, you can use the RPO to sprite images and combine all JavaScripts into one, you'll just need to ensure your images are correctly scaled and your JavaScripts behave well when combined. This level of optimization usually takes a "milestone" to complete, the RPO reduces the developer  effort to hours and keeps your images and scripts in their original maintainable format

Do you need it?

Speed is everything. Unless you've implemented best practices, the website that seems fast on your local machine is often slooooooow when people use it from around the country or internationally. Users hate slooooooow webpages. Asking your customers to wait is like asking them to leave. Try the RPO now from www.getrpo.com.

Posted by Pieter | 1 comment(s)
Filed under: , ,

Get access to Active Directory Properties

Here's a nice sample of how to get access to things like if an Account has been disabled or to get the Password Expiration Date.  You will need the Interop.ActiveDs.dll for this code to work.

using System;
using System.Security.Principal;
using System.Diagnostics;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            foreach (IdentityReference group in WindowsIdentity.GetCurrent().Groups)
            {
                DirectoryEntry entry = new DirectoryEntry(FriendlyDomainToLdapDomain("<FQDN>"));
                ActiveDs.IADsUser native = (ActiveDs.IADsUser)CurrentUser.NativeObject;
                Debug.Print("AccountDisabled = {0}", native.AccountDisabled);
                Debug.Print("AccountExpirationDate = {0}", native.AccountExpirationDate);
                Debug.Print("ADsPath = {0}", native.ADsPath);
                Debug.Print("BadLoginCount = {0}", native.BadLoginCount);
                Debug.Print("GraceLoginsAllowed = {0}", native.GraceLoginsAllowed);
                Debug.Print("PasswordExpirationDate = {0}", native.PasswordExpirationDate);
                Debug.Print("PasswordLastChanged = {0}", native.PasswordLastChanged);
            }
        }
        private static string FriendlyDomainToLdapDomain(string friendlyDomainName)
        {
            string ldapPath = null;
            try
            {
                DirectoryContext objContext = new DirectoryContext(DirectoryContextType.Domain, friendlyDomainName);
                Domain objDomain = Domain.GetDomain(objContext);
                ldapPath = objDomain.Name;
            }
            catch (DirectoryServicesCOMException e)
            {
                Debug.Assert(false, e.Message);
                Debug.Print("Error: {0}", e.Message);
            }
            return ldapPath;
        }
        public static DirectoryEntry CurrentUser
        {
            get
            {
                string[] currentUserName = WindowsIdentity.GetCurrent().Name.Split('\\');
                string domainDistinguishedName = GetDistinguishedName(currentUserName[0]);
                DirectoryEntry domain = new DirectoryEntry("LDAP://" + domainDistinguishedName);
                DirectorySearcher searcher = new DirectorySearcher(domain,
                    String.Format("(sAMAccountName={0})", currentUserName[1]));
                SearchResult result = searcher.FindOne();
                DirectoryEntry currentUser = null;
                if (result != null)
                {
                    currentUser = result.GetDirectoryEntry();
                }
                return currentUser;
            }
        }
        public static string GetDistinguishedName(string netbiosName)
        {
            if (string.IsNullOrEmpty(netbiosName))
            {
                throw new ArgumentNullException("netbiosName");
            }
            if (!Regex.IsMatch(netbiosName, @"^[-\w]{1,15}$"))
            {
                throw new ArgumentException("Invalid NetBIOS domain name format. Domain name should be a maximum of 15 alphanumeric characters (including dashes).", "netbiosName");
            }
            DirectoryEntry globalCatalog = new DirectoryEntry("LDAP://RootDSE");
            string configurationPath = (string)globalCatalog.Properties["configurationNamingContext"].Value;
            DirectoryEntry partitions = new DirectoryEntry("LDAP://CN=Partitions," + configurationPath);
            DirectorySearcher searcher = new DirectorySearcher(partitions,
                String.Format("(&(objectClass=crossRef)(nETBIOSName={0}))", netbiosName),
                new string[] { "nCName" },
                SearchScope.OneLevel);
            SearchResult result = searcher.FindOne();
            string distinguishedName = null;
            if (result != null)
            {
                distinguishedName = result.Properties["nCName"][0] as string;
            }
            return distinguishedName;
        }
    }
}
Posted by Pieter | with no comments
Filed under:

How to get the Groups a Windows User belongs to

using System;
using System.Security.Principal;
using System.Diagnostics;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            foreach (IdentityReference group in WindowsIdentity.GetCurrent().Groups)
            {
                // Translate the IdentityReference to an NTAccount to get the Group Name
                string groupName = group.Translate(typeof(NTAccount)).ToString();
                // Do a split on the groupName
                string[] splitGroupName = groupName.Split('\\');
                if (splitGroupName.Length == 2)
                {
                    // If the split returns an array of two elements the second element will be the Actual Group Name
                    Debug.Print("Group: {0}", splitGroupName[1]);
                }
            }
        }
    }
}
Posted by Pieter | with no comments

Replacing Notepad with Notepad2 on Windows 2003

I tried the script from http://geekswithblogs.net/robz/archive/2008/09/13/replacing-notepad-with-notepad2-on-windows-xp-sp3.aspx and it works for Windows 2003.

@echo off
echo *IMPORTANT*
echo This will kill all open instances of Notepad.
echo To cancel, end this batch file now (ctrl+c), or hit any key to continue.
pause
echo Killing all instances of notepad running...
TASKKILL /F /IM notepad.exe /T
echo Backing up...
call :backup %systemroot%\servicepackfiles\i386
call :backup %systemroot%
call :backup %systemroot%\System32
call :backup %systemroot%\System32\dllcache
echo Installing...
copy notepad2.exe %systemroot%\servicepackfiles\i386\notepad.exe /y
copy notepad2.exe %systemroot%\notepad.exe /y
copy notepad2.exe %systemroot%\System32\notepad.exe /y
copy notepad2.exe %systemroot%\System32\dllcache\notepad.exe /y
echo Done.
pause
goto :end
:backup
call set npath=%1
set count=0
for %%i in (%npath%\notepad.original*.exe) do (
set nname=%%i
set /a count=count+1
)
echo backing up to %npath%\notepad.original%count%.exe
copy %npath%\notepad.exe %npath%\notepad.original%count%.exe /y
:end
Posted by Pieter | with no comments

Code Access Security and .NET Framework Versions

This is a note to myself.

First of all you do not get the .NET Framework 2.0 Configuration Tool as part of the .NET 2.0 Framework.  You have to install the .NET 2.0 SDK to get it.  This is different from .NET 1.1 where the '.NET Framework 1.1 Configuration Tool' is installed with shortcuts in Administrative Tools.

So now if you are setting CAS setting through the 'Microsoft .NET Framework 1.1 Configuration' tool, but still get SecurityExceptions, then you need to check if you have .NET 2.0 installed.  And if you don't have the .NET 2.0 SDK installed then you need to use caspol.exe to set your Code Access Security settings.

Posted by Pieter | with no comments
Filed under:

Unit Testing not Part of Estimate

I had a talk to another Vendor recently on a site where the framework that is provided to developers are really restrictive, tightly bound and has way to many dependencies.  This all makes it almost impossible to write any sort of Unit Tests when we need to touch this framework, which is unfortunately almost all of the time.  What shocked me though is that when I asked the Vendor if they would like the Framework to be easier to test his response was that they have not factored in testing as part of their estimate.  For me testing is an integral part of development and no matter how you do it, it should be done and it should always be part of your estimates.

Posted by Pieter | 2 comment(s)
Filed under:

Windows Live Writer on Windows 2003

If you try and install Windows Live Writer on anything but XP or Vista you get an error when trying to use the default installer, saying something like only XP and Vista is supported.

If you run the MSI though, WLW installs without any problem on Windows 2003.  There are a couple of ways to get the MSI:

  1. Download it from the German WLW site: http://www.live-writer.de/windows-live-writer-download/
  2. Get it from an XP or Vista system where WLW is installed: C:\Windows\System32\config\systemprofile\AppData\Local\WindowsLiveInstaller\MsiSources\

As easy as that.

Posted by Pieter | with no comments
Filed under:

StyleCop 4.3

A new version of StyleCop has been released, and they are about to release their SDK documentation.

The new rules shipping with StyleCop 4.3 include:

· Enforce sort order for using directives. This aligns with the Organize Usings functionality in VS 2008

· Require standard summary text for constructors and destructors

· Require parenthesis in arithmetic and comparison expressions for added clarity

· Require String.Empty rather than “”

· Require explanation message text in debug asserts

· Require justification text in Code Analysis suppressions

· Enforce use of built-in type aliases for int, string, float, etc.

· Require a blank line between elements

· Disallow blank lines at the top or bottom of documentation headers

· Disallow regions within method bodies (enabled by default)

· Disallow the use of regions anywhere within the code (disabled by default)

· Disallow empty static constructors

· Disallow empty unsafe, lock, checked, and unchecked statements

· Disallow unnecessary or empty try\catch\finally

The 4.3 release is available here: https://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=sourceanalysis&ReleaseId=1425

Posted by Pieter | with no comments

2TB, 64 Core System

I want one of these!

image

Stole the image from Mark Russinovich’s blog.

Posted by Pieter | with no comments

New ActionThis Release

The ActionThis guys have been busy this weekend with a new release:

The following changes were released last Sunday.

Improvements to the Project area:

  • The Project and Action Item pages have been merged.  The new Project page has an Action Item and a Details tab.  The Project page functionality can be found on the Details Tab, while the Action Item page functionality can be found on the Action Item tab.
  • A team member can leave a project they are signed to by going to the Details tab and clicking “Remove me.”
  • We have created the “(Other)” project that will display all Action Items assigned to you from Projects you are not a member of.
  • A new tick box to allow the viewing “Show Closed Action Items” instead of the two “View Open” and “View Closed” text.

Parent/Sub Action Items on Action Profile Page:

  • A Sub Action Items can now be created in the Action Profile Page by going to the Sub Action Item section and clicking “Add Action Item."
  • Rollover command functionality (from Project page) is also available.
  • When viewing a Parent Action Item you can navigate to a Sub Action Item by selecting it in the Sub-Action Item section.
  • When viewing a Sub Action Item the Parent Action Item is displayed below the “Status:”
  • When viewing a Sub Action Item you can navigate to a Parent Action Item by selecting its display name.

Outlook Client:

  • When working offline the changes to an action item's workflow are now reflected correctly in the Workflow buttons (e.g. Accepting an Action Item off-line now causes the “Accept” button to be greyed out when the item is next opened and the action is recorded in the item's history).
  • A Sub Action Item can now be created by right-clicking on the Parent Action Item and selecting “New Sub Action Item."
  • Action items can now be dragged to different projects or even be moved to be a Sub Action Item of another Action Item.

If you have any questions or feedback please email ATSupport@ActionThis.com.

Thanks for your continued support.

The ActionThis Team

Posted by Pieter | with no comments
Filed under:

Equality Pattern from Resharper

I was just reading this blog entry on how Resharper can auto generate equality members.

This is a pretty nice pattern to follow even when doing this by hand.

Here is the class it was created for:

public class Fooberry
{
    public string Foo { get; set; }
    public string Bar { get; set; }
}

 

public override bool Equals(object obj) {   
    if (ReferenceEquals(null, obj)) return false;   
    if (ReferenceEquals(this, obj)) return true;   
    if (obj.GetType() != typeof (Fooberry)) return false;   
    return Equals((Fooberry) obj);   
}   
  
public bool Equals(Fooberry obj)   
{   
    if (ReferenceEquals(null, obj)) return false;   
    if (ReferenceEquals(this, obj)) return true;   
    return Equals(obj.Foo, Foo) && Equals(obj.Bar, Bar);   
}   
  
public override int GetHashCode()   
{   
    unchecked  
    {   
        return ((Foo != null ? Foo.GetHashCode() : 0)*397) ^ (Bar != null ? Bar.GetHashCode() : 0);   
    }   
}  

 

I’ve know about most of this pattern including ReferenceEquals, but look at the unchecked keyword.  Very cool indeed.  I do wonder what the significance of the ‘* 397’ is though.  Any ideas?

Posted by Pieter | with no comments
Filed under:

Using Linq to Filter a list

So yesterday I made this post on applying a filter or map on a list.  Now let’s have a look at how we can do this with Linq.

First the list:

List<string> list = new List<string>();
list.Add("Anne");
list.Add("Brian");
list.Add("Pieter");
list.Add("Wayne");
list.Add("Shane");
list.Add("Susan");
list.Add("Xavier");

Plain old Linq:

// Plain old Linq
var linqFiltered = from item in list
                            where item.StartsWith("S")
                            select item;

Using the Where extension method:

// Linq with the Whete extension method only
var linqListFiltered2 = Enumerable.Where(list, i => i.StartsWith("S"));

And for me the most readable:

// Linq using the Where extension method on the list
var linqListWhereFiltered = list.Where(i => i.StartsWith("S"));

You can even create your own Where method:

static IEnumerable<T> Where<T>(IEnumerable<T> sequence, Func<T, bool> predicate)
{
    foreach (var item in sequence)
        if (predicate(item))
            yield return item;
}

And you can use it like this:

var myLinqListFiltered = Where(list, i => i.StartsWith("S"));

I see so many uses and possibilities for the Linq style code as well as extension methods.

In fact I can easily change the last example to be a bit more clear:

static IEnumerable<T> Filter<T>(this IEnumerable<T> list, Func<T, bool> predicate)
{
    foreach (T item in list)
        if (predicate(item))
            yield return item;
}

and then the intent is much clearer:

var myFilteredList = list.Filter(item => item.StartsWith("S"));
Share this post: email it! | bookmark it! |