2015-12-02

Navigation in a Single page Web application: Sammy.js

,
Single page Web applications are becoming more and more frequent. There are a lot of frameworks/technologies that make the development of these applications a lot easier. You can use JQuery to manipulate your page, use Knockout.js to work the ViewModel way and use WebApi to get your data. All these tools make a fine toolbox to create responsive, single page web applications.
But how about the navigation in these applications? How can this be done in a pluggable, centralized way? You can easily create a JavaScript function on your page that will accept an id of a view that you want to show. This function will then hide all the others views, maybe using JQuery and some sort of animation, and then make the view you requested visible.
 <body>
    <a href="#" onclick="javascript:navigate('page_1')">Show Page 1</a>
    <a href="#" onclick="javascript:navigate('page_2')">Show Page 2</a>

    <div class="page" id="Div1" style="display: none">
        <h1>Page 1</h1>
        Lorem ipsum dolor sit amet, eos augue fierent id. Quo nonumes blandit ei, ut sensibus contentiones per.
        Nam te aliquam salutandi, sit at congue pertinax adversarium, eam putent verear laboramus ad. Ut viderer 
        legimus singulis duo, mel propriae volutpat ad. Mea suscipit gloriatur id, vel cu harum scaevola appetere.
    </div>

    <div class="page" id="Div2" style="display: none">
        <h1>Page 2</h1>
        Lorem ipsum dolor sit amet, eos augue fierent id. Quo nonumes blandit ei, ut sensibus contentiones per. 
        Nam te aliquam salutandi, sit at congue pertinax adversarium, eam putent verear laboramus ad. Ut viderer 
        legimus singulis duo, mel propriae volutpat ad. Mea suscipit gloriatur id, vel cu harum scaevola appetere.
    </div>

    <script type="text/javascript">
        function navigate(viewId) {
            $(".page").hide();

            $("#" + viewId).show("slow");
        }

    </script>
</body>

Now you have a function that is centralized and that actually is responsibly for showing the correct page (view). It acts like an ViewController. I’m not saying that this is a bad way of working, but there is one problem with this solution. The state of witch page was active isn’t maintained. This means that you can’t bookmark a specific page or send it to an external user. This is where Sammy.js comes to the rescue.

Sammy.js


Sammy.js is a small JavaScript framework that enables you to create routes in your page ( looks a lot like routes in MVC ). You can install it using Nuget.
<body>
    <a href="#page_1">Show Page 1</a>
    <a href="#page_2">Show Page 2</a>

    <div class="page" id="page_1" style="display: none">
        <h1>Page 1</h1>
        Lorem ipsum dolor sit amet, eos augue fierent id. Quo nonumes blandit ei, ut sensibus contentiones per.
        Nam te aliquam salutandi, sit at congue pertinax adversarium, eam putent verear laboramus ad. Ut viderer 
        legimus singulis duo, mel propriae volutpat ad. Mea suscipit gloriatur id, vel cu harum scaevola appetere.
    </div>

    <div class="page" id="page_2" style="display: none">
        <h1>Page 2</h1>
        Lorem ipsum dolor sit amet, eos augue fierent id. Quo nonumes blandit ei, ut sensibus contentiones per. 
        Nam te aliquam salutandi, sit at congue pertinax adversarium, eam putent verear laboramus ad. Ut viderer 
        legimus singulis duo, mel propriae volutpat ad. Mea suscipit gloriatur id, vel cu harum scaevola appetere.
    </div>

    <script type="text/javascript">

        $(function () {

            Sammy(function () {
                this.get('#:page', function () {
                    var pageId = this.params.page;
                    navigate(pageId);
                });
            }).run();
        });

        function navigate(viewId) {
            $(".page").hide();

            $("#" + viewId).show("slow");
        }

    </script>

With Sammy.js, i created a route “#:page” where “:page” is actually a parameter. In the links, i removed the onclick attribute and added some href information. When you now click on the link, this information will be added to the url. Sammy.js will see this, and will try to match this to its predefined routes. It will then resolve the parameter from the url and pass it to the navigate function.

The end result is still the same but now the “state” is added to the url so you can bookmark it or send it as a link.

image

The solution can be downloaded here.
Read more →

2014-01-27

