Showing posts with label Data Repository. Show all posts
Showing posts with label Data Repository. Show all posts

Wednesday, August 13, 2014

Singleton Data Repository - Gang of Four Singleton Pattern Simple Sample


In this article we create a singleton Data Repository for MVC. A Singleton class is a class of which only a single instance can exist: is one of the 23 software patterns by the Gang of Four. The Singleton Pattern become really useful in an MVC application, because instead of re-creating the Repository 1) each time a request comes to the MVC app, and 2) also for every different user which browser to the site, it is created ONLY ONE time and kept for the whole lifetime of the MVC application, that means, until the IIS application pool is reset.
First i give you the whole c# code to create a Singleton Data Repository for Asp.Net MVC. It will be  connected to a single XML file , and will be exposing all CRUD operations, using the XDocument class. The basic class will be "Message", and the Repository , "IMessagesRepository". The initial XML file is placed at the end of this post, if you want to use it as bootstrap.
After giving you the Repository code for COPY-PASTE, we'll explain how it works, and we'll compare its behavior with a non-singleton MVC application.

  The whole application can show as follows (i'm using the Twitter Bootstrap: HERE you have a tutorial for installing it in 5 minutes):




This is the code for the Singleton Data Repository. Just COPY-PASTE it in your Models folder and use it inside the Controller: 


namespace RichFormApplication.Models
{

    public class Message
    {
        public int ID { get; set; }
        public string To { get; set; }
        public string Sender { get; set; }
        public string Title { get; set; }
        public string Contents { get; set; }
    }


    public interface IMessagesRepository
    {
        IEnumerable GetAll();
        Message Get(int id);
        Message Add(Message item);
        bool Update(Message item);
        bool Delete(int id);
    }


    public class MessagesRepository : IMessagesRepository
    {
        static private int test;
        private List<Message> Messages = new List<Message>();
        private int iNumberOfMsgs = 1;
        private XDocument doc;

        #region Singleton Init
        private static MessagesRepository _RepositoryInstance = new MessagesRepository();
        public static MessagesRepository RepositoryInstance
        {
            get
            {
                test = 1;
                return _RepositoryInstance;
            }
        }
        #endregion

        private MessagesRepository()
        {
            doc = XDocument.Load(HttpContext.Current.Server.MapPath("~/App_Data/data.xml"));
            foreach (var node in doc.Descendants("note"))
            {
                Messages.Add(new Message
                {
                    ID = Int32.Parse(node.Descendants("id").FirstOrDefault().Value),
                    To = node.Descendants("to").FirstOrDefault().Value,
                    Sender = node.Descendants("from").FirstOrDefault().Value,
                    Title = node.Descendants("heading").FirstOrDefault().Value,
                    Contents = node.Descendants("body").FirstOrDefault().Value
                });
            }

            iNumberOfMsgs = Messages.Count;
        }

        public IEnumerable GetAll()
        {
            return Messages;
        }
        public Message Get(int id)
        {
            return Messages.Find(p => p.ID == id);
        }
        public Message Add(Message item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            item.ID = iNumberOfMsgs++;

            XElement newNode = new XElement("note");
            XElement id = new XElement("id"); id.Value = item.ID.ToString();
            XElement to = new XElement("to"); to.Value = item.To;
            XElement from = new XElement("from"); from.Value = item.Sender;
            XElement Title = new XElement("heading"); Title.Value = item.Title;
            XElement Contents = new XElement("body"); Contents.Value = item.Contents;
            newNode.Add(id, to, from, Title, Contents);
            doc.Root.Add(newNode);
            SaveToXML();
            return item;
        }
        public bool Update(Message item)
        {            
            XElement Message = doc.Descendants("Message").Where(n => Int32.Parse(n.Descendants("id").FirstOrDefault().Value) == item.ID).FirstOrDefault();
            Message.Descendants("to").FirstOrDefault().Value = item.To;
            Message.Descendants("from").FirstOrDefault().Value = item.Sender;
            Message.Descendants("heading").FirstOrDefault().Value = item.Title;
            Message.Descendants("body").FirstOrDefault().Value = item.Contents;
            SaveToXML();
            return true;
        }
        public bool Delete(int id)
        {
            doc.Root.Descendants("note").Where(n => Int32.Parse(n.Descendants("id").First().Value) == id).Remove();
            SaveToXML();
            return true;
        }

        private void SaveToXML()
        {
            doc.Save(HttpContext.Current.Server.MapPath("~/App_Data/data.xml"));
        }
    }
}

Take a look at the red code : the steps for creating the Singleton are:
1) change the "public" for a "private" constructor;
2) declare a "public static" property which returns an INSTANCE of the class
3) that static instance will be created by the .Net CLR runtime , at the private static field containing the
         instance, at the precise instant in which someone calls at least one of the properties or methods
         of the class. The static instance of the class will survive for all lifetime of the MVC application.

