Specializations

Showing posts with label MVC. Show all posts
Showing posts with label MVC. Show all posts

Tuesday, March 4, 2014

ASP.NET MVC and KnockoutJS

In our Getting Started with KnockoutJS in ASP.NET MVC article, we started off with the intention of weaning web client devs away from hacking up the DOM and using client side ViewModels with Knockout as much as possible. We got some good questions regarding the article of which the main ones are:
1. Why do we have to get the empty View using the Get Action method and then do a second HTTP Get using AJAX after Document load to get the actual data? We’ll see one of the ways to avoid the second Get.
2. Why are we using jQuery’s $(element).on(…) to assign click handlers instead of having the click handler functions in the ViewModel itself. Well we can, so we’ll see how to do so.
3. Why did we disable AntiForgeryToken? Do we really need to make our code ‘insecure’ to use JavaScript based clients? Nope, we don’t have to make our code ‘insecure’, we’ll see how we can put the AntiForgeryToken back and use it to validate input.
Finally we’ll see how we can avoid manual mapping between the Server side ViewModel and Client Side ViewModel.
We start off with the code from the first article so you can download the code or fork the code on GithubThis article has been written by Sumit Maitra and I. 

Avoid doing a second AJAX GET to get Data as JSON

On way to send data to Client as JSON from the server is to serialize the Data as a JSON string, stick it in a ViewModel property and bind it to an HTML element (like a Hidden Field) or use Razor syntax to include the data in a Hidden field directly.
We’ll use the second technique today.

Changes in LookupsController

We update the Index action method to pass the list of Lookups into the ViewResult.
public ActionResult Index()
{
    return View(db.Lookups.ToList());
}
Just to ensure that we are not calling old code by mistake, we’ll comment out the GetIndex Action method too.

Updating the Index View

We put back the Model declaration on top of the View and add the Hidden Input variable that will save the JSON serialized Model.
@model IEnumerable<KnockoutSamples.Models.Lookup><title>Index</title>
<h2>Index</h2>
<input type="hidden" id="serverJSON"
value="@Newtonsoft.Json.JsonConvert.SerializeObject(Model)" />
<!-- rest of the markup -->
If you went through the first article carefully, you’ll realize this works because all Razor syntax is evaluated on the server when generating final HTML markup that’s sent back to the Browser. So here the @Newtonsoft.Json.JsonConvert.SerializeObject will be evaluated on the server for the data that we passed into the View(…) function in the Index Action method. So value of the hidden field will essentially end up with a long JSON string.

Updating the JavaScript to use the Hidden Field as the Data Source