I moved

,
Recently i decide to move my blog to my own domain. You can now find me at http://kennytordeur.be

Happy readings ...
Read more →

2012-12-21

Asp.net MVC MEF: Per Request Lifetime

,

Like the title says, i want to use MEF in an Asp.Net MVC application and the lifetime of the object has to be exactly the same as the lifetime of the request. In short, i want 1 single unique object that is recreated per request.

In MEF there is a way to control the lifetime of the created object. This is specified the PartCreationPolicy attribute that you can use to decorate the object. In my test project i installed the nuget package i created in this post to incorporate MEF in an Asp.net MVC application. I also created an object called MyCustomObject with an interface IMyCustomObject. This object has only one property called Created that contains the date when the object is created. In the constructor of that object i have but an thread.sleep. This way i am sure that the Created property will be different for every created object.

 public interface IMyCustomObject
{
DateTime Created { get; set; }
}
 [Export(typeof(IMyCustomObject))]    
public class MyCustomObject : IMyCustomObject
{
public DateTime Created { get; set; }

public MyCustomObject()
{
Created =
DateTime.Now;
System.Threading.
Thread.Sleep(1000);
}
}

I also created an object called MyCustomObjectContainer. This object will contain a property of the type IMyCustomObject.

 [Export]   
public class MyCustomObjectContainer
{
[
Import]
public IMyCustomObject MyCustomObject { get; set; }
}


The controller will have 2 properties. The first of type IMyCustomObject aand the other of type MyCustomContainer. In the action method of the controller, i will write the Created value that is found in those 2 properties to the viewbag. That way i will be sure if the application is using the same object.

    [Export]
[
PartCreationPolicy( CreationPolicy.NonShared)]
public class HomeController : Controller
{
[
Import]
public IMyCustomObject MyCustomObject { get; set; }

[
Import]
public MyCustomObjectContainer MyCustomObjectContainer { get; set; }

public ActionResult Index()
{
this.ViewBag.MyCustomtObjectDateCreated = MyCustomObject.Created;
this.ViewBag.MyCustomObjectContainerDateCreated = MyCustomObjectContainer.MyCustomObject.Created;
return View();
}
}

Choosing the right PartCreationPolicy


In MEF there are 3 different type of creation policies that we can choose. More information can be found here.



  • Shared: the part author is telling MEF that at most one instance of the part may exist per container.
  • NonShared: the part author is telling MEF that each request for exports of the part will be served by a new instance of it.
  • Any or not supplied value: the part author allows the part to be used as either “Shared” or “NonShared”.

The Shared Creation policy


We will set Creation policy to Shared and run the application.


image


 


We see that the same instance of the MyCustomOject is used. But when we refresh the page, we will get exactly the same value, over and over again. So this is not the behavior that we want.


The NonShared Creation Policy


We will set the creation policy to NonShared.


image


With every refresh, we will get a different value for the Created property, but everytime that an IMyCustomObject is asked form the MEF container, a new value is created so this is not a solution for my problem.



The solution


We can create a solution for this problem using the Proxy-pattern, HttpContext and ExportFactory<T>.


The ExportFactory<T> class was introduced in MEF 2. It allows us to create new instances and control the lifetime of those instances. This will be  perfect to create the MyCustomObject object since we need to control the lifetime of this object.


The HttpContext contains Http information about an HttpRequest. There is one property that is very interesting  in our case, the Items property. This property is in fact a dictionary where you can insert objects into. This collection is cleared with every request (perfect). We will use this dictionary to add the created MyCustomObject. So every time that this object is requested, we will look in this dictionary. When it is not found, the ExportFactory<T> will create it and add it to the dictionary.


The proxy pattern will be used to make this a transparent as possible.


image


The Implementation


I’ll create an IItemContainer that has one property Container of type IDictionary. Then i’ll create an HttpContextContainer that will implement this interface. This object will map the Container property to the HttpContext.Items property.

public interface IItemContainer
{
IDictionary Container { get; }
}
[Export(typeof(IItemContainer))]
[
PartCreationPolicy(CreationPolicy.Shared)]
public class HttpContextContainer : MEF_Asp.Net_MVC_Per_Request.Models.IItemContainer
{
public IDictionary Container
{
get
{
return HttpContext.Current.Items;
}
}
}