To use the Repository just type the following code in the Controller:

        public ActionResult Index()
        {
            return View(MessagesRepository.RepositoryInstance.GetAll());
        }

Now let's test the singleton: browse to the website and put in debugger two breakpoints inside the Repository:


There is no initialization of the Repository , as it is static and its constructor is private.
You'll see that the first time some user browse to the site, the repository is initialized:





Try a second time, refreshing the web page: the repository will not be created again, because it already exists:



Try now as a new user, opening a second session in another browser tab, to see that you keep using the same repository as the first user does.

This is the XML initial file:



<?xml version="1.0" encoding="utf-8"?>
<notes>
  <note>
    <id>0</id>
    <to>Fry</to>
    <from>Leela</from>
    <heading>Reminder</heading>
    <body>Don't forget me this weekend!!!</body>
  </note>
  <note>
    <id>1</id>
    <to>Leela</to>
    <from>Fry</from>
    <heading>Finally!!!</heading>
    <body>Leela, have you asked permission from the Professor?</body>
  </note>
  <note>
    <id>2</id>
    <to>Fry</to>
    <from>Leela</from>
    <heading>Rejection</heading>
    <body>You know what? In second thoughts, i'm going out with Lars this weekend. Sorry...</body>
  </note>

</notes>

That's all concerning to the Singleton Repository.

If you are asking yourself about the XML related code, some relevant points about the XML include:
 We are using the Descendants("") method and the Load() method, for reading the XML file into memory and then inside the List<>.
The Get methods use Find(p => p):


To add a new node, we CREATE an XElement with all its XElement CHILDREN , and then add it to the ROOT (be careful adding them to the root) of the XDocument:




That's all!!  
Happy programming.....
        By Carmel Schvartzman
כתב: כרמל שוורצמן

Wednesday, August 6, 2014

Building Blocks: XML Data Repository for Asp.Net MVC with all CRUD Operations

The following code is the complete C# code to create an XML Data Repository for Asp.Net MVC with all CRUD Operations  , connected to a single XML file , and exposing all CRUD operations, everything using XDocument. The base class is "Note", and the Repository is "INotesRepository". A little XML bootstrap file is at the end of this post.
This code can also be downloaded from the following GitHub repository:
https://github.com/CarmelSoftware/MVCDataRepositoryXML
The whole application can show as follows:
Building Blocks: XML Data Repository for Asp.Net MVC with all CRUD Operations


Just COPY-PASTE it inside your Models folder and initialize it inside some Controller:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Linq;