We update the $(document).ready function to retrieve the data object from the Hidden Field instead of a AJAX call to the server. I’ve kept the code that we remove as commented and highlighted in gray. The code to convert the JSON string to JS object is highlighted in Yellow. Note the rest of the code remains the same.
$(document).ready(function () {
 //$.ajax({
//    type: "GET",
//    url: "/Lookups/GetIndex",
//}).done(function (data) {

var data = JSON.parse($("#serverJSON").val());$(data).each(function (index, element) {
  var mappedItem =
  {
   Id: ko.observable(element.Id),
   Key: ko.observable(element.Key),
   Value: ko.observable(element.Value),
   Mode: ko.observable("display")
  };
  viewModel.lookupCollection.push(mappedItem);
});
ko.applyBindings(viewModel);
 //}).error(function (ex) {
//    alert("Error");
//});

//… Rest of the code
}
With that we are all done, if we run the application now, we’ll see the three default items come up in the Index.
If you run F12 dev tools, you’ll see that there is only one AJAX Get that’s made by Visual Studio’s browser link tech by the injected SignalR code.
knockout-ajax-get-server-side

Handling Edit, Update, Delete in ViewModel functions rather than external Event handlers

There were some protestations on why were we using jQuery ‘On’ function to attach Click event handlers for Edit, Delete etc. and it was suggested that we add the functions to the View Model and be done with it.
To Use KO View Model functions, we need to declare two more functions in the ViewModel. As you can see below, we’ve added two functions Edit and Update. KO automatically passes the data in current context, so we don’t have to extract it using ko.dataFor. The rest of the implementation is copied over from the older event handler.
$(data).each(function (index, element) {
var mappedItem =
{
  Id: ko.observable(element.Id),
  Key: ko.observable(element.Key),
  Value: ko.observable(element.Value),
  Mode: ko.observable("display"),
  Edit: function (current) {
   //var current = ko.dataFor(this);
   current.Mode("edit");
  },
  Update: function (current) {
   //var current = ko.dataFor(this);
   saveData(current);
   current.Mode("display");
  }
};
viewModel.lookupCollection.push(mappedItem);
});

Binding the Button Click handlers

We now have functions to handle the events but we need to assign them to the respective button’s click events. Since the new methods are a part of the View Model, we’ll use KO’s click binding in the markup.
The Edit Button:
<button class="btn btn-success kout-edit" data-bind="click: Edit">Edit</button>
The Update Button:
<button class="btn btn-success kout-update" data-bind="click: Update">Update</button>
If you run the app now, things will work as before. Pretty neat and doesn’t seem to be a troublemaker, so let’s keep it as is and go ahead!

Getting the Anti Forgery token back

We have covered what Anti Forgery tokens are and how they help prevent CSRF attacks here. We also saw how to use it in Web API services. So lets see how we can continue using it in our KO based app.
1. First we restore the AntiForgeryToken Razor syntax in the Index.cshtml. We add the following at the top of the page just below the @model declaration.
@Html.AntiForgeryToken()
This simply adds a Hidden field to the final HTML page.
2. Next we enable the Token Verification on the Controller method, so we uncomment the highlighted line below in the LookupsController
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Lookup lookup)
{
if (ModelState.IsValid)
{
  db.Entry(lookup).State = EntityState.Modified;
  db.SaveChanges();
  return Json(lookup.Id);
}
return View(lookup);
}
3. If we try submitting now, we’ll get the AntiForgeryToken validation failed error. So finally, we update the saveData function in the knockout.samples.js. We make three simple changes:
a. Add the __RequestVerificationToken to the JS object that we are submitting on Save. The property name is so because that’s what MVC looks for in the submitted form and that also happens to be the name of the hidden field in which it is stored.
b. Change contentType to from-url-encoded
c. And finally since we are sending a url-encoded form, so we no longer JSON.stringify submitData and send the JavaScript object instead
function saveData(currentData) {
var postUrl = "";
var submitData = {
  Id: currentData.Id(),
  Key: currentData.Key(),
  Value: currentData.Value(),
  __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val()
};
if (currentData.Id && currentData.Id() > 0) {
  postUrl = "/Lookups/Edit";
}
else {
  postUrl = "/Lookups/Create";
}
$.ajax({
  type: "POST",
  contentType: "application/x-www-form-urlencoded",
  url: postUrl,
  data: submitData
}).done(function (id) {
  currentData.Id(id);
}).error(function (ex) {
  alert("ERROR Saving");
})
}
Okay, that’s three different questions solved and a different perspective towards using KO achieved.

Conclusion

Today we revisited some of the questions that rose in our previous article and explored some alternate techniques when using Knockout JS and ASP.NET MVC. We also saw how we could secure our application using the AntiForgery Token that we had ignored previously. In the next part of the series, we’ll step it up and learn more techniques using Knockout JS in near production scenarios.

MVC FAQs 3

So how do we implement bundling in MVC?

Open BundleConfig.cs from the App_Start folder.
In BundleConfig.cs, add the JS files you want bundle into a single entity in to the bundles collection. In the below code we are combining all the javascript JS files which exist in the Scripts folder as a single unit in to the bundle collection.
bundles.Add(new ScriptBundle("~/Scripts/MyScripts").Include(
"~/Scripts/*.js")); 
Below is how your BundleConfig.cs file will look like:
public  class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.Add(new ScriptBundle("~/Scripts/MyScripts").Include(
           "~/Scripts/*.js"));
        BundleTable.EnableOptimizations = true;
    }
}
Once you have combined your scripts into one single unit we then to include all the JS files into the view using the below code. The below code needs to be put in the ASPX or Razor view.
<%= Scripts.Render("~/Scripts/MyScripts")  %>
If you now see your page requests you would see that script request is combined into one request.

How can you test bundling in debug mode?

If you are in a debug mode you need to set EnableOptimizations to true in the bundleconfig.cs file or else you will not see the bundling effect in the page requests.
BundleTable.EnableOptimizations = true;

Explain minification and how to implement it

