Thursday, 31 May 2012

Unit testing MVC routes

If you are using the MVC Routing engine, you can test your routes to ensure that they work as expected.

To test the default route:

[Test]
routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home",
          action = "Index",
          id = UrlParameter.Optional }
);

The example test is:

[Test]
public void DefaultRouteTest()
{
    var routes = new RouteCollection();
    var application = new Application();
    application.RegisterRoutes(routes);

    var context = new Mock<httpcontextbase>();
    context.Setup(p => p.Request.AppRelativeCurrentExecutionFilePath)
                                   .Returns("~/");
    var routeData = routes.GetRouteData(context.Object);

    Assert.AreEqual(((Route)routeData.Route).Url, 
                    "{controller}/{action}/{id}");
    Assert.AreEqual("Home", routeData.Values["controller"]);
    Assert.AreEqual("Index", routeData.Values["action"]);
}

This came from an original post by Scott Gu, that we had to change slightly. http://weblogs.asp.net/scottgu/archive/2007/12/03/asp-net-mvc-framework-part-2-url-routing.aspx

The original code was causing the first parameter to drop the first character. i.e. For the default route, the controller was return 'ome' instead of 'home'.

Wednesday, 11 April 2012

Profile not available in Web Application

Using the Web Application project, you are unable to use the intellisense on the Profile class. A workaround has been provided by Joe Wrobel in a post build task.
This post build task is called Web Profile Builder and can be download here.
The simple approach:
  1. Install the package.
  2. Add the following to your .csproj file
    <Import Project="$(MSBuildExtensionsPath)\WebProfileBuilder\WebProfileBuilder.targets" />
  3. Build project
Joe has a more details in his post on how to use the build task.

Datatables update function shows an Alert Box

When using the jQuery Datatable plugin and jeditable to allow tables to be editable, calling the update function via sUpdateUrl shows an alert box on it's return.
To suppress the alert box, return the same value that was originally passed in.
C# MVC Example:
$('#myDataTable').dataTable().makeEditable({
    sUpdateURL: "/Home/UpdateData"
})

public class HomeController : Controller
{
    public string UpdateData(int id, string value,
                             int? rowId, int? columnPosition,
                             int? columnId, string columnName)
    {
        //Add code to update cell
        return value;
    }
}
Code borrowed from http://code.google.com/p/jquery-datatables-editable/wiki/EditCell

Tuesday, 6 March 2012

Checkbox validation with the MVC data annotations

I've been using MVC3 for a new site and require a check box to be true before continuing. e.g. "Accept T & Cs".

The data annotation have the [Required] attribute for other field types, but this is ignored for check boxes.

You can create your own custom validators. Below is an example for a single check box to ensure it is true.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class MustBeTrueAttribute : ValidationAttribute
{
      public override bool IsValid(object value)
      {
            return value != null && value is bool && (bool)value;
      }
}

You can then add the attribute to your MVC component model

[Display(Name = "I accept the terms and conditions")]
[MustBeTrue(ErrorMessage = "Please accept terms and conditions before continuing")]
public bool AcceptTerms { get; set; }

This solution was discovered on StackOverflow

Thursday, 19 January 2012

WCF Error - This collection already contains an address with scheme http.

This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.
I've found two solutions to this error depending on which version of the .NET framework you are using. You need to update the web.config with the following:

.NET 4.0

<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />

.NET 2.0 - 3.5

<serviceHostingEnvironment>
  <baseAddressPrefixFilters>
    <add prefix="http://www.yourdomain.com"/>
  </baseAddressPrefixFilters>
</serviceHostingEnvironment>

Unknown server tag 'asp:ScriptManager'

Currently build a new portal using Ajax for asynchronous calls.  Had the following error:
Unknown server tag 'asp:ScriptManager'

This error has caused me a headache over the last few days.  I finally narrowed it down to a missing line in the web.config.

<pages>
  <controls>
    <add tagPrefix="asp" namespace="System.Web.UI" 
            assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  </controls>
</pages>

Tuesday, 17 January 2012

SetSite failed for package [Visual Studio Class Designer Package]

When starting Visual Studio you get a pop up which contains the following error:
The package 'Visual Studio Class Designer package' has failed to load properly. GUID {DD1683A7-5A4C-4234-81B3-A4CC91DBEAC9}
Close Visual Studio.

Now start Visual Studio with devenv /log

Navigate to the log location, normally:
C:\Users\username\AppData\Roaming\Microsoft\VisualStudio\10.0\ActivityLog.xml
If this log contains the following entries:

<entry>
 <record>208</record>
 <time>2012/01/17 15:06:00.310</time>
 <type>Information</type>
 <source>VisualStudio</source>
 <description>Begin package load [Visual Studio Class Designer Package]</description>
 <guid>{DD1683A7-5A4C-4234-81B3-A4CC91DBEAC9}</guid>
</entry>
<entry>
 <record>209</record>
 <time>2012/01/17 15:06:00.412</time>
 <type>Error</type>
 <source>VisualStudio</source>
 <description>SetSite failed for package [Visual Studio Class Designer Package]</description>
 <guid>{DD1683A7-5A4C-4234-81B3-A4CC91DBEAC9}</guid>
 <hr>8000ffff - E_UNEXPECTED</hr>
 <errorinfo>Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))</errorinfo>
</entry>
<entry>
 <record>210</record>
 <time>2012/01/17 15:06:00.415</time>
 <type>Error</type>
 <source>VisualStudio</source>
 <description>End package load [Visual Studio Class Designer Package]</description>
 <guid>{DD1683A7-5A4C-4234-81B3-A4CC91DBEAC9}</guid>
 <hr>8000ffff - E_UNEXPECTED</hr>
 <errorinfo>Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))</errorinfo>
</entry>
Now start Visual Studio with devenv /ResetSettings

If this doesn't work, then repair or re-install Visual Studio.

Monday, 12 December 2011

MSBuild and XmlTransform

Using .NET 4.0 you can use the Config Transformation features by which we can maintain multiple configuration files for different environments. To have one of these files built as part of your continuous integration you can use the MSBuild task TransformXml:

An example of the code usage is below:

<UsingTask TaskName="TransformXml" 
           AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>

<Target Name="GenerateConfigs">
  <TransformXml Source="Source\Web.config"
                Transform="Source\Web.$(Configuration).config"
                Destination="Output\Web.config"/>
</Target>

MSBuild - Non-string data for Inetstp@MajorVersion

When using the the Microsoft.Web.Publishing.Tasks.dll library to do the XML Transforms in a Continuous Integration set-up, like TeamCity. You receive an error like below:

[GetProjectWebProperties] error MSB4138: Non-string data was specified at the registry location "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Inetstp@MajorVersion".

If this is the case, ensure that your build scripts are using .NET 4.0. The scripts I had were defaulting to use .NET 3.5 which threw the error.

Thursday, 24 November 2011

YAF Polls - You already voted.

A user can't vote as it says "You already voted." when you know you haven't voted with this user account. Have you voted though with a different user account from the same machine or the same network?
By default, YAF only lets a user vote if no one using the same IP Address has already voted.
You can turn this feature off in Host Settings -> Features -> Poll Options -> Poll Votes Dependant on IP