.net

Are you Learning C#?

0

If you’re learning C# you won’t go much wrong with the C# Yellow book. Rob Miles has just released a new version. This year’s copy is a minor release, of a sort. It’s mostly a couple of corrections to last years content. If you’re starting out with programming or programming C# then you really should take a look: http://www.robmiles.com/journal/2011/10/13/c-yellow-book-2011.html

Dynamic Robots.txt in ASP MVC

0

I recently had the need to switch a robots.txt file dynamically, depending on whether a site was deployed to live or beta servers. The solution was very simple, ditch the real file and replace it with a controller action. This is a brief note on how I did this. I don’t pretend this is an ideal solution, it was something I knocked together before I went out for dinner.

The solution I went for was in three parts: a web.config transform, routing and the controller itself.

The web config transform for my live site looks like this:

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <appSettings>
        <add key="SiteStatus" value="live" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
    </appSettings>
</configuration>

The route is equally simple:

routes.MapRoute(
    "Robots.txt",
    "Robots.txt",
    new
    {
        controller = "Robots",
        action = "RobotsText"
    }
);

view raw routing.cs This Gist brought to you by GitHub.

And finally the actual controller:

public class RobotsController : Controller
{
    public FileContentResult RobotsText()
    {
        var content = "User-agent: *" + Environment.NewLine;

        if (string.Equals(ConfigurationManager.AppSettings["SiteStatus"], "live", StringComparison.InvariantCultureIgnoreCase))
        {
            content += "Disallow: /elmah.axd" + Environment.NewLine;
            content += "Sitemap: http://www.jacquelinewhite.co.uk/sitemap.xml";
        }
        else
        {
            content += "Disallow: /" + Environment.NewLine;
        }

        return File(
                Encoding.UTF8.GetBytes(content),
                "text/plain");
    }
}

And there we have it, my robots.txt file now is customised on a per deployment basis.

A Better Guard Class

2

Recently I was working with some of the developers in a different office, I don’t normally see their code, so it was interesting to see how they are meeting various problems. Generally speaking, they are doing some nice looking work. The architecture that they are moving towards looks like it’s going a long way to solving a lot of problems, all good stuff.

One bit of code that I kept seeing really bothered me. It was a guard class that I kept seeing. I think it was a clone of a class from the here. The reason it bothered me was simply that it didn’t read well, I kept thinking that it was guarding against an exception. In reality it was guarding against an error condition and would throw an exception if the condition happened. For example:

Guard.Against<InvalidOperationException>(string.IsNullOrEmpty(serverName), "Server name must be provided")

I would much rather something that reads like this:

Throw<InvalidOperationException>
    .WithMessage("Server name must be provided")
    .When(string.IsNullOrEmpty(serverName));

Here’s my implementation of the class, thoughts?

public static class Throw<T> where T : Exception
{
    public static Thrower WithMessage(string message)
    {
        return new Thrower(message);
    }

    public class Thrower
    {
        private readonly string message;
        public Thrower(string message)
        {
            this.message = message;
        }

        public void When(Func<bool> predicate)
        {
            if (predicate())
            {
                throw (T)Activator.CreateInstance(typeof(T), message);
            }
        }

        public void When(bool condition)
        {
            if (condition)
            {
                throw (T)Activator.CreateInstance(typeof(T), message);
            }
        }
    }
}
view raw Throw.cs This Gist brought to you by GitHub.

Encrypt Connection Strings on Application Startup

0

Just so I don’t forget how I do this:

protected void Application_Start()
{
#if !DEBUG
    EncryptConnectionStrings();
#endif
}

private void EncryptConnectionStrings()
{
    var sectionName = "connectionStrings";
    var config = WebConfigurationManager.OpenWebConfiguration("~");

    ConfigurationSection section = config.GetSection(sectionName);

    if (section != null && !section.SectionInformation.IsProtected)
    {
        section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
        config.Save();
    }
}
view raw gistfile1.cs This Gist brought to you by GitHub.

FluentMigrator Code Templates

0

