Getting typed JSon in TypeScript using Weld

1. juni 2013 20:32 by admin in .net, DRY, jQuery, MVC, typescript, Weld
Imagine you have a MVC controller exposing a Person as following: 

public JsonResult GetPerson(int id)
{
return Json(new Person
{
First = "Barack",
Last = "Obama"
},JsonRequestBehavior.AllowGet);
}
Now I want to use this client side. I want to update my "first" span with the First property of the person I get back from the server. After messing around I came up with the following: 
$(document).ready(function() {
$.getJSON("/Person/GetPerson/", { id: 4 }, function(data) {
$("#first").text(data.First);
});
});
This took me five minutes to get right (which JQuery method? -> Google, how to pass data? -> find example, plus a typo in the first/First member). Five minutes of stupid getting right what should be trivial. Why not let the compiler help? So using Weld I change my server side method to this :
[AjaxMethod]
public JsonResult<Person> GetPerson(int id)
{
return new JsonResult<Person>(Json(new Person
{
First = "Barack",
Last = "Obama"
}, JsonRequestBehavior.AllowGet)); ;
}
Basically I wrap my JsonResult in a generic wrapper JSonResult<T> (included with Weld) so that Weld knows what type to expect. Next I add the AjaxMethod Weld attribute. Client side I use TypeScript and use the generated proxy class.  
/// <reference path="Weld/PersonController.ts" />/// <reference path="typings/jquery/jquery.d.ts" />
$(document).ready(function () {
PersonController.prototype.GetPerson(2, (person) => {
$("#first").text(person.First)
});
});
Now person is a JavaScript object or a TypeScript 'any' type. No, Person is a fully defined TypeScript interface with a First and Last member just like my C# class. Here's the generated code:
/// <reference path="../typings/jquery/jquery.d.ts" />
class PersonController
{
GetPerson(id: number, callback: (data: Person) => any)
{
var url = "/Person/GetPerson";var data = { id: id };
$.ajax({
url: url,
type : "POST",
data: data,
success: callback,
});
}
}
interface Person
{
First: string;
Last: string;
}
As always in the end there is still JavaScript code generated which you can easily debug. Weld code is simple and clean. Easy huh? And there are more benefits:
  1. If I remove or rename my action-method the TypeScript compiler will detect my breaking client side code at compile time. If you just use javascript you will (hopefully) find out at runtime.
  2. If I add or remove properties from my Person class my changes will cascade to the clientside immediately. 
  3. I get a nice interface clientside making code completion really work 
  4. No more Googling JQuery methods
  5. This is more DRY (Don't Repeat Yourself). For example if you don't like JQuery you can build a Weld template using a different method. Regenate and you are ready
Weld is fully open source and can be found at weld.codeplex.com

Creating a Yes/No toggle switch for a boolean property in ASP.MVC

11. mei 2013 13:20 by admin in .net, jQuery, JQuery UI, MVC

When editing boolean values in MVC the default option is to use a checkbox. This results in the following Create page when using the default scaffolding

image

This is fine and works OK but sometimes you want something more..’fancy’. ASP.NET MVC ships with Jquery.UI so why no use the slider of JQuery.UI to create a nice toggle switch?

In this post I will use and modify a JQuery.UI plugin that will result in the following. The plugin is based on http://taitems.github.io/UX-Lab/ToggleSwitch/ which had some errors in my opinion.

image 

There are a two parts to this:

  1. Create a HTMLHelper extension method that renders a <select> element for the boolean property with <option> elements for true and false
  2. Change the rendered <select> element to a jquery slider using a JQuery.UI plugin

Creating the HTMLHelper

public static class HtmlHelperExtensions
{
public static MvcHtmlString ToggleSwitchFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool>> expression)
{
return htmlHelper.DropDownListFor(expression, new[]
{
new SelectListItem { Text = "No", Value = "false" },
new SelectListItem { Text = "Yes", Value = "true" } 
}, new { @class = "toggleswitch" });
}
}