Next I'll create the proxy object (MyCustomObjectPerRequest). This object will contain the IItemContainer and the Exportfactory<T> instances and implement the IMyCustomObject. This object will be served by the MefContainer when something is request of type IMyCustomObject.

[Export(typeof(IMyCustomObject))]
public class MyCustomObjectPerRequest : IMyCustomObject
{
[
Import]
public ExportFactory<MyCustomObject> Factory { get; set; }

[
Import]
public IItemContainer ItemContainer { get; set; }

private IMyCustomObject MyCustomObject
{
get
{
if (null == ItemContainer.Container["MyCustomObject"])
{
ItemContainer.Container[
"MyCustomObject"] = Factory.CreateExport().Value;
}

return (IMyCustomObject)ItemContainer.Container["MyCustomObject"];
}
}

public DateTime Created
{
get
{
return MyCustomObject.Created;
}
set
{
MyCustomObject.Created =
value;
}
}
}

 


We also need to change the ExportAttribute on the MyCustomObject class so that it doesn’t specify a ContractType.

 [Export] 
public class MyCustomObject : IMyCustomObject

The Result


When we know run the application, we will use the same MyCustomObject object per request. When we refresh, we’ll get an other instance.


image





Conclusion


This solution can also be used to use the same instance per Session or to incorporate a caching mechanism.  All that needs to been done is to implement the IItemsContainer and map the Container property. The Visual Studio solution can be downloaded here.

Read more →

2012-12-16

Asp.net MVC: reuse Areas from external project

,

I created a MVC project that has an Area defined that i would like to use in an other MVC project. Here is the structure.

image

I created a reference between the AlphaArea and MainApp project. When i run the application is see that the area registration of the AlphaArea is executed. But when i try to go to the area i get an error.

image

What this error says, is that the view for the Index of the AlphaController in the Alpha area isn’t found. This makes perfect sense because the Index view isn’t declared in the MainApp project and this is where MVC  tries to find the view. We need to make sure that the view engine can resolve the view.

There are a couple solutions to resolve this. We could copy or create a link in the MainApp to the index view that is defined in the AlphaArea. We would need to copy the whole Area structure. Don’t know about you but I'm not really found of that solution. An other solution is to compile the AlphaArea views in the DLL. This can be done by a Visual Studio extension and a Nuget package.

First you need to install the Razor Generator extension for Visual Studio.

image

This extension will create a .cs file for a view, but in the properties of that view, the Custom Tool needs to be set to “RazorGenerator”.  Otherwise the VS extension will not create a .cs file for that view.

image                                                 image

When we compile the project, the view will be added to the DLL of the AlphaArea project. This isn’t enough. Now we need a way to tell the view engine that the view can be found in the DLL. Luckily, there is a Nuget package that does the trick. You simply need to install the package “RazorGenerator.Mvc” in the AlphaArea project.

image

This package will add a file (RazorGeneratorMvcStart) in the AppStart folder. This file will create a PrecompiledMvcEngine and add it to the ViewEngines. The code will be executed when the applications starts. This is done by using the WebActivator.

using System.Web;
using System.Web.Mvc;
using System.Web.WebPages;
using RazorGenerator.Mvc;

[
assembly: WebActivator.PostApplicationStartMethod(typeof(AlphaArea.App_Start.RazorGeneratorMvcStart), "Start")]

namespace AlphaArea.App_Start {
public static class RazorGeneratorMvcStart {
public static void Start() {
var engine = new PrecompiledMvcEngine(typeof(RazorGeneratorMvcStart).Assembly) {
UsePhysicalViewsIfNewer =
HttpContext.Current.Request.IsLocal
};

ViewEngines.Engines.Insert(0, engine);

// StartPage lookups are done by WebPages.
VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
}
}
}

When we now run the application and go to the Alpha area, the view is resolved.


image


The same system can also be used on Controllers in external projects. The example for the post can be downloaded here.

Read more →

2012-12-12

Web Api: Passing a Complex type in JSON

,

In one project i wanted to pass a complex type to the Post method of an Web Api controller. The Post itself will be done using JQuery in the JSON format. I noticed that the parameter was always null. After a bit of searching i found the solution.