namespace IoCDependencyInjection.Models
{

public class Note
{
public int ID { get; set; }
public string To { get; set; }
public string From { get; set; }
public string Heading { get; set; }
public string Body { get; set; }
}


public interface INotesRepository
{
IEnumerable
<Note> GetAll();
Note Get(int id);
Note Add(Note item);
bool Update(Note item);
bool Delete(int id);
}


public class NotesRepository : INotesRepository
{
private List
<Note> notes = new List<Note>();
private int iNumberOfEntries = 1;
private XDocument doc;

public NotesRepository()
{
doc = XDocument.Load(HttpContext.Current.Server.MapPath("~/App_Data/data.xml"));
foreach (var node in doc.Descendants("note"))
{
notes.Add(new Note
{
ID = Int32.Parse(node.Descendants("id").FirstOrDefault().Value),
To = node.Descendants("to").FirstOrDefault().Value,
From = node.Descendants("from").FirstOrDefault().Value,
Heading = node.Descendants("heading").FirstOrDefault().Value,
Body = node.Descendants("body").FirstOrDefault().Value
});
}

iNumberOfEntries = notes.Count;
}

public IEnumerable
<Note> GetAll()
{
return notes;
}
public Note Get(int id)
{
return notes.Find(p => p.ID == id);
}
public Note Add(Note item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}

item.ID = iNumberOfEntries++;

XElement newNode = new XElement("note");
XElement id = new XElement("id"); id.Value = item.ID.ToString() ;
XElement to = new XElement("to");to.Value = item.To;
XElement from = new XElement("from"); from.Value = item.From;
XElement heading = new XElement("heading"); heading.Value = item.Heading;
XElement body = new XElement("body"); body.Value = item.Body;
newNode.Add(id, to, from, heading, body);
doc.Root.Add(newNode);
SaveXML();
return item;
}
public bool Update(Note item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
XElement note = doc.Descendants("note").Where(n => Int32.Parse( n.Descendants("id").FirstOrDefault().Value ) == item.ID ).FirstOrDefault();
note.Descendants("to").FirstOrDefault().Value = item.To;
note.Descendants("from").FirstOrDefault().Value = item.From;
note.Descendants("heading").FirstOrDefault().Value = item.Heading;
note.Descendants("body").FirstOrDefault().Value = item.Body;
SaveXML();
return true;
}
public bool Delete(int id)
{
doc.Root.Descendants("note").Where(n => Int32.Parse(n.Descendants("id").First().Value ) == id).Remove() ;
SaveXML();
return true;
}

private void SaveXML()
{
doc.Save(HttpContext.Current.Server.MapPath("~/App_Data/data.xml"));
}
}
}

This is the XML initial file:



<?xml version="1.0" encoding="utf-8"?>
<notes>
  <note>
    <id>0</id>
    <to>Fry</to>
    <from>Leela</from>
    <heading>Reminder</heading>
    <body>Don't forget me this weekend!!!</body>
  </note>
  <note>
    <id>1</id>
    <to>Leela</to>
    <from>Fry</from>
    <heading>Finally!!!</heading>
    <body>Leela, have you asked permission from the Professor?</body>
  </note>
  <note>
    <id>2</id>
    <to>Fry</to>
    <from>Leela</from>
    <heading>Rejection</heading>
    <body>You know what? In second thoughts, i'm going out with Lars this weekend. Sorry...</body>
  </note>

</notes>


Some important points are the XDocument utilization:
Building Blocks: XML Data Repository for Asp.Net MVC with all CRUD Operations 1
 We are using essentially the Descendants("") & the Load() methods, to read the XML document into memory and inside a List<>.
The Get method uses Find(p => p):

XML Data Repository for Asp.Net MVC with all CRUD Operations

To INSERT a new node, we CREATE an XElement with its inner XElement CHILDS , and then add it to the ROOT of the XDocument:

Data Repository for Asp.Net MVC


If you liked the look of this site, learn how to create it using open source CSS templates in this tutorial.

A Generic Data Repository is built step by step in the following Tutorial: http://themvcclub.blogspot.co.il/2014/06/generic-data-Repository-ASP.NET-MVC.html

A GitHub repository containing a Data Repository With Caching can be found here:
https://github.com/CarmelSoftware/Data-Repository-with-Data-Caching-in-ASP.NET-MVC-4

That's all!!  
Happy programming.....
        By Carmel Schvartzman
כתב: כרמל שוורצמן

Tuesday, August 5, 2014

Inversion of Control ( IoC ) Container - Step by step how to add to an MVC Application