This adds a HTMLHelper method that renders a dropdown list which comes down to a single select HTML element. There are two options in the select : one for true and one for false. To use it we just do 

@Html.ToggleSwitchFor(model => model.CommentsEnabled)

And we get the following html

<select class="toggleswitch" data-val="true" data-val-required="The CommentsEnabled field is required." id="CommentsEnabled" name="CommentsEnabled"><option value="false">No</option><option value="true">Yes</option></select>

This is all what we need to get our JQuery plugin going.

Creating the JQuery plugin

The plugin uses the JQuery.UI slider to create a toggle switch. This means that any styling or theme you might have for the slider will work for the toggle as well. The plugin transforms the select element into two labels with a slider in between. When you click on a label or move the slider the select control will be updated as well and when you do form post the values get updated. The http://taitems.github.io/UX-Lab/ToggleSwitch/ had two errors when I tried it

  1. The change event was just passing the change event of the slider. This meant even if the boolean property did not change (you moved the slider a little) you would still get a change event. In this version the change event is only fired when the value really changed.
  2. The plugin did not allow chaining.
  3. The normal ‘change’ event of JQuery was no longer fired. This is fixed by not having a change event on the control itself but just fire the existing change event.

To use it you need to add the CSS and JS of the plugin to your page. You also need the default JQuery UI js and css (which is not referenced by default!). Once you have done that you can activate the plugin for a control:

$(document).ready(function () {
$("#CommentsEnabled").toggleSwitch().change(function() {
alert("Changed!!");
});
});

I attached a sample MVC application as well as the JQuery.UI.ToggleSwitch plugin.

ToggleSampleMVC4.zip (771,1 KB)
jquery.ui.toggleswitch.zip (1,73 KB)

Adding and removing build targets from NuGet powershell

1. mei 2013 15:56 by admin in .net, msbuild, nuget
In NuGet packages you can add powershell scripts to alter the .csproj file of the project in which your package is installed. Recently I had quote some trouble getting this exactly right but nailed it in the end. So here's a sample to share with google so I can find it later ;) This sample adds a target that runs after the AfterBuild target: The Get-Project and Get-MSBuildProject are from the nuget powertools by David Fowlder. (This script is part of the install.ps1 script from a open source project called Weld).

Adding a build target to a project

