Thursday, March 12, 2015

Kendo UI Grid Server Side Paging

I recently did some project into Kendo UI so here I sharing my experience that I have regarding to Kendo UI.
So here I going to writing useful notes for those who want to do server side paging in Kendo UI Grid. Lets begin first from client side.
Below you can see js code for Kendo Grid binding in JS.

            $("#UserGrid").kendoGrid({
                dataSource: {
                    transport: {
                        read: "<%=ResolveUrl("/api/KendoData/GetJsonData")%>"
                    },
                    pageSize: 5,
                    serverPaging: true,
                    schema: {
                        data: "data",
                        total: "total"
                    }
                },
                height: 200,
                groupable: true,
                sortable: true,
                pageable: true,
            });

Copy below code and paste into your default.aspx or wherever you want into your page. Change the div Id as per your requirement.

VB.net

Imports System.Net
Imports System.Web.Http
Imports System.Collections
Imports Newtonsoft.Json
Imports System.Net.Http
Imports Newtonsoft.Json.Linq
Public Class KendoDataController
    Inherits ApiController
    <HttpGet>
    Public Function GetJsonData(take As Integer, skip As Integer, page As Integer, pageSize As Integer) As JToken
        If (skip <> Nothing And take <> Nothing) Then
            Return JObject.FromObject(New With {.total = 9, .data = Context.Users().Skip(skip).Take(take)})
        Else
            Return JObject.FromObject(New With {.total = 9, .data = Context.Users().Skip(0).Take(pageSize)})
        End If
    End Function
End Class

C#

[HttpGet]
Public  JToken GetJsonData(int take, int skip, page int, int pageSize){
If(skip!=null && take !=null)
      Return JObject.FromObject(New {.total = 9, .data = Context.Users().Skip(skip).Take(take)});
else
  Return JObject.FromObject(New {.total = 9, .data = Context.Users()});
}

When you are going to create API controller in Asp.net then don't forget to configure route setting for API controller in global.asax.
Here is code for setting API controller in global.asax, this code should be call into Application_start method.

Dim config = GlobalConfiguration.Configuration
        config.Routes.MapHttpRoute("ActionApi", "api/{controller}/{action}/{id}", New With {.Id = RouteParameter.Optional})
        config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", New With {.Id = RouteParameter.Optional})

The code written into vb.net so if someone need into C# then please convert it into C# code format from online code converter tools.

Grid paging work flow :
Kendo grid provide a useful way to do server side paging, you just need to configure server side page setting in Kendo grid. As you see in above Grid binding js code where I enable serverPaging:true and setup schema which says to grid in which format Grid receive a data from server side (Api Controller).

Programmer don't need to care about page settings related logic because it handle at client side in Kendo grid. Paging related settings are receive at server side like Skip, Take, Page, Page Size. So here what I did into API controller, I just receive paging parameter which was requested from client side and apply those parameter into fetching records.

If you want more trace on URL which was generated after changing page into Kendo Grid, for that just do right click on page and select Inspect element there you can see Network tab and there you will see all requested trace URLs which was made from this page. For example you can see below screen shots for more information.


Saturday, July 12, 2014

Angular JS and signalR Based Chat App

Hello friends! Here I’m writing useful blog for those programmers who are going to start learning Angular JS, and also for those who want make chat application using SignalR.
So here I'm creating a sample chat application using bootstrap, SignalR and Angular JS in .net framework 4.0.
Here I’m going to explain some part of this chat application. Let start from creating SignalR hub class which is play vital role for handling bi-directional connection between server to client and client to server.


Hub class




using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
namespace AngularChatApp.ChatController
{
    public class Chat : Hub, IChat
    {
        private static List<User> userCollection = new List<User>();
        private static List<MapRoomUser> mapRoomUserCollection = new List<MapRoomUser>();
        private static List<Message> msgCollection = new List<Message>();