In this article we'll see how to add an Inversion of Control ( IoC ) Container to an Asp.Net MVC Application , applying the Dependency Injection pattern.
In this tutorial we'll be using the Unity Application Block (Unity) container . This IoC container will allow us to perform a  dependency injection in our Controller class , in order to achieve a fully decoupled software design of our MVC App.
MVC loosely coupled applications are flexible, easy to test and easier to maintain.
Building loosely coupled applications means minimizing or just nullifying the dependencies between software objects. In our example, our Controller will have not knowledge at all of the Data Repository, and viceversa, and that means that we can in the future alter each one of them with no consequences for the other.The data will be displayed in the View as follows :




The complete documentation for the Unity open source software resides in Codeplex. It also includes a FREE ebook for you to deep in the issue:


When we talk about Inversion of Control we intend to express that instead that we control the data framework instantiating it in our Controllers, THE FRAMEWORK CONTROLS our controllers code by injecting itself into them. We don't initialize the framework, but it is alive and search the controllers in order to inject itself there. Then, when we come to test our MVC, we don't have to access the database because we don't have the framework constructor inside our controllers anymore. We can inject into them any test framework we want.
There are many IoC Containers, such as Castle Windsor, Spring.Net, Ninject and Unity by Microsoft. We are going to use this later.

The complete step by step stages for adding an IoC container to your MVC application are the following:

1) Install the Unity Block container using NuGet
2) Add an Unity Container .cs file (provided by the NuGet package) containing the code to build the container
3) Register your Data Repository type inside that code (in the BuildUnityContainer() method)
4) Setup the IoC Container in the Global.asax (calling the Initialize() method)
5) Inject the dependency in your Controller


1) Install the Dependency Injection Container using NuGet

Open the NuGet Manager and search for "Unity.MVC4", then install the package :


The package includes 2 assemblies and the "Bootstrapper" Container code file:



2) Add an Unity Container .cs file (provided by the NuGet package) containing the code to build the container 

This file is habitually provided in that package , but if don't, just create a .cs file with this code:


namespace IoCDependencyInjection
{
public static class IoC
{
public static IUnityContainer Initialise()
{
var container = BuildUnityContainer();

DependencyResolver.SetResolver(new UnityDependencyResolver(container));

return container;
}

private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();

// register all your components with the container here
// it is NOT necessary to register your controllers

// e.g. container.RegisterType<itestservice testservice="">();
container.RegisterType<INotesRepository, NotesRepository>(); 

RegisterTypes(container);

return container;
}

public static void RegisterTypes(IUnityContainer container)
{

}
}
}


(I changed the class name to "IoC")

3) Register your Data Repository type inside that code (in the BuildUnityContainer() method)

Then uncomment the code lines inside the BuildUnityContainer() method , and insert the Repository Interface and Class types:




// e.g. container.RegisterType<ITestService, TestService>();        container.RegisterType<INotesRepository, NotesRepository>();  

4) Setup the IoC Container in the Global.asax (calling the Initialize() method)





5) Inject the dependency in your Controller






private INotesRepository Repository;
        public IoCTestingController(INotesRepository rep)        {            Repository = rep;        }

That's all respecting to Dependency Injection & Inversion of Control.


Now, in order to finish building the MVC app, we need a Data Repository and a Controller with its Views.
First we'll need a Repository working on an XML file to store the data in, so build it with the code you'll find in this Building Block.

You'll also find there a small XML file to include in your application.

Now for the Controller, these are the methods using the Dependency Injection that we created :

CRUD OPERATIONS : 


CREATE :



RETRIEVE :




UPDATE :



DELETE :






After you finish your application , browse to the Views to see the List, Details, Edit & Delete screens:






If you liked the look of this site, learn how to create it using open source CSS templates in this tutorial.

That's all!!  In this tutorial we've learned how to add an Inversion of Control ( IoC ) Container to an Asp.Net MVC Application , applying the Dependency Injection pattern.
Happy programming.....
        By Carmel Schvartzman
כתב: כרמל שוורצמן

Tuesday, June 3, 2014

Step By Step How to create a Generic Data Repository in ASP.NET MVC 4

         By Carmel Schvartzman

