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.

Getting Started with Rails

1

I started in BASIC, moved to Java, then to .Net. After working in .Net for about 6.5 years it’s time to properly learn something new. I’ve had my eye on learning Ruby on Rails for a while, but haven’t ever really had a reason.

I still don’t have a compelling reason, but I’m going to have a go at learning it anyway.

First things first, I need to get my Windows 7 machine ready to start developing. It turns out this is a really easy job.

  1. Download the latest version of Ruby. I used a handy windows installer from here: http://rubyinstaller.org/
  2. Open a command prompt and type: gem update –system
  3. Then once that’s finished type: gem install rails
  4. Now I need a folder to do my project work in: mkdir MyFirstRailsApp (on my desktop for now)
  5. Switch to that directory: cd MyFirstRailsApp
  6. Create a new project: rails new MyFirstRailsApp
  7. Now switch to the directory rails just created for you and get the sqllite bits and bobs: bundle install (I’m not 100% sure that I had to run this command, but it certainly doesn’t seem to have caused any problems)
  8. Download the SQLite dlls from here and drop them into you ruby/bin directory, mine is c:\Ruby192\bin\
  9. Now you’re ready to start your rails server, make sure you are in your project directory and type: rails server
  10. If everything has gone correctly you should now be able to navigate to http://127.0.0.1:3000/ and view your first Ruby on Rails application.

Look ma, I’m a ruby developer!