The Set Up

Server side

public class ValuesController : ApiController
{
// POST api/values
public void Post(MyComplexType value)
{
}
}

public class MyComplexType
{
public string Name { get; set; }

public MyComplexSubType MyComplexSubType { get; set; }
}

public class MyComplexSubType
{
public int Age { get; set; }
}

Client Side

 <script type="text/javascript">

function
MyComplexSubType()
{
var self = this;

self.Age = 26;
}

function MyComplexType()
{
var self = this;

self.Name =
"Kenny Tordeur";
self.MyComplexSubType =
new MyComplexSubType();
}


function PostComplexType()
{
$.ajax(
"/api/values", {
data: JSON.stringify(
new MyComplexType()),
contentType:
'application/json',
type:
'POST',
success: SendComplexTypeCallBack
});
}


function SendComplexTypeCallBack(data)
{
alert(
"Complex type sended");
}
</script>

The PostComplexType will be trigged by a click event on a button. It will create a javascript object called MyComplexType. This object will map directly to the object we created on the server side.


 


image


The missing link


With this set-up the parameter will always be null. We need to add a line of code to the global.asax.

ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());

 


Value providers are used by the model binding system in MVC to populate the values of model objects. We basically add a provider that enables to bind a model to a JSON model.  The solution can be downloaded here.

Read more →

2012-12-07

WebApi: File upload and download using JQuery and submit button

,

I am going to create a WebApi service called FileService that can be used to upload and download files. The service will only contain 2 methods. A Post to upload and a Get method that accepts an id parameter to identify the file that needs to be downloaded. Let’s start with the Post method.

The Post method

This method will look in the Request object to see if there are any posted files. If so, it will loop over the files and create them on the server side. The server will return a 201 HttpStatus and a list of strings that will contain the full path of the file(s) at server side. When there are no files posted, the service will return a 401 status a.k.a. BadRequest.

public HttpResponseMessage Post()
{
HttpResponseMessage result = null;
var httpRequest = HttpContext.Current.Request;

// Check if files are available
if (httpRequest.Files.Count > 0)
{
var files = new List<string>();

// interate the files and save on the server
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = HttpContext.Current.Server.MapPath("~/" + postedFile.FileName);
postedFile.SaveAs( filePath);

files.Add(filePath);
}

// return result
result = Request.CreateResponse(HttpStatusCode.Created, files);
}
else
{
// return BadRequest (no file(s) available)
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}

return result;
}

The Get Method


As mentioned before, the Get Method will accept a string file that will identify (= filename) the file that needs to be downloaded.

public HttpResponseMessage Get(string id)
{
HttpResponseMessage result = null;
var localFilePath = HttpContext.Current.Server.MapPath("~/" + id);

// check if parameter is valid
if (String.IsNullOrEmpty(id))
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
// check if file exists on the server
else if (!File.Exists(localFilePath))
{
result = Request.CreateResponse(HttpStatusCode.Gone);
}
else
{// serve the file to the client
result = Request.CreateResponse( HttpStatusCode.OK);
result.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read));
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = id;
}

return result;
}

Uploading a File


Using a submit  button

 <form name="form1" method="post" action="api/file" enctype="multipart/form-data">
<
div>
<
label>
Using submit</label>
<
input name="myFile" type="file" />
</
div>
<
div>
<
input type="submit" value="Submit" />
</
div>
</
form>


Using JQuery

<form enctype="multipart/form-data">
<
label>
Using JQuery</label>
<
input name="file" type="file" />
<
input type="button" id="Upload" value="Upload" />
</
form>
        <script type="text/javascript">
$(function () {
$('#Upload').click(function () {
var formData = new FormData($('form')[0]);
$.ajax({
url: 'api/file',
type: 'POST',
// Form data
data: formData,
//Options to tell JQuery not to process data or worry about content-type
cache: false,
contentType: false,
processData: false
});
});
});
</script>

Downloading a File


image


Summary


The solution can be downloaded here.

Read more →

2012-12-01

Paged Grid with Knockout.js and WebApi

,
I want to see how easily you can create a custom grid that uses an WebApi as datasource and that allows the user to page the data and also allow them to choose a page size for the grid.

The WebApi