A little while back I created some migrator.net code templates. Since I’ve now moved over to using FluentMigrator it seemed only reasonable that I port the templates for the FluentMigrator project as well. To use them simply take the zip file from here and drop it into C:\Users\username\Documents\Visual Studio 2010\Templates\ItemTemplates\Visual C#\ Once you’ve done that restart Visual Studio and you’ll be able to do File > New File > New Fluent Migration. Give the file a name and you’ll get a code file a little like this:

Which I happen to think is rather nice.

A Quick and Dirty Cache

0

Brownfield development on a tight deadline is never fun, it’s never elegant and it’s certainly not satisfying.

One problem I keep finding is code that repeatedly calls the backing stores with the same query. If I don’t have the time to refactor the code to work properly I sometimes cheat and use a cache that’s specific to the HttpContext. It’s not nice, but it does get me out of a hole every once in a while.

public static class ContextCache
{
	public static T Get(string key)
	{
		var value = HttpContext.Current.Items[key];
		return value is T ? (T)value : default(T);
	}

	public static void Put(string key, object value)
	{
		HttpContext.Current.Items[key] = value;
	}
}

It’s pretty simple to use:

var entity = ContextCache.Get("Entity_123");
if (entity == null)
{
    entity = GetFromBackingStore(123);
    ContextCache.Put("Entity_123", entity);
}

return entity;

This is definitely one of those bits of ugly code that can get you out of a hole in a rush. It aint pretty, but it works.

Forcing Culture Settings in WCF

1

I had the need to force the thread culture on a WCF service recently. The culture kept dropping back to en-US, but I needed it to run in en-GB as the client was sending me files with UK dates in them. After banging my head against every setting I could find I gave up and opted to write a custom WCF service and force the culture. It’s not a pretty hack, but it works.

If you use this and it breaks your servers, steals your wallet and then runs off with your wife, consider it your fault for using code from some random blog post you found. Caveat emptor applies.

You can download a working sample here: WCFCulture

First up we need to create a message inspector to hook in and mush about with our messages:

public class CultureMessageInspector : IDispatchMessageInspector
{
	private readonly string _culture;
	public CultureMessageInspector(string culture)
	{
		_culture = culture;
	}

	public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
	{
		Thread.CurrentThread.CurrentCulture = new CultureInfo(_culture);
		return null;
	}

	public void BeforeSendReply(ref Message reply, object correlationState)
	{
	}
}

Then we need to hook this into an endpoint behaviour:

public class CultureBehavior : IEndpointBehavior
{
	private readonly string _culture;
	public CultureBehavior(string culture)
	{
		_culture = culture;
	}

	public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
	{
	}

	public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
	{

	}

	public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
	{
		var inspector = new CultureMessageInspector(_culture);
		endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
	}

	public void Validate(ServiceEndpoint endpoint)
	{
	}
}

And because we want to configure the culture we end up using, we need a custom extension element:

public class CultureExtensionElement : BehaviorExtensionElement
{
	[ConfigurationProperty("Culture", DefaultValue = "en-GB")]
	public string Culture
	{
		get { return (string)base["Culture"]; }
		set { base["Culture"] = value; }
	}

	protected override object CreateBehavior()
	{
		return new CultureBehavior(Culture);
	}

	public override Type BehaviorType
	{
		get { return typeof(CultureBehavior); }
	}
}

Ok, so assuming that you can get that pretty lot to compile all we need to do is hook it in via the web.config in the services project.

First register the extension:


	
		
			
		
	

Then to your behaviour simply add:

Your resulting config should look a bit like this:


	
		
			
				
				
			
		
		
			
				
			
		
	
	
		
			
		
	
	

So now, it won’t matter what your client wants the culture to be, you can override it in config.

Timestamp Your Assembly Version

0

Recently Jimmy Bogard (@bogardj) blogged about a simple, but very effective versioning strategy for .Net assemblies. I thought I’d show you how I implemented that for a project I’m working on.

I opted to use MSBuild Community Tasks, which can be downloaded from here. To get started, crack open your .csproj file and find the line that starts with “<Import Project”, there might be several of them, just find the last one. Underneath the last one add the line:

This just lets MSBuild that we are going to use the targets files that come with MSBuild Community Tasks. Next we need to wire in our new assembly info file, the current on will be replaced with the output of the build task.