Minification reduces the size of script and CSS files by removing blank spaces , comments etc. For example below is a simple javascript code with comments.
// This is test
var x = 0;
x = x + 1;
x = x * 2;
After implementing minification the JavaScript code looks like below. You can see how whitespaces and comments are removed to minimize file size, thus increasing performance.
var x=0;x=x+1;x=x*2;

How do we implement minification?

When you implement bundling, minification is implemented by itself. In other words the steps to implement bundling and minification are the same.  

Explain Areas in MVC?

Areas help you to group functionalities in to independent modules thus making your project more organized. For example in the below MVC project we have four controller classes and as time passes by if more controller classes are added it will be difficult to manage. In bigger projects you will end up with 100’s of controller classes making life hell for maintenance.
 
If we can group controller classes in to logical section like “Invoicing” and “Accounting” that would make life easier and that’s what “Area” are meant to.
You can add an area by right clicking on the MVC solution and clicking on “Area” menu as shown in the below figure.
In the below image we have two “Areas” created “Account” and “Invoicing” and in that I have put the respective controllers. You can see how the project is looking more organized as compared to the previous state. 
 

Explain the concept of View Model in MVC?

A view model is a simple class which represents data to be displayed on the view.
For example below is a simple customermodel object with “CustomerName” and “Amount” property.
CustomerViewModel obj = new CustomerViewModel();
obj.Customer.CustomerName = "Shiv";
obj.Customer.Amount = 1000;
But when this “Customer” model object is displayed on the MVC view it looks something as shown in the below figure. It has “CustomerName” , “Amount” plus “Customer Buying Level” fields on the view / screen. “Customer buying Level” is a color indicationwhich indicates how aggressive the customer is buying.
“Customer buying level” color depends on the value of the “Amount property. If the amount is greater than 2000 then color is red , if amount is greater than 1500 then color is orange or else the color is yellow.
In other words “Customer buying level” is an extra property which is calculated on the basis of amount.
So the Customer viewmodel class has three properties
  • “TxtCustomerName” textbox takes data from “CustomerName” property as it is.
  • “TxtAmount” textbox takes data from “Amount” property of model as it is.
  • “CustomerBuyingLevelColor” displays color value depending on the “Amount “ value.
Customer ModelCustomer ViewModel
CustomerNameTxtCustomerName
AmountTxtAmount
CustomerBuyingLevelColor

What kind of logic view model class will have?

As the name says view model this class has the gel code or connection code which connects the view and the model.
So the view model class can have following kind of logics:-
  • Color transformation logic: - For example you have a “Grade” property in model and you would like your UI to display “red” color for high level grade, “yellow” color for low level grade and “green” color of ok grade.
  • Data format transformation logic :-Your model has a property “Status” with “Married” and “Unmarried” value. In the UI you would like to display it as a checkbox which is checked if “married” and unchecked if “unmarried”.
  • Aggregation logic: -You have two differentCustomer and Address model classes and you have view which displays both “Customer” and “Address” data on one go.
  • Structure downsizing: - You have “Customer” model with “customerCode” and “CustomerName” and you want to display just “CustomerName”. So you can create a wrapper around model and expose the necessary properties.

MVC Faqs

Table of contents

 


Thursday, March 28, 2013

How to create simple MVC 3 application for insert, delete and update functionality.


Contents

Introduction

        Step1:- Create MVC 3 project.
        Step2:- Create Model
        Step3:- Create Controller and Views
        Step3:- Change the Defualt controller value in Global.asax.cs
        Step 4 :- Run your application

Conclusion

Introduction

So In this article I have used all component of MVC (Model, View and controller). I have one database table "categories" containing ID, Name and Description columns. I have made simple mvc application to view, update and delete categories.



Step 1

In this step create a simple MVC application with empty template and razor view engine. please refer screen shot as below
 


Step 2

After create project you find your structure as below

  
As we saw we have _ViewStart.cshtml inside Views folder so that's the startup file we have in project. beside this we have _Layout.cshtml and Error.cshtml inside Views->Shared because we use these two views as shared for all others views.

_Layout.cshtml view we used as master page for other views. So we have Views folder for containing View or html page for GUI purpose. Controller folder for all controller and Models for all Models classes.

As I'm going to create a simple application based on categories table as below
 

So start with writing a Model for this table as 
1. Create a class with name of category inside Models folder with line of codes as 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Insert_Update_Delete_Demo.Models
{
    public class Category
    {
        public int ID { get; set; }
        public String Name { get; set; }
        public String Description { get; set; }
    }
}