In this tutorial we'll learn how to create a Generic Data Repository in ASP.NET MVC 4. This MVC C# code example can be downloaded from the following GitHub repository:
https://github.com/CarmelSoftware/Generic-Data-Repository-for-ASP.NET-MVC
A Wiki page is here:
https://github.com/CarmelSoftware/Generic-Data-Repository-for-ASP.NET-MVC/wiki
A Data Repository is a class designed to implement the Repository Pattern. This software pattern was designed in order to access, cache in memory and persist in the database the application data.  Thus the repository will support all CRUD operations (Create Retrieve Update Delete) enhancing a clear separation between data domain and database.
There exist Repository implementations with the use of data caching. The caching only stands to avoid unnecessary round trips to the SQL server. But when scalability of the sites is on the stage, may be we don't want to choke our web server's memory. Then, caching is not only redundant, but also dangerous as a waste of the web server resources.
In this tutorial we'll add GENERIC Repository functionality (no caching) to a new ASP.NET MVC 4 app.
That means, our Repository will offer all CRUD functionality, using the same GENERIC methods for all classes.
In successive tutorials, we'll use this Generic Data Repository to build MVC Applications as the following :



Let's say we have an MVC internet application with an Entity Data Model mapped to an SQL server database. This EDM maps just two entities: Blog and Comment:
Generic Data Repository in ASP.NET MVC 4

We'll develop a GENERIC Data Repository which will support ALL model entities in our application.
First, create a new class in the Model folder, name it "Repository", and type the following EDM context instantiation:

Data Repository in ASP.NET MVC 4

 public class DataRepository : IDisposable
    {
        #region Context
        private BlogEntities _Context;
        public BlogEntities Context
        {
            get
            {
                if (_Context == null)
                {
                    _Context = new BlogEntities();
                }
                return _Context;
            }

        }
        #endregion
Next, create the SAVE method, as follows:
Generic Repository in ASP.NET MVC 4

 public bool Save(object target, int RecordsNumber)
        {
            try
            {
                return Context.SaveChanges() == RecordsNumber;
            }
            catch (OptimisticConcurrencyException)
            {
                ObjectContext ctx = ((IObjectContextAdapter)Context).ObjectContext;
                ctx.Refresh(RefreshMode.ClientWins, target);
                return Context.SaveChanges() == RecordsNumber;
            }
        }

        public void Dispose()
        {
            if (Context != null)
            {
                Context.Dispose();
                GC.Collect();
            }
        }
As you see, we have a response in case of a concurrency exception. Optimistic Concurrency Exception means, we are optimistic in supposing that the current record being updated by us, is not being changed by anybody else. But, if at the moment we SAVE the record, the Entity Framework realize it has been changed in the meantime by somebody else, it will not allow us to save, but will throw an OptimisticConcurrencyException instead. What we do here, is REFRESHING the entity (getting the updated record) , state that CLIENTWINS over the data store (meaning that OUR changes override the record from database), and then SAVE it again.
Notice that we CAST the DbContext in an ObjectContext, in order to REFRESH the data.

Now let's code the complete C.R.U.D. (Create Retrieve Update Delete) operations, in a generic way:
Generic Data Repository

public void Create<T>(T entity) where T : class
        {
            Context.Set<T>().Add(entity);
        }
We typed a generic Create method using the generic Set<T>( ) method from the DbContext.
Now, Retrieve will support 3 cases :
   1) retrieve ALL records : if both parameters ID and PRED are empty : it's sensible, isn't it?
   2) retrieve just ONE record : if ID contains a value
   3) retrieve SELECTED records according to a PREDICATE : if the PRED parameter is set :
Data Repository ASP.NET MVC 4

public List<T> Retrieve<T>(int? Id, Func<T, bool> pred) where T : class
        {
            List<T> list = new List<T>();
            if (Id.HasValue)
            {
                list.Add(Context.Set<T>().Find(Id.Value));
            }
            else if (pred != null)
            {
                list = Context.Set<T>().Where(pred).ToList();
            }
            else list = Context.Set<T>().ToList();
            return list;
        }