A pretty much complete version follows immediately, but if you want it explaining a bit; keep reading.


	
	
	
	
	
	

This translates to:

Create a new target called version.

Create a new build property called year that is the current year in the form “yyyy”. This is repeated for the month, day and time.

This is simply for diagnostics purposes and dumps a message out as part of the build process.

Then we wire up our new assembly info file, making sure we fill in everything that we need. At this point we are able to set the AssemblyVersion and the AssemblyFileVersion with our new timestamp.

The last thing we must do is to let MSBuild know when to run this task. I opted to put this in as part of the “BeforeBuild” target. If you’ve got other targets running then you may have a better place to put it, but this works fine for me. The key part is to make sure this task runs before the compiler runs.


That’s it, my assembly now has a nice timestamp, which makes it pretty simple to track when it was built.

A Gotcha when Comparing ImageFormat in .Net without TDD

0

I’m not there yet, but I’m working towards doing TDD / BDD for nearly all of my code. Even though I’m doing a lot of Web Forms development at the moment I’m discovering that it is still possible to drive a very large portion of my development through testing. Occasionally when I’m in a rush or the code seems very trivial I’ll fall back into bad habits and code first, test later. Sadly later is often too late.

One such example was when I needed the mime type of an image that was passed to me as a byte array, since I know that the images are always going to be thumbnail sized and the result will be cached I wrote a method similar to this:

public string GetMimeType(byte[] imageData)
{
    ImageFormat format;
    using (var buffer = new MemoryStream(imageData))
    {
        var image = Image.FromStream(buffer);
        format = image.RawFormat;
    }

    if (format == ImageFormat.Png)
    {
        return "image/png";
    }

    // repeated for a bunch of mime types

    return "image/jpeg";
}

Nothing extravagant, I tested it very briefly with a jpeg and moved on. The best way to show how wrong I was is to write the tests I should have written when I was feeling slack.

[TestFixture]
public class ImageFormatCompareTests
{
    byte[] singlePixelPng = new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49,
                                            0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02,
                                            0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xDE, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52,
                                            0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41,
                                            0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05, 0x00, 0x00, 0x00,
                                            0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3,
                                            0x01, 0xC7, 0x6F, 0xA8, 0x64, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54,
                                            0x18, 0x57, 0x63, 0xB0, 0xF7, 0x38, 0x03, 0x00, 0x02, 0x1D, 0x01, 0x54, 0x40,
                                            0xC5, 0x12, 0x88, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42,
                                            0x60, 0x82 };

    private ImageFormat GetImageFormatForImage(byte[] imageData)
    {
        using(var buffer = new MemoryStream(imageData))
        {
            var image = Image.FromStream(buffer);
            return image.RawFormat;
        }
    }

    [Test]
    public void ComparePngUsingEqualsEquals_Fails()
    {
        //Arrange
        var formatFromPng = GetImageFormatForImage(singlePixelPng);

        //Act
        var areImageFormatsEqual = formatFromPng == ImageFormat.Png;

        //Assert
        Assert.That(areImageFormatsEqual, Is.True);
    }

    [Test]
    public void ComparePngUsingEqualsMethod_Suceeds()
    {
        //Arrange
        var formatFromPng = GetImageFormatForImage(singlePixelPng);

        //Act
        var areImageFormatsEqual = formatFromPng.Equals(ImageFormat.Png);

        //Assert
        Assert.That(areImageFormatsEqual, Is.True);
    }
}

It turns out that the ImageFormat class has not overridden the == operator and since that’s not implemented the runtime drops back to Object.ReferenceEquals which will always return false in my case. Simply switching my code over to using the .Equals fixes my problems and acts as a very simple wrap on the knuckles to not get lazy with TDD. Lesson re-learnt.

Unit Testing in 1995, Hello ASP .Net Membership Providers

2

Among the many wonders that is .Net we have the task parallel library, linq, a first class garbage collector and the legend that is Jon Skeet. If, however, you have the crazy desire to unit test code that relies on System.Web.Security.Membership you’re in for a world of pain. To ease that pain slightly I’ve created an interface to hide away all that static class nastiness. Now mock out the behaviours that you need to test and pretend all is right with the world.