We have project name Insert_Update_Delete_Demo and create category class with getter and setter same as table schema.

2. Now we need to create a DBContext class which is going to interaction with database as 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
namespace Insert_Update_Delete_Demo.Models
{
    public class MesDB : DbContext
    {
        public DbSet<Category> Categories { getset; }
    }
}

In this class we have something new firstly we use Namespace System.Data.Entity because DbContext class and DbSet comes from this Namespace. This functionality part of EntityFramework code first approach. A brief about code first approach we create code first in project and its create your database schema when its run first time. This is out of context of this article.

Now we need to create a connectionString with same name as we have class name here "MesDB"

 <connectionStrings>
    <add name="MesDb" connectionString="Data Source=.\sqlexpress;Initial Catalog=MES;Integrated Security=True"
     providerName="System.Data.SqlClient" />
  </connectionStrings>

Finally we are done with Model creation for Categories table.

Step 3

Now add controller as below 

 

I have pick controller name as CategoryController, template I have pick as read/write actions and views using entity framework.

Model class I pick Category class and in Data context class pick the DbContext class. In view type i pick Razor view type. 

as soon as click Add button immediately magic begin and its create following items for me.
1. Controller with name of CategoryController 
2. Create views inside Views->Category folder for Index, Create, Edit, Details and delete functionality.

We done almost just one more thing pending in this... let have look inside Global.asax.cs file we have function for register default route as 

 public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );
        }

So as function shows that default controller should be Home but in our case we have CategoryController only so our Default should be Category so change accordingly 

new { controller = "Category", action = "Index", id = UrlParameter.Optional } // Parameter defaults

ASP.NET MVC Extensions for CSS



Introduction


Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type.

Objective


How to create and use extension for css

Using the code

Step1: Create a project for extension
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Web.Mvc;
 
namespace MyExtensions
{
    public static class CssExtensions
    {
        private static readonly string defaultContentURL = @"http://localhost:50900/Content";
 
        public static MvcHtmlString Css(this HtmlHelper helper, string cssfile)
        {
            return Css(helper, cssfile, null);
        }
 
        public static MvcHtmlString Css(this HtmlHelper helper, string cssfile, string mediaType)
        {
            string cssUrl = defaultContentURL + @"/Css";
            if (String.IsNullOrEmpty(cssfile))
            {
                throw new ArgumentException();
            }
            string src;
            if (IsRelativeToDefaultPath(cssfile))
            {
                src = "~/Content/Css" + cssfile;
            }
            else
            {
                src = string.Format("{0}{1}", (ConfigurationManager.AppSettings["ContentURL"] + @"/Css").Or(cssUrl), cssfile);                
            }
            TagBuilder linkTag = new TagBuilder("link");
            linkTag.MergeAttribute("type""text/css");
            linkTag.MergeAttribute("rel""stylesheet");
            if (mediaType != null)
            {
                linkTag.MergeAttribute("media", mediaType);
            }
            linkTag.MergeAttribute("href"UrlHelper.GenerateContentUrl(src, helper.ViewContext.HttpContext));
            return MvcHtmlString.Create(linkTag.ToString(TagRenderMode.SelfClosing));
        }
 
        internal static bool IsRelativeToDefaultPath(string file)
        {
            return !(file.StartsWith("~"StringComparison.Ordinal) ||
                file.StartsWith("../"StringComparison.Ordinal) ||
                file.StartsWith("/"StringComparison.Ordinal) ||
                file.StartsWith("http://"StringComparison.OrdinalIgnoreCase) ||
                file.StartsWith("https://"StringComparison.OrdinalIgnoreCase));
        }
 
        public static string Or(this string text, string alternateText,
           bool allowEmptyText = falsebool paramCheckAlternateText = true)
        {
            if (paramCheckAlternateText && string.IsNullOrEmpty(alternateText))
                throw new ArgumentNullException("alternateText");
 
            var useAlternate = allowEmptyText ? (text == null) : string.IsNullOrEmpty(text);
            return useAlternate ? alternateText : text;
        }
    }
}
Refer the dll of the above code compiled in your web app
@using MyExtensions
<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    @Html.Css("/Site.css")
</head>
<body>
    <div>
        @RenderBody()
    </div>
</body>
</html>

Output



Happy Implementation

Reference

http://msdn.microsoft.com/en-us/library/bb383977.aspx