$project = Get-Project
$buildProject = Get-MSBuildProject
$target = $buildProject.Xml.AddTarget("WeldAfterbuild")
$target.AfterTargets = "AfterBuild"
$task = $target.AddTask("Exec")
$task.SetParameter("Command", "`".\..\packages\Weld.1.0.0\tools\Weld.console`" bin\`$(TargetFileName) `"`$(ProjectDir)\Scripts\Weld`"")
$project.Save() #persists the changes
Notice how the ` (backtick) is used to escape the " and $ characters. This result in the .csproj like this:
<Target Name="WeldAfterbuild" AfterTargets="AfterBuild">
<Exec Command="&quot;.\..\packages\Weld.1.0.0\tools\Weld.console&quot; bin\$(TargetFileName) &quot;$(ProjectDir)\Scripts\Weld&quot;" />
</Target>
This effectively calls the Weld.Console application passing it the current project .dll name and a target folder.

Removing a build target from a project

In uninstall.ps1 we can remove the same target like this:
$project = Get-Project
$buildProject = Get-MSBuildProject
$projectRoot = $buildProject.Xml;
Foreach ($target in $projectRoot.Targets)
{
If ($target.Name -eq "WeldAfterbuild")
{
$projectRoot.RemoveChild($target);
}
}
$project.Save() #persists the changes
Basically we search for target called "WeldAfterbuild" and then remove that from the project! Easy once you know how :)

Sample MVC 4 application

5. april 2013 10:15 by admin in
This is a sample Asp.NET MVC 4 application for the presentation I gave 5 april 2013 at Hanzehogeschool Groningen. It's created using Visual Studio 2012. To run you also need SqlExpress 2012 or change the connectionstring in web.config to a 'localdb' (for example) to make it work. 


Get it here (50Mb)

Setting up LinqToXSD in Visual Studio 2012

28. maart 2013 20:29 by admin in .net, linqtoxsd, vs2012, linq

Intro


Linq To XSD is a code generation library for accessing xml in a strongly typed manner. Linq to XSD allows you to query and xml file like this:

Offcourse you need a XSD to define the structure of your xml but once you have that the API is much nicer than the general LinqToXML.

Setting it up in Visual Studio


Since it took me way too long and way too much googling to setup LinqToXSD in VS 2012 I thought I'd do 
a HOWTO setup for VS2012. So here's the step by step
  1. Download linqtoxsd from http://linqtoxsd.codeplex.com/ (I used 2.0.2.56002)
  2. Extract the zip to ($SolutionDir)\LinqToXSD
  3. Next unload the project in which you want use LinqToXSD (right click -> Unload Project) and edit the project file (right click->edit myproject.csproj)
  4. Now you have to reference the targets file in the LinqToXSD folder. At the top of the file insert the following line:

     <LinqToXsdBinDir Condition="'$(LinqToXsdBinDir)' == ''">$(SolutionDir)\LinqToXSD\</LinqToXsdBinDir>

    So it looks like this
    5. Finally at the bottom of the project file add   

        <Import Project="$(LinqToXsdBinDir)\LinqToXsd.targets" /> 

        below <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
    6. Reload the project
    7. If all is well you can now change the build action of xsd files in your project like this:

         
    8. Once this is done code is generated which you should be able use immediately. Your xsd/xml has to obey certain restrictions. I included two sample files which should work out of the box here :
 
books.xsd (,92 KB)
books.xml (,93 KB)

Hope this is of some use and happy easter!

Type safer databinding in legacy asp.net forms projects

22. februari 2013 10:56 by admin in .net, vs2010 vs2012
I love compilers. I love ReSharper. And that's why i hate statements like this:

<%# DataBinder.Eval(Container.DataItem,"FirstName") %>
If I was to change the name of the FirstName property or would try to find all references to this property this would not work! In asp.net 4.5 there is a ItemType property on databinding controls which you can use so the dataitem gets a proper type. See http://brijbhushan.net/2012/07/01/strongly-typed-data-controls-and-modal-binding-in-asp-net-4-5-part-1/ for an explanation about this. Unfortunately not all code is asp.net 4.5 and we can not use this feature everywhere. 

In pre asp.net 4.5 projects we can use a different construct. On the container of the databinding control we expose a type-safe version on the current dataitem like this:
public Person CurrentDataItem
{
get { return (Person) Page.GetDataItem(); }
}
Now in our binding control we can use:
 <%# CurrentDataItem.FirstName %>
No strings involved :) See the attached vs2008 sample project for an example.

TypeSafeBindingExample.zip (27,75 KB)

Pinchzoom Image with Adobe Air

24. december 2012 10:06 by admin in actionscript, air, pinchzoom, image
For a recent project I needed to create an image view with pinchzoom similar to the gallery application on iOS. To my surprise this was not very trivial and online resources were limited. Hence this sample project. I use the touchbegin,touchmove,touchmove events to keep track of the users fingers. Because touchend is not always fired I also require a touch to be 'seen' every X milliseconds. Otherwise I remove it from my touchpoints administration. 

The code is based on the idea the location in 'image coordinates' below a users finger should remain the same while moving. If the user moves a finger we need to move/scale the image so that it snaps to the users finger. You can think of it like this

Ps=Pi*S + Poffset

This means that the screen position Ps is equal to image postion Pmultiplied by the scale S and added to an offset. We determine the new scale by looking at the distance between the two fingers. The new scale is newDistance/oldDistance. If the distance between the fingers increases the scale increases. Now that we know Ps,Pi and S we can calculate Poffset.

The core of the algorithm is in the touchmove event. This is the starting point for understanding the code. You can also just use the component like a normal image and set the MaxZoom to specifiy a maximal zoom level. Like this:
<components:PinchZoomImage width="100%" height="100%" source="@Embed('/assets/high.jpg')" MaxZoom="5" />

I added a sample project in zip file pinchzoom.zip (1,73 MB) as well.
The pinchzoomimage code:
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark" clipAndEnableScrolling="true" 
creationComplete="creationCompleteHandler(event)" touchBegin="container_touchBeginHandler(event)"
 touchEnd="container_touchEndHandler(event)" touchMove="container_touchMoveHandler(event)" >
    
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.events.FlexEvent;
            
            import components.TouchPoint;
            
            private var startImageX : Number;
            private var startImageY : Number;
            private var touchIsDown : Boolean;
            
            private var startX : Number;
            private var startY : Number;
            
            //dont' update on every move            
            private var SkipCount : Number = 0;            
            
            [Bindable]
            public var source: Object;
            
            private const Margin : Number =10; 
            private var lastX : Number;
            private var lastY : Number;
            private var ImageIsWide : Boolean;
            
            
            public var MaxZoom : Number = 1.5;
            private var maxScale : Number;
            
            private var TouchPoints : ArrayCollection = new ArrayCollection();
            
            protected function creationCompleteHandler(event:FlexEvent):void
            {
                flash.ui.Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;        
                
                var scale: Number =Math.min(width / image.width,height / image.height);
                image.scaleX = image.scaleY = scale;
                
                ImageIsWide = (image.width / image.height) > (width / height);
                
                if (ImageIsWide)
                {
                    image.y = (height -image.height*image.scaleY ) /2 ;
                }
                else
                {
                    image.x = (width -image.width*image.scaleX ) /2 ;
                }
                
                maxScale = scale*MaxZoom;
            }        
            
            protected function container_touchBeginHandler(event:TouchEvent):void
            {
                trace("down");
                // TODO Auto-generated method stub                
                TouchPoints.addItem(new TouchPoint(event.touchPointID,event.stageX,event.stageY));
            }    
            
            protected function container_touchEndHandler(event:TouchEvent):void
            {
                trace("up");
                // TODO Auto-generated method stub                
                var p = GetTouchPointById(event.touchPointID);
                if (p != null)
                {
                    var idx : int = TouchPoints.getItemIndex(p);
                    TouchPoints.removeItemAt(idx);    
                }
                
            }
            private function GetTouchPointById(id : int) : TouchPoint
            {
                for each (var p:TouchPoint in TouchPoints)
                {
                    if (p.Id == id)
                    {
                        return p;
                    }
                }
                return null;
            }
            
            private function SetImageWithinBounds(minX : Number,maxX : Number,minY : Number,maxY : Number)
            {
                image.x = Math.min(Math.max(image.x,minX),maxX);
                image.y = Math.min(Math.max(image.y,minY),maxY);
            }
            
            private function FitImageToScreen():void 
            {
                if (ImageIsWide)
                {
                    //make sure the image is not smaller  than te container
                    if (image.width*image.scaleX < width)
                    {
                        image.scaleX = image.scaleY =  width / image.width;
                        image.x = 0;
                    }
                    
                    var maxX : Number = 0;
                    var minX : Number = width - (image.width * image.scaleX);
                    var minY = (height -image.height*image.scaleY ) ;
                    var maxY = Math.max(0,(height -image.height*image.scaleY ) /2 );
                    
                    SetImageWithinBounds(minX,maxX,minY,maxY);
                    
                }
                else //high image
                {
                    //make sure the image is not smaller  than te container
                    if (image.height*image.scaleY < height)
                    {
                        image.scaleX = image.scaleY =  height/ image.height;
                        image.y = 0;
                    }
                    
                    var maxY : Number = 0;
                    var minY  : Number = height- (image.height* image.scaleY);
                    
                    var minX = (width -image.width*image.scaleX ) ;
                    var maxX = Math.max(0,(width-image.width*image.scaleX ) /2 );
                    
                    SetImageWithinBounds(minX,maxX,minY,maxY);
                }
                
            }
            
            private function UpdateTouchPoints(event:TouchEvent):void
            {
                //update point                
                var tp : TouchPoint = GetTouchPointById(event.touchPointID);
                if (tp == null)
                {
                    return; 
                }
                tp.CurrentX = event.stageX;
                tp.CurrentY = event.stageY;
                var now : Date = new Date();
                tp.LastTouchTime = now;
                
                //remove old points 
                for each (var tp : TouchPointin TouchPoints) 
                {
                    if ((now.getTime() - tp.LastTouchTime.getTime()) > 1000) 
                    {
                        var idx : int = TouchPoints.getItemIndex(tp);
                        TouchPoints.removeItemAt(idx);    
                    }
                }    
                
            }
            protected function container_touchMoveHandler(event:TouchEvent):void
            {
                SkipCount++;
                
                if (SkipCount < 3)
                {
                    return ;
                }
                SkipCount = 0;
                
                trace("move");
                
                UpdateTouchPoints(event);
                
                
                if (TouchPoints.length == 2) //zoom + move
                {
                    var p1  : TouchPoint = TouchPoints[0];
                    var p2  : TouchPoint = TouchPoints[1];
                    var scale :Number = p1.CurrentDistance(p2)  / p1.PreviousDistance(p2);
                    
                    //no more than max
                    scale = Math.min(maxScale/image.scaleX ,scale);
                    
                    //find image coordinate based on previous situation
var imageX : Number = (p1.PreviousX - image.x) / image.scaleX;
var imageY : Number = (p1.PreviousY - image.y) / image.scaleY;
//update scale
image.scaleX *= scale;
image.scaleY *= scale;
//update offset
var offsetX : Number = p1.CurrentX - image.scaleX*imageX;
var offsetY : Number = p1.CurrentY - image.scaleY*imageY;
image.x = offsetX;
image.y = offsetY;                   
                    
                    p1.UpdatePreviousPosition();
                    p2.UpdatePreviousPosition();
                }
                else if (TouchPoints.length == 1) //just move
                {
                    var p1  : TouchPoint = TouchPoints[0];
                    
                    var offsetX : Number = p1.CurrentX - p1.PreviousX;
                    var offsetY : Number = p1.CurrentY - p1.PreviousY;
                    image.x += offsetX;
                    image.y += offsetY;
                    
                    p1.UpdatePreviousPosition();
                }
                
                FitImageToScreen();                     
            }
            
        ]]>
    </fx:Script>
    
    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
        <s:Rect width="100%" height="100%">
            <s:fill>
                <s:SolidColor color="#000000" />
            </s:fill>
        </s:Rect>
        <s:Image id="image" source="{source}" fillMode="clip" >
            
        </s:Image>    
    
    
</s:Group>


pinchzoom.zip (1,73 MB)

Mixing SEO urls with normal routing in Asp.Net using a custom RouteHandler

1. oktober 2012 20:24 by admin in
On a project I was working on we would like to have URLs like

www.thesite.com/greatproduct

Since this was a MVC 3 site the normal routing like this should work as well.

www.thesite.com/product/details/4

To make this work I was inspired bu the article of Lars-Erik Kindblad. In his article he defines a very greedy route that catches all: 

routes.MapRoute("Friendly", "{*FriendlyUrl}").RouteHandler = new FriendlyUrlRouteHandler();


This breaks the default MVC route defined like this

routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new {controller = "Product", action = "Index", id = UrlParameter.Optional},
                new[] {"thesite.Web.Controllers"} // Parameter defaults
                );

Since both routes are catch all mixing them was not an option. But what about override the functionality of the default route handler? This is very easy. Basically by subclassing MvcRouteHandler we can add custom routing as well :) My custom routehandler does a lookup in the product table to find a product of that name and then show the details for that product. If the product name is not found the normal functionality is 'restored'. Also I do a check to see if the name is not a controller name. So the url www.thesite.com/product still maps to the index method of my product controller even if some product's name is 'product'.
     public class FriendlyUrlRouteHandler : System.Web.Mvc.MvcRouteHandler
{
private static IList<string> controllerNames;private static IList<string> ControllerNames
{
get
{
if (controllerNames == null)
{
controllerNames = Assembly.GetExecutingAssembly().GetTypes().
Where(t => typeof(Controller).IsAssignableFrom(t)).
Select(c=>c.Name.Replace("Controller","")).
ToList();
}
return controllerNames;
}
}
protected override IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
{
var friendlyUrl = (string)requestContext.RouteData.Values["controller"];
var firstPart = friendlyUrl.Contains("/")? 
friendlyUrl.Split('/')[0] : 
friendlyUrl;//it's a controller..handle normally
if (ControllerNames.Contains(firstPart))
{
return base.GetHttpHandler(requestContext);
}
if (!string.IsNullOrEmpty(friendlyUrl))
{
using (var ctx = new SiteDbContext())
{
                    var product = ctx.Events.FirstOrDefault(p => p.Title == friendlyUrl);
 if (product != null)
{
requestContext.RouteData.Values["controller"] = "product";
requestContext.RouteData.Values["action"] = "details";
requestContext.RouteData.Values["id"] = product.Id;
}
}
}
return base.GetHttpHandler(requestContext);
}
}

Closing all sql connections from Solution Explorer.

27. september 2012 17:21 by admin in .net, vs2010 vs2012
In my development work I get the following message quite a lot : Cannot drop database "XXX" because it is currently in use. This usually means I have an existing website or tool with a connection to the database I want to drop. Especially with Entity Framework Code-First I tend to rewrite the whole DB quite often. Instead of killing the 'guilty' process I decided to create a VS shortcut to deal with it. So here's what I have now:


What does this do?

  1. Look for a App.Config or Web.Config of the selected project
  2. Look for connection strings in the configuration file
  3. Use the first connection string and try to connect to the corresponding master db
  4. Close existing connections to the database specified in 3

So HOW does it work?

For this purpose i created a small console application and integrated it into my Visual Studio as an external command. 

The application (source code) is included as a zip file here: connection-killer.zip (211,17 KB)
This consists of a VS2012 solution but it should be easy to open it in VS2010 as nothing special is done. (For VS2010 just import the .cs files into a 'fresh' project) The heart of the application is the following:

Basically switching between SINGLE_USER and MULTI_USER closes all active connections. 

Next (and final) step is to integrate the program into vs2012. The steps are the same on VS2010 and afaik VS2008. Here's how:
1 Add the program as external tool
Via Tools->External tools click add. Point to the point where you have connection-killer exe file and change the initial directory of the application. Move connection killer up so it is the first external tool (you'll see why later). It should look like this:


2 Create a short in the Solution Explorer context menu
  1. Go Tools->Customize and click the Commands tab. 
  2. Click the context menu 'Project and Solution Context Menus | Project'
  3. Add command select category 'tools' and select command 'External Command 1'
  4. Click 'Modify Selection' and rename the menu item to kill connection or something
  5. Close the dialog and you're done

Packages needed for mvc 4 and scaffolding.

27. september 2012 14:56 by admin in
Here's my packages folder after I added a MVC site and installed mvc-scaffolding. 

I agree with the lego strategy of Asp.Net but isn't this overkill? Added the version specific dependencies and the fact that packages don't get uninstalled if no longer needed and things get really messy quickly.