The WebApi will return a viewmodel that contains an array of names (string) and a property that specifies how many pages that there are available.
    public class NamesGridViewModel
    {
        public IEnumerable<String> Names { get; set; }

        public int NumberOfPages { get; set; }
    }

The WebApi itself will contain a method that accepts 2 parameters. The parameters will be page (the page that we request) and pagesize (how many entries a page contains). This method will be responsible for calculating how many pages there are and to serve the requested names based on the 2 parametes.
    public class ValuesController : ApiController
    {
        public IList<String> Names
        {
            get { return new List<String> { "Fred", "Barney", "Betty", "Wilma", "Bart", "Lisa", "Maggie", "Homer", "Marge" }; }
        }
            
        public NamesGridViewModel Get(int page, int pagesize)
        {
            return new NamesGridViewModel
                       {
                           // get the request names for the specific page
                           Names = (0 == page? null : Names.Skip((page - 1)*pagesize).Take(pagesize).ToArray())
                           ,
                           // calculated number of pages and ceil the value
                           NumberOfPages = ((int) Math.Ceiling((double) Names.Count/pagesize))
                       };
        }
    }

The client


The client will need a reference to kockout.js. With knockout.js it is possible to apply the MVVM pattern and also work with templates in javascript.


The UI

Page size: <select data-bind="options: availablePageSize, optionsText: $data, value: selectedPageSize"></select><!-- the grid --><table data-bind="with: namesGridViewModel">
    <thead>
        <tr>
            <th>
                Name
            </th>
        </tr>
    </thead>
    <tbody data-bind="foreach: Names">
        <tr>
            <td data-bind="text: $data">
            </td>
        </tr>
    </tbody>
</table><!--Contains the page links--><div id="pager"></div>

The Javascript

<script type="text/javascript">
    // Our  ViewModel.
    function pageViewModel() {
        var self = this;
        self.namesGridViewModel = ko.observable(); // contains the viewmodel returned by the WebApi
        self.selectedPageSize = ko.observable(3); // contains the selected page size, default value is 3
        self.availablePageSize = ko.observableArray([1, 2, 3, 4, 5]); // contains the available page sizes a user can select
        self.selectedPage = ko.observable(1); // contains the selected page

        // Add a click event to all future element with a class "pageIndex". This event will fire
        // when the user clicks a specific page.
        $("#pager").on("click", ".pageIndex", function (event) {
            // set the selected page in the viewModel
            self.selectedPage($(this).text());
        });

        // This function will be used to get the data from our WebApi. The requested page and page size are passed
        // as a parameter. The result will be stored in the namesGridViewModel property. This will cause that the subscribe event
        // for the namesGridViewModel will be fired ==> the page links will be created.
        self.navigate = function () {
            $.get("/api/values?page=" + self.selectedPage() + "&pagesize=" + self.selectedPageSize(), self.namesGridViewModel);
        };

        // Function that will subscribe to all the needed events.
        self.SubscribeToEvents = function () {

            // This event will fire when selectedPageSize is changed.
            self.selectedPageSize.subscribe(function (newValue) {
                self.selectedPage(1);
                self.navigate();
            });

            // This event will be fired when the selectedPage is changed.
            self.selectedPage.subscribe(function (newValue) {
                self.navigate();
            });

            // This event will fire when a new value is defined for the namesGridViewModel.
            // It will create the page links below the grid.
            self.namesGridViewModel.subscribe(function (newValue) {
                var numberOfPages = newValue.NumberOfPages;
                var $pager = $("#pager");
                // clear the pager
                $pager.html("");
                // created the pages the user can click on
                for (var i = 1; i <= numberOfPages; i++) {
                    var link = $('<a class="pageIndex">' + i + '</a>');
                    $pager.append(link);
                }
            }, this);
        };
        
        // This function will be used to kick start everything.
        self.bind = function () {
            self.SubscribeToEvents();
            self.navigate();
            ko.applyBindings(self);
        }
    }
    // Create the viewModel and bind it.
    $(function () { new pageViewModel().bind(); })</script>

The result


image

Summary


You have seen how to create a basic paging grid using Knockout.js.You can easily extend this example to also allow sorting. The solution can be downloaded here.
Read more →