        public void EnterRoom(string userName, string roomId)
        {
            var users = userCollection.Where(s => s.UserName == userName);
            if (users.Count() == 0)
                userCollection.Add(new User() { UserName = userName, ConnectionId = new string[] { Context.ConnectionId } });
            else
                users.FirstOrDefault().ConnectionId = new string[] { Context.ConnectionId };
            if (mapRoomUserCollection.Where(s => s.user.UserName == userName && s.roomId == s.roomId).Count() == 0)
                mapRoomUserCollection.Add(new MapRoomUser() { user = new User() { UserName = userName }, roomId = roomId });
            Groups.Add(Context.ConnectionId, roomId);
            LoadChatHistory(roomId, userName);
        }

        public void SendRoomMessage(string userName, string roomId, string message)
        {
            var msg = new Message() { SendUser = userName, RoomId = roomId, MessageId = Guid.NewGuid().ToString(), Text = message };
            msgCollection.Add(msg);
            Clients.Group(roomId).getRoomMessage(msg);
        }

        public void LeaveRoom(string userName, string roomId)
        {
            mapRoomUserCollection.Remove(mapRoomUserCollection.Where(s => s.user.UserName == userName && s.roomId == roomId).FirstOrDefault());
        }

        public void LoadChatHistory(string roomId, string userName)
        {
            var messages = msgCollection.Where(s => s.RoomId == roomId);
            Clients.Client(Context.ConnectionId).showChatHistory(messages);
        }
    }
}

ng-view Container

After creating chat hub class, lets come on view side of chat application. Here we need a page where we bind ng-view for displaying room list, chat history at client side. For this I added a chat.aspx page and mention ng-view attribute into the div element. We also need to mention app name which is required for route and controller configuration.


Chat.aspx

 <div ng-app="ChatApp">
        <div ng-view>
        </div>
 </div>

After mention ng-app and ng-view. Now, lets create the config js for configuration of angular route and controller. A controller is for handling view of room list and chat  history, and factory has all client side method of signalR.


Config.js

var app = angular.module("ChatApp", ['ngRoute']);
app.config(function ($routeProvider) {
    $routeProvider
    .when('/', {
        controller: 'Rooms',
        templateUrl: 'Template/Rooms.htm'
    })
    .otherwise({
        redirectTo: '/'
    });
});

Factory.js

app.factory("RoomFactory", function () {
    var obj = {
        RoomId: 0,
        Rooms: [{ UnReadMsgCount: 0, RoomName: "Room1", RoomId: 1 },
                    { UnReadMsgCount: 0, RoomName: "Room2", RoomId: 2 },
                    { UnReadMsgCount: 0, RoomName: "Room3", RoomId: 3 },
                    { UnReadMsgCount: 0, RoomName: "Room4", RoomId: 4 },
                    { UnReadMsgCount: 0, RoomName: "Room5", RoomId: 5 },
                    { UnReadMsgCount: 0, RoomName: "Room6", RoomId: 6}]
    }

    
    return obj;
});

app.factory("signalR", function () {
    var $hub = $.connection.chat;
    var signalR = {
        startHub: function () {
            $.connection.hub.start();
        },
        EnterRoom: function (username, roomid) {
            $hub.server.enterRoom(username, roomid);
        },
        SendRoomMessage: function (userName, roomId, message) {
            $hub.server.sendRoomMessage(userName, roomId, message);
        },
        GetRoomMessage: function (callback) {
            $hub.client.getRoomMessage = callback;
        },
        RequestChatHistory: function (roomId, userName) {
            $hub.server.loadChatHistory(roomId, userName);
        },
        GetChatHistory: function (callback) {
            $hub.client.showChatHistory = callback;
        }
    }
    return signalR;
});

Contoller.js