using System.Web.Security;
using System.Web.Configuration;

public interface IMembershipWrapper
{
    MembershipUser CreateUser(string username, string password);
    MembershipUser CreateUser(string username, string password, string email);
    MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, out MembershipCreateStatus status);
    MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status);
    bool DeleteUser(string username);
    bool DeleteUser(string username, bool deleteAllRelatedData);
    MembershipUserCollection FindUsersByEmail(string emailToMatch);
    MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords);
    MembershipUserCollection FindUsersByName(string usernameToMatch);
    MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords);
    string GeneratePassword(int length, int numberOfNonAlphanumericCharacters);
    MembershipUserCollection GetAllUsers();
    MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords);
    int GetNumberOfUsersOnline();
    MembershipUser GetUser();
    MembershipUser GetUser(bool userIsOnline);
    MembershipUser GetUser(object providerUserKey);
    MembershipUser GetUser(string username);
    MembershipUser GetUser(object providerUserKey, bool userIsOnline);
    MembershipUser GetUser(string username, bool userIsOnline);
    string GetUserNameByEmail(string emailToMatch);
    void UpdateUser(MembershipUser user);
    bool ValidateUser(string username, string password);
}

public class MembershipWrapper : IMembershipWrapper
{
    public MembershipUser CreateUser(string username, string password)
    {
        return Membership.CreateUser(username, password);
    }

    public MembershipUser CreateUser(string username, string password, string email)
    {
        return Membership.CreateUser(username, password, email);
    }

    public MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, out MembershipCreateStatus status)
    {
        return Membership.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, out status);
    }

    public MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
    {
        return Membership.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status);
    }

    public bool DeleteUser(string username)
    {
        return Membership.DeleteUser(username);
    }

    public bool DeleteUser(string username, bool deleteAllRelatedData)
    {
        return Membership.DeleteUser(username, deleteAllRelatedData);
    }

    public MembershipUserCollection FindUsersByEmail(string emailToMatch)
    {
        return Membership.FindUsersByEmail(emailToMatch);
    }

    public MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
    {
        return Membership.FindUsersByEmail(emailToMatch, pageIndex, pageSize, out totalRecords);
    }

    public MembershipUserCollection FindUsersByName(string usernameToMatch)
    {
        return Membership.FindUsersByName(usernameToMatch);
    }

    public MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
    {
        return Membership.FindUsersByName(usernameToMatch, pageIndex, pageSize, out totalRecords);
    }

    public string GeneratePassword(int length, int numberOfNonAlphanumericCharacters)
    {
        return Membership.GeneratePassword(length, numberOfNonAlphanumericCharacters);
    }

    public MembershipUserCollection GetAllUsers()
    {
        return Membership.GetAllUsers();
    }

    public MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
    {
        return Membership.GetAllUsers(pageIndex, pageSize, out totalRecords);
    }

    public int GetNumberOfUsersOnline()
    {
        return Membership.GetNumberOfUsersOnline();
    }

    public MembershipUser GetUser()
    {
        return Membership.GetUser();
    }

    public MembershipUser GetUser(bool userIsOnline)
    {
        return Membership.GetUser(userIsOnline);
    }

    public MembershipUser GetUser(object providerUserKey)
    {
        return Membership.GetUser(providerUserKey);
    }

    public MembershipUser GetUser(string username)
    {
        return Membership.GetUser(username);
    }

    public MembershipUser GetUser(object providerUserKey, bool userIsOnline)
    {
        return Membership.GetUser(providerUserKey, userIsOnline);
    }

    public MembershipUser GetUser(string username, bool userIsOnline)
    {
        return Membership.GetUser(username, userIsOnline);
    }

    public string GetUserNameByEmail(string emailToMatch)
    {
        return Membership.GetUserNameByEmail(emailToMatch);
    }

    public void UpdateUser(MembershipUser user)
    {
        Membership.UpdateUser(user);
    }

    public bool ValidateUser(string username, string password)
    {
        return Membership.ValidateUser(username, password);
    }
}
Go to Top