Now for the UPDATE method, just get the local entry, and set its state to "modified" :

public void Update<T>(T entity) where T : class
        {
            var e = Context.Entry<T>(entity);
            e.State = EntityState.Modified;
        }
Finally, DELETE just removes the entity : 
Repository ASP.NET MVC 4
public void Delete<T>(T entity) where T : class
        {
            Context.Set<T>().Remove(entity);
        }
That's all the GENERIC Repository.

How to use it? Example of using it on a Controller:
Get ALL records : 
Generic Data Repository

Get a LIST of SOME records : 

Generic Data Repository in MVC 4

Get just ONE record : 
 CREATE a new record : 


UPDATE a record : 


DELETE a record :

 This is the complete Generic Data Repository code for you:
public class DataRepository : IDisposable
    {
        #region Context
        private BlogEntities _Context;
        public BlogEntities Context
        {
            get
            {
                if (_Context == null)
                {
                    _Context = new BlogEntities();
                }
                return _Context;
            }

        }
        #endregion
        ///////// GENERIC C R U D METHODS :
        public void Create<T>(T entity) where T : class
        {
            Context.Set<T>().Add(entity);
        }
        public List<T> Retrieve<T>(int? Id, Func<T, bool> pred) where T : class
        {
            List<T> list = new List<T>();
            if (Id.HasValue)
            {
                list.Add(Context.Set<T>().Find(Id.Value));
            }
            else if (pred != null)
            {
                list = Context.Set<T>().Where(pred).ToList();
            }
            else list = Context.Set<T>().ToList();
            return list;
        }
        public void Update<T>(T entity) where T : class
        {
            var e = Context.Entry<T>(entity);
            e.State = EntityState.Modified;
        }
        public void Delete<T>(T entity) where T : class
        {
            Context.Set<T>().Remove(entity);
        }
        public bool Save(object target, int RecordsNumber)
        {
            try
            {
                return Context.SaveChanges() == RecordsNumber;
            }
            catch (OptimisticConcurrencyException)
            {
                ObjectContext ctx = ((IObjectContextAdapter)Context).ObjectContext;
                ctx.Refresh(RefreshMode.ClientWins, target);
                return Context.SaveChanges() == RecordsNumber;
            }
        }

        public void Dispose()
        {
            if (Context != null)
            {
                Context.Dispose();
                GC.Collect();
            }
        }
    }



That's All !!!! 
In this tutorial we've learned how to create a  Generic Data Repository in ASP.NET MVC 4.  

Happy programming.....


כתב: כרמל שוורצמן

Sunday, April 27, 2014

Step by Step how to create a Cascading DropDownList with Ajax functionality

        By Carmel Shvartzman


In this tutorial we'll learn how to create two Cascading DropDownLists with Ajax functionality. The  two Cascading DropDownLists will update its items dynamically Ajax-loading data from database, according to the user's selections.

We'll design a web site using a free CSS Template, as explained in a former tutorial,  and a JQuery UI Theme that we imported in this tutorial. They are short step by step begginer's guides, so if you like the look-and-feel of this web site, follow those 10 minutes tutorials to make this same site.

We'll want to create two Cascading DropDownLists with Ajax functionality , showing as follows:

The <select> tags will be loaded with data from the following related entities:


First, create a new Controller and create a Repository instance (provided you have one):


Add a new View for the Index Action method, and create two <select> as follows:

<div class="ui-widget-content ui-corner-all divselect">
    <div class="float-left">
        Select a Blog Post
        <br />
        <select id="Posts">
            <option value="-1">Select a Post</option>
        </select>
    </div>
    <div class="float-right">
        Select a Post Comment<br />
        <select id="Comments">
            <option value="-1">Select a Comment</option>
        </select>
    </div>
    <div id="txtComment" class="ui-widget-content ui-corner-all divselect float-left"></div>
</div>

Notice we're using the JQueryUI theme CSS classes.
Now add a <script> and an Ajax $.getJSON() call which executes right after the HTML document is loaded. This call will populate the FIRST <select>  control:


<script>$(function () {
    $.getJSON("CascadingDDL/Blogs/", function (data) {
        var list = "<option value='-1'>Select a Post</option>";
        $.each(data, function (i, post) {
            list += "<option value='" + post.Value + "'>" + post.Text + "</option>";
        });
        $("#Posts").html(list);
    });

The function makes a HTTP_GET call to the following Action method, which returns all the Blog posts in JSON notation:


public ActionResult Blogs()
        {
            List<Blog> posts = Rep.RetrieveBlog(null).ToList();
            if (HttpContext.Request.IsAjaxRequest())
            {
                SelectList select = new SelectList(posts, "BlogID", "Title");
                return Json(select, JsonRequestBehavior.AllowGet);
            }
            return View(posts);
        }

This Action method uses the RetrieveBlog method on the Repository:

       public IEnumerable<Blog> RetrieveBlog(int? Id)
        {
            List<Blog> list = new List<Blog>();
            if (Id.HasValue)
            {
                list.Add(Context.Blogs.Find(Id));
            }
            else
            {
                list = Context.Blogs.ToList();
            }
            return list;
        }

It's a generic method which works with or without a parameter.
Next, add an event handler for the 1st <select> CHANGE event at the <script>:


 $("#Posts").change(function () {
        var PostId = $("#Posts > option:selected").attr("value");
        $.getJSON("CascadingDDL/Comments/" + PostId, function (data) {
            var list = "<option value='-1'>Select a Comment</option>";
            $.each(data, function (k, comment) {
                list += "<option value='" + comment.Value + "'>" + comment.Text + "</option>";
            });
            $("#Comments").html(list);
        });
    });

This sends an Ajax HTTP_GET request to populate the 2nd <select> with the data corresponding to the SELECTED value at the 1st <select> control. This $.getJSON calls another Action method :



 public ActionResult Comments(int? Id)
        {
            List<Comment> comments = Rep.RetrieveBlogComments(Id).ToList();
            if (HttpContext.Request.IsAjaxRequest())
            {
                SelectList select = new SelectList(comments, "CommentID", "Title");
                return Json(select, JsonRequestBehavior.AllowGet);
            }
            return View(comments);
        }

This method uses another Repository function as follows:

 public IEnumerable<Comment> RetrieveBlogComments(int? Id)
        {
            List<Comment> list = new List<Comment>();
            if (Id.HasValue)
            {
                list = Context.Comments.Where(c => c.BlogID == Id).ToList();
            }
            else
            {
                list = Context.Comments.ToList();
            }
            return list;
        }


This fetchs only the Comments corresponding to the selected Blog post.
Finally, append a last $.ajax HTTP_POST function to the <script>, in order to get the text of the selected Comment:

$("#Comments").change(function () {
        var Id = $("#Comments > option:selected").attr("value");
        if (Id >= 0) {
            $.ajax("CascadingDDL/CommentText/", {
                data: { "CommentId": Id }, type: "POST", success: function (txt) {
                    $("#txtComment").html("<i>" + txt + "</i>");
                }
            });
        }
    });

This $.ajax calls the following Action method:


 public JsonResult CommentText(int? CommentId)
        {
            if (HttpContext.Request.IsAjaxRequest())
            {
                string comment = Rep.RetrieveComment(CommentId).Text;
                return Json(comment);
            }
            return Json("");
        }

This Action method uses a Repository function to fetch the Comment's text::


 public Comment RetrieveComment(int? Id)
        {
            Comment comment = null;
            if (Id.HasValue)
            {
                comment = Context.Comments.Where(c => c.CommentID == Id).FirstOrDefault();
            }          
            return comment;
        }
Build and run the app:


When the user selects a Post, the list of Comments is refreshed:



And when a Comment is selected, its text is Ajax displayed below:



That's all!! 
In this tutorial we've learn how to create two Cascading DropDownLists with Ajax functionality.  

Happy programming.....


כתב: כרמל שוורצמן