Tuesday, 13 April 2010

MVC DateTime Suffix HTMLHelper

Recently I have been working on an MVC Project, and tonight I got to the point where I wanted to output a date in a specific format, for example Tuesday 13th April 2010. Sadly DateTime formatting still doesn't allow you to specify output a suffix, you can do Tuesday 13 April 2010 but not what I wanted.


I decided that I could achieve what I wanted by writing a quick HTMLHelper, this would then allow me to specify a datetime format string with a magic / special character which I could then replace for the appropriate suffix.


Writing the helper was very quick and easy, if you want to learn about HTMLHelpers and how to write your own I recommend looking at Stephen Walther's Post on HTMLHelpers .

The code for my datetimehelper is below:


using System;
using System.Web.Mvc;

namespace mjjames.MVCHelpers
{
 public static class DateTimeExtensions
 {
  public static string DateTimeFormat(this HtmlHelper helper, string dateTimeFormat, DateTime dateTime){
            var dateTimeOutput = dateTime.ToString(dateTimeFormat);
            if (dateTimeFormat.Contains("~"))
            {
                dateTimeOutput = dateTimeOutput.Replace("~", GenerateDaySuffix(dateTime.Day));
            }
      return dateTimeOutput;
  }

        /// <summary>
        /// Generates a Day Suffix from the Day Number
        /// </summary>
        /// <param name="day">Day Number</param>
        /// <returns>Suffix String</returns>
     private static string GenerateDaySuffix(int day)
     {
         var suffix = "";
            //find out if the day matches a suffix which isn't th
         switch(day)
         {
             case 1:
                case 21:
                case 31:
                 suffix = "st";
                    break;
                case 2:
                case 22:
                 suffix = "nd";
                 break;
                case 3:
                case 23:
                 suffix = "rd";
                    break;
                default:
                 suffix = "th";
                 break;
         }
         return suffix;
     }
 }
}

Then to use it first include the namespace in your view:


<%@ Import Namespace="mjjames.MVCHelpers" %>

And then to use it call Html.DateTimeFormat passing the format string and the DateTime value. To use the day suffix include the ~ character. Note you can use it with.


<%= Html.DateTimeFormat("dddd d~ h", Model.StartDate) %>
<%= Html.DateTimeFormat("dddd d h", Model.EndDate) %>

There we go, nice and easy, if you want to use this feel free I hope it helps

Tuesday, 6 April 2010

Using DOTRas - An Overview and some things I've learnt

Yesterday I decided to starting knocking together a quick application to help me backup my server to some local storage. The idea being that at any point I have a local copy of my server setup a maximum of a day old. The point of this application and how I've gone about writing it, what libraries I'm using etc will be part of a future blog post.


I decided early on that I however I wanted to transfer files I wanted to do this over a VPN to the server. I had several reasons for this, being able to expose my files over a network share, more secure etc. My Application will be running on an old laptop, so I first thought about just always having it connected to a VPN using windows, and run the application as normal. However I then thought what if the VPN disconnects and I don't notice, how long would it take until I noticed etc. So I decided to make the application create a VPN Connection at start up and then disconnect from it upon completion.


I figured that there would be a good library that would help with this and it turns out there is. DotRAS provides remote access service (RAS) components for .NET languages , it's tag line is "WindowsRAS made easy" and I have to say so far it has lived up to that.


A quick example of how to open the computers RAS PhoneBook :


using(var phoneBook = new RasPhoneBook())
{
     phoneBook.Open();
}
You could then find an existing entry within the phonebook to make a connection too and open a connection:

var entry = phoneBook.Entries.FirstOrDefault(e => e.Name.Equals("mikes test entry");
if(entry != null){
    entry.Open();
}

Now there's obviously alot you can do with it, create and manage connections programatically etc, use phone dialers but so far I'm just tinkering with VPN's.


Tips and Tricks

Now to what I wanted to post about, tips and tricks. Sadly whilst working with DOTRas I found a few gotcha's that I wanted to post about. I will also update this list as I find more. It's worth noting that all of these apply to DotRAS 1.1 and I'm using the Win2k8 build, some of these I know also apply to the XPSP2 build. And my development machine is Windows 7 x64.

Invalid Default PhoneBook Location

The default phonebook location, which is called when you just do phonebook.Open(), is set to use RasPhoneBookType.AllUsers, now this maps to : C:\ProgramData\Microsoft\Network\Connections\Pbk\rasphone.pbk which for me doesn't exist. The folders exist up to connections, I have no Pbk folder.


I could obviously check for this and then create the phonebook entry but really you should always use RasPhoneBookType.User which uses the phonebook located within the current users AppData.

The entry is not associated with a phone book

Actually quite an obvious issue but worth commenting on, If you create a new phonebook entry


var entry = RasEntry.CreateVpnEntry(_connectionName, IPAddress.Loopback.ToString(), RasVpnStrategy.Default,                                 RasDevice.GetDeviceByName("(PPTP)", RasDeviceType.Vpn));

And then try to set the user's credentials without first adding the entry to the phonebook:


entry.UpdateCredentials(new NetworkCredential(authenticationDetails.UserName, authenticationDetails.Password));

Everything goes horribly wrong, instead add the entry to the phonebook and then set the credentials.


phoneBook.Entries.Add(entry);
entry.UpdateCredentials(new NetworkCredential(authenticationDetails.UserName, authenticationDetails.Password));

Keep an eye on this post, I'll update it as I continue to use DotRAS and then on a later date post about my application in full.

Tuesday, 9 February 2010

Unable to merge or create branches with SVN

I've been using SubVersion for a while, several years infact, I use VisualSVN on my server and TortoiseSVN on my machines.


Until recently I had never experienced any problems or glitches with it. However at some point within the last two months one of my main repositories started playing up. It's the only repository I have ever branched. The problem occurred when after working on a branch for several months I decided it was time to merge it back into the head. However when I tried to use the merge function and take the branch into the head I was given the following error message:

[branch] is not a child of repository root URL [trunk]


I tried several attempts at trying to do this, rechecking out the branch and trunk in case they were corrupt but to no avail. I then decided to try creating a new branch to see if the repository was totally broken and I indeed got an error.

Repository moved permanently to [svn server address] please relocate;


So it looked liked the reopsitory was broken. On a bit of a whim I noticed that my file path looked something similar to f:\development\shared\a repository name\trunk and similarly the branch was f:\development\shared\a repository name\1.6 The SVN url however was http://[svn-url]/svn/arepositoryname , I was wondering if somehow the directory path was confusing SVN, was it always expecting the directories to be checked out in the same folder structure as the server.


So I tried creating a new directory called arepositoryname and then checked out the trunk and version 1.6 underneath it. I then tried to merge the 1.6 repository back into the trunk and create a new branch and it all worked fine!


So it indeed seemed that TortoiseSVN was getting confused by my folder structure not replicating the servers, simply fixing this, maybe it was just removing the spaces need to possibly try that further, resolved my issue.


Just to add clarification if you stumble across this trying to solve your issue that I was running VisualSVN 2.1 and Tortoise 1.6 on a Windows 7 x64 machine.


Some crazy behaviour but I least I figured it out after several hours ... hope this helps.

Friday, 22 January 2010

Drivers Causing "This file came from another computer and might be blocked to help protect this computer" On Startup

This weekend I had to reinstall a driver for a laptop touch pad. I went to the Sony site and got the driver, it came in a zip file and looked pretty standard. A load of driver files and an install file.


It install all OK and the touchpad started to have its scroll options, however then I rebooted and found each time the laptop started up Windows Vista kept asking to confirm I wanted to run the programs, "This file came from another computer and might be blocked to help protect this computer". Straight away I thought it had to be the file was blocked from running as it came from a download. I went to the files unblocked them all, clicked apply and rebooted again only to find it happen again.


Just to ensure I hadn't forgotten to click apply I tried this again only to find the same thing. After Googling for the issue I found the issue was that the installer had simply copied the drivers and files. This meant that the NTFS information was also copied, this information contained the flag "downloaded from internet" along with others.


The solution was to strip these files of this information, luckily you can obtain a free tool to do this. "Streams" from Sysinternals, I simply downloaded this,http://www.microsoft.com/technet/sysinternals/utilities/Streams.mspx, ran it on the directory, command prompt only, and rebooted to find all was well.

Certainly one to remember as I have came across this before and removed the program.

Thursday, 1 October 2009

Why we have to be more careful about what we read and more importantly what we write

In this day and age it is very uncommon to not use the internet to research or solve problems. Our reliance on printed reference books and even reference sites has dwindled massively.


As developers, especially budding developers, we often just Google our problems, in fact I think most of our senior dev's often say to us "have you Googled it?" When asked about something.


Now googling things of course has changed our industry, we can often solve problems or get good starting points within seconds.
This on its own is not a bad thing, we google we get the results and we crack on. The problem however is when you pick the first item or a random article and use what someone else has written as FACT.


The problem with our "Google" culture, this applys to more than programming, is that we often don't filter what we read. We suffer from fps, first page symdrom. If its on the first page of our results it has to be correct.


Sadly though all too often the actual blogs or forum posts we end up reading are from FACT. Today I was investigating an issue with a JS tab solution I had wrote and sadly found a ton of some very poor "tutorials". These articles / blogs although well presented and often written with the best intentions often lead people to learn / pick up bad habits. I won't name the article that prompted me to write this but to say the solution was so far wrong is an understatement.


New developers will always trust what they read, I think it stems from how our education systems work. I believe we need to refine our "google" culture tendencies and in particular our FPS.


How do we change this? Firstly we need to encourage people to not just read the first article / blog they reach from a search. Instead to open several tabs of articles on the subject matter and then read each one, and then and only then look at the common concepts / answers they provide. We need to consider multiple sources before something is FACT.


Also I believe blog and article writers also have an obligation to research / check out what others think or do regarding a subject before they post onto the internet. This also applies to big sites like the BBC, in fact the bigger you are the more this applies.


Its great to share solutions to problems and to write about things we like, things we have done, things we think are cool but we must ensure that what we write is technically sound, otherwise we continue to breed a culture and community of half baked products and websites.


This is where I believe sites like stack overflow and all their derivatives will help. As these sites continue to grow and questions with highly voted answers appear in our search engines, hopefully quality will begin to cut through the noise.


Our "google" culture no doubt makes things easier and quicker and I'm a believer in "have you Googled for it?" , but I do think us as writers and us as searchers need to be more analytical of what we read in order to produce things of higher quality and to grow in our profession.

Wednesday, 26 August 2009

TDD Masterclass in the UK

Roy Osherove is giving an hands-on TDD Masterclass in the UK, September 21-25. Roy is author of "The Art of Unit Testing" (http://www.artofunittesting.com/), a leading tdd & unit testing book; he maintains a blog at http://iserializable.com (which amoung other things has critiqued tests written by Microsoft for asp.net MVC - check out the testreviews category) and has recently been on the Scott Hanselman podcast (http://bit.ly/psgYO) where he educated Scott on best practices in Unit Testing techniques. For a further insight into Roy's style, be sure to also check out Roy's talk at the recent Norwegian Developer's Conference (http://bit.ly/NuJVa).


Full Details here: http://bbits.co.uk/tddmasterclass

bbits are holding a raffle for a free ticket for the event. To be eligible to win the ticket (worth £2395!) you MUST paste this text, including all links, into your blog and email Ian@bbits.co.uk with the url to the blog entry. The draw will be made on September 1st and the winner informed by email and on bbits.co.uk/blog

Friday, 26 June 2009

FlickVimTube - An FCKEditor Plugin

First things first, ignore the random title for this post, it does have a meaning and it's the best I could up with ;)


The other evening I was hitting some downtime and rather than carry on playing FarCry 2 I decided I'd write a quick FCKEditor plugin which I've been meaning to write for a while. By default the editor comes with functionality to insert flash files into your content which works well however I wanted to have a way to only insert online videos from Flickr, Vimeo or YouTube. To insert these I was having to manually go into source view, paste in the embed code etc. A chore and a heartache.


So enough was enough and I banged together a quick plugin that would take a YouTube Embed URL and then insert the appropiate embed HTML for it. This was actually quite simple. I worked out there was four main steps, 1. Extract the video ID from the URL 2. Create suitable embed markup and insert into the editor 3. Create a preview video so you can ensure it works before clicking ok. 4. Be able to view and update the video after inserting.


Extracting the video ID I'm sure could be done using some clever regex expression however for simplicity and speed I opted to simply slice the YouTube url at ?v= bit and then use the remainder as the ID. As the official embed url is in the format http://www.youtube.com/watch?v={id} I have decided for my first version of this plugin I can nievly split, however I should really parse it properly.


To insert the embed object I made use of some build in FCKEditor methods to create the object and then assign the attributes to it.


e = FCK.EditorDocument.createElement('EMBED');
SetAttribute(e, 'src', embedUrl);

SetAttribute(e, 'type', 'application/x-shockwave-flash');
SetAttribute(e, 'pluginspage', 'http://www.macromedia.com/go/getflashplayer');

SetAttribute(e, "width", GetE('txtWidth').value == '' ? 360 : GetE('txtWidth').value);
SetAttribute(e, "height", GetE('txtHeight').value == '' ? 150 : GetE('txtHeight').value);
SetAttribute(e, "allowscriptaccess", "always");
SetAttribute(e, "allowfullscreen", "true");

After getting the basics working I decided to add support for Vimeo and Flickr. This was a case of just working out which service it was and then parsing out the id's and then setting the correct embed URL on the embed object.

FCKEditor plugin's are dead easy to configure, in your fckeditor settings file simply register the plugin using FCKEditor.Plugins.Add and ensure your custom toolbar settings include the button, 'OnlineVideo'


FCKConfig.ToolbarSets["mjjames"] = [
    ['Cut','Copy','PasteText','-','SpellCheck',
    '-','Image','OnlineVideo','Table','Rule','Smiley','SpecialChar','-',
 'Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat','-','Link','Unlink','Anchor','-','Source'],
 ['Style','FontFormat','-','JustifyLeft','JustifyCenter','JustifyRight','JustifyFull',
 '-','Bold','Italic','Superscript','OrderedList','UnorderedList','-','Outdent','Indent'] 
];

FCKConfig.Plugins.Add('OnlineVideo', 'en');

The plugin file includes language settings for english, however adding additional languages can be added by simply providing translations for the labels and then changing your plugin registration to include the new file name. If you want to add French for example create a file called fr.js in the plugins languages and then the plugin registration becomes:


FCKConfig.Plugins.Add('OnlineVideo', 'fr');

The following language settings are available:
OnlineVideoTip, DlgOnlineVideoTitle, DlgNoVideo, DlgInvalidVideoUrl, DlgOnlineVideoURL, DlgOnlineVideoWidth, DlgOnlineVideoHeight, DlgOnlineVideoQuality, DlgOnlineVideoLow, DlgOnlineVideoHigh.


The plugin can be downloaded as a zip file and is licensed under Creative Commons Attribution-Share Alike 3.0 License


In the future I intend to extend this further, maybe to allow users to find and search for videos using the various API's provided by the video sources but that will be at a later date.