app.controller("Rooms", function ($scope, RoomFactory, signalR) {
    $scope.$parent.UserName = "";
    $scope.rooms = RoomFactory.Rooms;
    $scope.$parent.UserName = prompt("Enter unique name :");
    $scope.chatHistory = [];
    signalR.startHub();
    $scope.typemsgdisable = true;
    $scope.openChatPanel = function (RoomId, RoomName) {
        //$scope.templateURL = "/Template/ChatPanel.htm";
        RoomFactory.RoomId = RoomId;
        $scope.RoomId = RoomId;
        $scope.RoomName = RoomName;
        $scope.chatHistory = [];
        signalR.EnterRoom($scope.$parent.UserName, $scope.RoomId);
        $scope.typemsgdisable = false;
        //Check this for each function
        angular.forEach($scope.rooms, function (room, key) {
            if ($scope.RoomId == room.RoomId) {
                room.UnReadMsgCount = 0;
            }
        });
        $scope.$apply();
    };
    $scope.sendMsgOnEnter = function ($event) {
        if ($event.keyCode == 13) {
            $scope.sendMessage();
            $event.preventDefault();
        }
    }
    $scope.sendMessage = function () {
        signalR.SendRoomMessage($scope.$parent.UserName, $scope.RoomId, $scope.typeMessage);
        $scope.typeMessage = "";
    };
    signalR.GetRoomMessage(function (message) {
        if (message.RoomId == $scope.RoomId) {
            $scope.chatHistory.push(message);
            $scope.$apply();
        }
        else {
           
            angular.forEach($scope.rooms, function (room,key) {
                if (message.RoomId == room.RoomId) {
                    room.UnReadMsgCount = room.UnReadMsgCount + 1;
                }
            });
            $scope.$apply();
        }
    });
    signalR.GetChatHistory(function (messages) {
        $scope.chatHistory = messages;
        $scope.$apply();
    });
});

And Last one is Templates.

Rooms.html


<div class="container theme-showcase">
    <div class="jumbotron-custom">
        <div style="text-align: center">
            <h2>
                User Name : {{UserName}}
            </h2>
        </div>
        <div class="row">
            <div class="col-md-3">
                <ul class="list-group">
                    <li class="list-group-item" ng-repeat="room in rooms" ng-click="openChatPanel(room.RoomId,room.RoomName);">
                        <span class="badge">{{room.UnReadMsgCount}}</span> {{room.RoomName}} </li>
                </ul>
            </div>
            <div class="col-md-8">
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h3 class="panel-title">
                            {{RoomName}}</h3>
                    </div>
                    <div class="panel-body" style="height: 500px">
                        <!--<table class="table">
                            <thead>
                                <tr>
                                    <th>
                                        Sender User
                                    </th>
                                    <th>
                                        Message
                                    </th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr ng-repeat="chat in chatHistory">
                                    <td>
                                        {{chat.SendUser}}
                                    </td>
                                    <td>
                                        {{chat.Text}}
                                    </td>
                                </tr>
                            </tbody>
                        </table>-->
                        <div ng-repeat="chat in chatHistory">
                            <div class="userName">
                                {{chat.SendUser}}</div>
                            <div class="message ">
                                <div class="message-inner">
                                    {{chat.Text}}</div>
                            </div>
                        </div>
                    </div>
                    <div class="input-group">
                        <input id="txtMessage" type="text" class="form-control" ng-model="typeMessage" ng-keypress="sendMsgOnEnter($event)"
                            ng-disabled="typemsgdisable" />
                        <span class="input-group-btn">
                            <button id="btnsend" class="btn btn-default" type="button" ng-click="sendMessage();"
                                ng-disabled="typemsgdisable">
                                Send</button>
                        </span>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

After Complete all the things your app will look be like as below.


Click Here for get the source code.

NuGet Information:

Angular Nuget Command : PM> Install-Package angularjs -Version 1.2.19
BootStrap Nuget Command : PM> Install-Package bootstrap
SignalR Nuget Command : PM> Install-Package bootstrap


Note:  This is my first blog of my life. I'm not good at English, so please take care of this.