If everything in rails is as easy as this, I my find I go off .Net really quickly. Watch this space for me making a mess of learning how to actually do work in rails.

    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);
        }
    }

    Enable SSL in web.config for SmtpClient

    5

    If you want to use SSL when connecting to your email server and are using the SmtpClient from .Net 4.0 you can now set EnableSSL via the web.config file, which you couldn’t do before.

    I’m only posting this because the docs (http://msdn.microsoft.com/en-us/library/w355a94k.aspx) for .net 4 don’t seem to bother mentioning it, which is a bit frustrating.

    Now you can do this:

    <configuration>
        <system.net>
            <mailSettings>
                <smtp deliveryMethod=”network”>
                    <network host="localhost"
                             port="25"
                             enableSsl="true"
                             defaultCredentials="true" />
                </smtp>
            </mailSettings>
        </system.net>
    </configuration>

    An imperfect Hack to Keep App_Offline Showing When You Delete Your Web App

    0

    In a simple world, a good solution for deploying web apps looks a bit like this:

    1. Remove server from load balancer
    2. Remove old site
    3. Install new site
    4. Verify installation locally
    5. Add server back into the load balancer

    Nice and simple, now you just move onto the next server and repeat the process.

    The problem I have is that I don’t have that kind of access to the load balancer; I have no mechanism for taking a given server out of action other than using the app_offline.htm file. This works tolerably, but it’s a dirty hack rather than an elegant solution. As part of my deployment process I always delete all files in the site, this is fine as all data is stored either in a database or in a different folder. This causes problems for asp.net as it stops seeing the site as an application and ignores the app_offline.htm file. That’s no good for users as they will start to see either the default 404 page, or a message about the directory listing not being found. A simple hack that I’ve put in is to add the app_offline.htm to the list of default documents; also I set the IIS 404 for that site to app_offline.htm. It’s safe to do this as my app sets its own 404 pages, so in normal operation the app_offline.htm is ignored. It’s not a perfect solution, but it is better than nothing and hopefully brings the number of users seeing duff pages down to a minimum.

    What I really need now is a way for the app_offline.htm file to be ignored for requests coming to the local machine and then I can stop doing deployments in front of my users.

    So you’d Like Implicit Casting in Moq?

    0

    I love using Moq, it’s great and it saves me a huge amount of time and effort when I’m writing unit tests. There’s only thing that bothers me about it. The Object property on a mock, why is this even needed? Surely the judicious use of the implicit keyword and you could have a cleaner API, for example (coded in a text editor, I haven’t even tried to compile it):

    var mockFileSystem = new Mock<T>();
    var objectUnderTest = new FileBackedThingy(mockFileSystem.Object);
    objectUnderTest.Save();
    mockFileSystem.Verify(x => x.SaveFile(It.IsAny()), Times.Once);

    Could be replaced with:

    var mockFileSystem = new Mock<T>();
    var objectUnderTest = new FileBackedThingy(mockFileSystem);
    objectUnderTest.Save();
    mockFileSystem.Verify(x => x.SaveFile(It.IsAny()), Times.Once);

    Now, I know it doesn’t really make much difference, but it does make things a little nicer to my eyes. So it’s Sunday afternoon, my wife’s got rehearsals and gigs all day. What’s a geek to do?

    Never having seen the Moq codebase before I thought it might take a little while to find what I needed to do, I was wrong, in about 90 seconds I found the Moq.Mock class and thought I’d just need to add something along the lines of:

    public static implicit operator T(Mock mock)
    {
        return mock.Object;
    }

    A really simple change, weirdly the code is already there, but commented out. Since commented out code is one of my programmer pet hates and it was code I was hoping for, this was a bit like a red rag to a bull. Fortunately there was a reasonably sensible comment justifying this heinous action:

    // NOTE: known issue. See https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=318122

    The complaint is a simple one, C# won’t let you have user defined casts between interface types. Also, they won’t let us have it, ever. So the lesson learned? No idea, but I think Bravo is show the monster trucks, so I might watch that and snooze before I go out.

    FindParent Extension Method for Web Controls

    0

    This is another one of those tiny bits of code that I’ve written too many times and I don’t want to waste my time thinking about again. It’s simple, but I’m bored of writing it. I’ve also posted it to http://www.extensionmethod.net (http://www.extensionmethod.net/Details.aspx?ID=415)

    Anyway it all its limited glory;

    public static T FindParent(this Control target) where T : Control
    {
        if (target.Parent == null)
        {
            return null;
        }
    
        var parent = target.Parent as T;
        if (parent != null)
        {
            return parent;
        }
    
        return target.Parent.FindParent();
    }

    Unable to Update WordPress Plugins Hosted in IIS 7

    0

    I’ve had a bit of trouble updating my Worpress plugins this evening, it’s normally a 30 second job, but tonight things were being a bit tricky.

    Initially I was seeing Akismet complaining that it couldn’t create its plugin directory. Looking at the folder in <website root>\wp-content\plugins\ I could see that the folder was already there. Assuming that the plugin updater was just being daft I thought I’d delete it myself and try again. Nope, no joy, the folder wouldn’t budge. My first guess was that something in IIS was holding a reference to the folder and not letting go. The easiest (if somewhat brutal option) was iisreset, but that didn’t help either.  The next thing I tried was to use the folder options and check its permissions and that’s where thing started to get a bit odd. The GUI was unable to show me the permissions to the folder and also refused to allow me (running as an elevated user) to take ownership of the folder. So I ran up a command prompt (again with elevated permission) and pointed takeown.exe at the folder; the command ran and told me it had successfully given me ownership. Nice! On to deleting the folder and trying again, oddly, the folder wasn’t there anymore. Giving me permissions was clearly too much of a humiliation for the folder, it had committed hara-kiri and was no more. Simply reinstalling askismet to the latest version left my server happy as can be and left me a little more confused as to how windows handles it’s folders.

    Saving CSV files in UTF8 Creates  Characters in Excel

    1

    A few weeks ago in work I was minding my own business creating one of the ubiquitous “Export to CSV” features. You know the one, the one that screams “My application even get close to what my client needs, we’ve run out of time, CSV FTW!”, yep, that one. Anyway, I ran my testing and checked the code in, happy that it did what it was supposed to.

    Wrong.

    I got a bug report from the client that the exported file had spurious  characters in it. Well, I ran the tool popped open the file in notepad++, nope, nothing in there. I ran the export with a larger dataset and tried again, ok now for a monster export, give me everything. Still no joy, so I did what the average developer is prone to doing and assumed that the client was being daft. I pushed back and asked for the client to give me an example. They did, I opened the file and nope, there wasn’t a single  in the file. Ok, so either the client is having a laugh at my expense, they’re lying or I’m missing something. Knowing this client, I’m missing something. I open the file again, but for a moment pretend I’m not a developer and open the file in Excel. Â’s abound, arse, how did I do that?!

    It turns out that for all Excel’s sophistication it doesn’t like UTF-8 encoded files. It’s much more at home with files encoded as Windows-1252, well at least for Latin languages; I’m not sure what happens in non-Latin languages.

    So if you have code that looks like this:

    using (var writer = new StreamWriter("myfile.csv", false))
    {
        writer.WriteLine("Look,Ma,I,Can,Do,CSV");
    }

    Change it to this:

    using (var writer = new StreamWriter("myfile.csv", false, Encoding.GetEncoding("Windows-1252")))
    {
        writer.WriteLine("Look,Ma,I,Can,Do,CSV");
    }

    And now Excel will play nice. You can now rest easy in the knowledge that your client can use Excel to draw pretty graphs, pivot things and you know, do whatever it is normal people do with Excel.

    Go to Top