Carpool Project: Part #12

I am working though the basic CRUD of EF/Factory and I ran into an issue. I coded

1 public static void DeleteCarpool(Carpool carpool) 2 { 3 using (CarpoolEntities carpoolEntity = new CarpoolEntities()) 4 { 5 var carpoolToDelete = (from cp in carpoolEntity.Carpool_Carpool 6 where cp.CarPoolId == carpool.Id 7 select cp).First(); 8 9 carpoolEntity.DeleteObject(carpoolToDelete); 10 carpoolEntity.SaveChanges(); 11 } 12 } 13  

 

And I got the following error in my unit test:

Carpool68

I then realized I didn’t cascade the changes on the server. I thought EF handled that for me – I guess not. I changed it in SQL Server:

Carpool69

And things ran like a champ….

Carpool Project: Part #10

I went back to the update of the Carpool Controller and changed the view to include the Driver like so:

Carpool62

I then updated the driverId to see if the changes propagate. The new value is in the form collection:

Carpool63

But after running UpdateView(), the new value is dropped.

Carpool64

Apparently, only the top-level properities are affected by UpdateView? Ugh – between the date/time conflict the nested properties, UpdateView only is useful for the most basic scenarios. I’ll replace UpdateView with a method that I write.

I thought about using Reflection like so (this is not right):

1 private void UpdateCarpoolFromFormCollection(Carpool.Domain.Carpool carpool, FormCollection collection) 2 { 3 4 PropertyInfo[] propertyInfos = carpool.GetType().GetProperties(); 5 foreach (PropertyInfo propertyInfo in propertyInfos) 6 { 7 for (int i = 0; i < collection.Count; i++) 8 { 9 if (propertyInfo.Name == collection[i].ToString()) 10 { 11 propertyInfo.SetValue(carpool,collection[i],null); 12 } 13 } 14 } 15 16 } 17  

I realized I really don’t understand the FormCollection object and how to enumation (or write some LINQ) to pull the correct value out of it. I then realized that I am being stupid. Of course the MVC creators would allow for next properities. I wrote a quick hello world app and sure enough, the changes are coming down:

Carpool65

The difference is the “.”. In my carpool solution, the Carpool.Drver is somehow turning into CarpoolDriver:

Carpool66

Changing this

1 <div class="editor-label"> 2 <%: Html.LabelFor(model => model.Driver.Id) %> 3 </div> 4 <div class="editor-field"> 5 <%= Html.TextBox("carpoolDriverId", Model.Driver.Id)%> 6 <%: Html.ValidationMessageFor(model => Model.Driver.Id)%> 7 </div> 8  

To This

1 2 <div class="editor-label"> 3 <%: Html.LabelFor(model => model.Driver.Id) %> 4 </div> 5 <div class="editor-field"> 6 <%: Html.TextBoxFor(model => model.Driver.Id)%> 7 <%: Html.ValidationMessageFor(model => model.Driver.Id)%> 8 </div> 9  

 

And boom goes the dynamite…

Carpool Project: Part #9

I started with the View a bit more and I ran into an issue that cuts to the heart of D3 and SOC. On my Carpool page, I want a grid of all practices that are associated with the car pool (usually 1, but could be more). In the view, I wrote this (headers omitted for brevity):

1 <% foreach (Com.Tff.Carpool.Domain.Practice practice in Model.Practices) 2 { %> 3 <tr> 4 <td> 5 <%: practice.Id%> 6 </td> 7 <td> 8 <%: practice.Date%> 9 </td> 10 <td> 11 <%: practice.DryLandIndicator%> 12 </td> 13 <td> 14 <%: practice.EndTime%> 15 </td> 16 <td> 17 <%: practice.StartTime%> 18 </td> 19 <td> 20 <% foreach (Com.Tff.Carpool.Domain.SwimGroup swimGroup in practice.SwimGroups) 21 { %> 22 <%: swimGroup.Name%> 23 <% } %> 24 </td> 25 <td> 26 <%: Html.ActionLink("Edit", "Edit", new { practiceId = practice.Id })%> 27 <%: Html.ActionLink("Delete", "Delete", new { PracticeId = practice.Id })%> 28 </td> 29 </tr> 30 31 <% } %> 32  

And it comes out with the expected HTML:

carpool32

Notice how the Swim Group is joined together using that secondary loop. This got me thinking, part of the reason I crated the ViewModel POCOs was to do this kind of flattening. If the UI can handle it easily, why not use EF-enabled POCOs and save the who Domain Layer step of mapping the EF Classes to the POCO ones? If all I had to worry about was the flattening of Swim Groups to practices, perhaps writing that join in the UI is better than the Domain Layer. Then I thought – NO. The domain layer should be responsible for serving objects, even if the UI can handle it. I would say that is analogous to “we can put the code in the code-behind in Web Forms.” Eventually, the code needs to be written – so I would rather have it in the Domain layer where I have exact control and can add in any custom logic. If any custom logic for the flattening happens, the UI will quickly become a morass of spaghetti. On a side note, I find writing C# is much much better than writing WebForms View Engine code – those gators drive me nuts.

Saying that, I realized I don’t need a carpool controller, I need a CarpoolSummary controller and view -> for the simple reason that Carpools don’t have PracticeSummaries – CarpoolSummaries do. Time to do some re-writing!

Carpool Project: Part #7

I am now moving into the site navigation of the carpool site. It was my 1st real foray into routing and after a couple of minutes, I realized it is straightforward. I had 2 controllers:

1 for the main page that shows 2 grids (current carpools and uncovered practices)

1 for the carpool update, insert, and delete pages

Here is an example of the Update method (so far):

1 public ActionResult Edit(int carpoolId) 2 { 3 Carpool.Domain.Carpool carpool = CarpoolFactory.GetCarpool(carpoolId); 4 return View(carpool); 5 } 6 7 [HttpPost] 8 public ActionResult Edit(int carpoolId, FormCollection collection) 9 { 10 try 11 { 12 Carpool.Domain.Carpool carpool = CarpoolFactory.GetCarpool(carpoolId); 13 UpdateModel(carpool); 14 CarpoolFactory.UpdateCarpool(carpool); 15 return RedirectToAction("Index"); 16 } 17 catch 18 { 19 return View(); 20 } 21 } 22  

 

I had to do some redirecting – there is no Index controller/page for the carpool as it is all handled out of Main.Index. I created the follwoign routes to allow me to redirect from one controller to the next:

1 routes.MapRoute( 2 "EditCarpool", 3 "Home/Edit", 4 new { controller = "Carpool", action = "Edit" } 5 ); 6 7 routes.MapRoute( 8 "CreateCarpool", 9 "Home/Create", 10 new { controller = "Carpool", action = "Create" } 11 ); 12 13 routes.MapRoute( 14 "DeleteCarpool", 15 "Home/Delete", 16 new { controller = "Carpool", action = "Delete" } 17 ); 18 19 routes.MapRoute( 20 "ReturnHome", 21 "Carpool", 22 new { controller = "Home", action = "Index", id = UrlParameter.Optional } 23 ); 24 25 routes.MapRoute( 26 "Default", // Route name 27   "{controller}/{action}/{id}", // URL with parameters 28 new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults 29 ); 30

My only question is how to add in the parameter so it looks like Carpool/Update/2 and not Carpool/Update?carpoolId = 2

Carpool Project: Part #4

I wrote this factory code:

1 public SwimTeam GetSwimTeam(int swimTeamId) 2 { 3 var selectedSwimTeam = (from swimTeam in carpoolEntity.Carpool_SwimTeam 4 where swimTeam.SwimTeamId == swimTeamId 5 select swimTeam).First(); 6 7 return MapSwimTeam(selectedSwimTeam); 8 9 } 10 11 public List<SwimTeam> GetAllSwimTeams() 12 { 13 List<SwimTeam> swimTeams = new List<SwimTeam>(); 14 15 var swimTeamsQuery = (from swimTeam in carpoolEntity.Carpool_SwimTeam 16 select swimTeam); 17 18 foreach(Carpool_SwimTeam carpool_Swimteam in swimTeamsQuery) 19 { 20 swimTeams.Add(MapSwimTeam(carpool_Swimteam)); 21 } 22 23 return swimTeams; 24 } 25  

How do I know that I wrote it right?

Unit Test? Integration Test? I don’t care what you call it – I want to make sure it is right BEFORE I use this as a pattern for the rest of the project.

So I created a couple of unit tests (and remembering to add the app.config to my unit test project)

1 [TestMethod()] 2 public void GetSwimTeamTest() 3 { 4 string expected = "RSA"; 5 string actual = SwimTeamFactory.GetSwimTeam(1).Name; 6 Assert.AreEqual(expected, actual); 7 } 8 9 /// <summary> 10 ///A test for GetAllSwimTeams 11 ///</summary> 12   [TestMethod()] 13 public void GetAllSwimTeamsTest() 14 { 15 int expected = 3; 16 int actual = SwimTeamFactory.GetAllSwimTeams().Count; 17 Assert.AreEqual(expected, actual); 18 } 19  

And got green:

Carpool14

I then wired up the UI

I added a controller to my MVC application

1 public class SwimTeamController : Controller 2 { 3 SwimTeamFactory swimTeamFactory = null; 4 5 public SwimTeamController() 6 { 7 swimTeamFactory = new SwimTeamFactory(); 8 } 9 10 public ActionResult Index() 11 { 12 return View(swimTeamFactory.GetAllSwimTeams()); 13 } 14 15 } 16

Added the connection string to the Web.Config

Added an auto generated View

Carpool15

 

And boom goes the dynamite…

Carpool16

ASP.NET MVC 2 RoutingEngineSiteMapProvider

Continuing my thought on RoutingEngineSiteMapProvider, I worked with Rob Seder on Sunday for a bit

I was thinking of Maarten Balliau’s solution on CodePlex to a MVCSiteMapProvider and was wondering if there is an easier way. We tried inheriting from StaticSiteMapProvider and copy/pasting the code from XmlSiteMapProvider and re-writing it(like Maarten did), created our own implementation for the SiteMapProvider, and then giving up.

That afternoon I then looked at inheriting from XMLSiteMapProvider and intercepting the NodeCreation to plug in a MvcSiteMapNode.  I just created a basic node like so:

        public MvcSiteMapNode(SiteMapProvider provider, string key, string url, string title, string description, IList roles, NameValueCollection attributes, NameValueCollection explicitResourceKeys, string implicitResourceKey):

            base(provider, key, url, title, description,roles,attributes,explicitResourceKeys,implicitResourceKey)

        {

        }

 

        public string Controller { get; set; }

        public string Action { get; set; }

 

The rest of the constructiors were omitted for brevity

I then tried to intercept the call in BuildSiteMap method. 

    public class RoutingEngineSiteMapProvider: XmlSiteMapProvider

    {

        public override SiteMapNode BuildSiteMap()

        {

            SiteMapNode siteMapNode = base.BuildSiteMap();

            MvcSiteMapNode mvcSiteMapNode = ConvertSiteMapNodeIntoMvcSiteMapNode(siteMapNode);

            return mvcSiteMapNode;

        }

 

        private MvcSiteMapNode ConvertSiteMapNodeIntoMvcSiteMapNode(SiteMapNode siteMapNode)

        {

            MvcSiteMapNode mvcSiteMapNode = new MvcSiteMapNode(siteMapNode.Provider,siteMapNode.Key,

                siteMapNode.Url,siteMapNode.Title, siteMapNode.Description);

 

            mvcSiteMapNode.Controller = "Test Controller";

            mvcSiteMapNode.Action = "Test Action";

 

            return mvcSiteMapNode;

        }

    }

 

Surprisingly, it worked.  However, when I went to add a line to check on the nodes themselves in BuildSiteMapNode() like this:

            int counter = mvcSiteMapNode.ChildNodes.Count;

 

Things went bad – Stack Overflow.  I was in recursive hell.

I then tried to intercept AddNode like this:

        protected override void AddNode(SiteMapNode node)

        {

            base.AddNode(node);

        }

 

The problem is that this method is not called when I spun up the site.

Grrrr… I am out of patience on this.  Looking at the code in Reflector makes me appreciate best practices all that more.  Node6  Microsoft, really?  What happens if there is a 7th level node?  No exception is thrown.

The last thing I can think of is to copy/paste the code in BuildSiteMap() and then getting rid of the XMLReader completely.  However, this would be a mucho breaking change because the method violates the Open/Closed Principle and the IoC tenant and I really don’t have the time to track down all of the dangling dependencies in this API.

ASP.NET MVC and Menu Trimming

One of the nice features with ASP.NET is menu trimming pretty much out of the box.  You need to:

Create a SiteMap:

<?xml version="1.0" encoding="utf-8" ?>

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >

  <siteMapNode url="" title=""  description="">

    <siteMapNode url="/Public" title="Public"  description="">

        <siteMapNode url="/Public/PublicContent1" title="Public Content #1"  description="" />

        <siteMapNode url="/Public/PublicContent2" title="Public Content #2"  description="" />

    </siteMapNode>

    <siteMapNode url="/Private" title="Private"  description="">

      <siteMapNode url="/Private/PrivateContent1" title="Private Content #1"  description="" />

      <siteMapNode url="/Private/PrivateContent2" title="Private Content #2"  description="" />

    </siteMapNode>

  </siteMapNode>

</siteMap>

 

Add the sitemap to your web.config:

    <siteMap defaultProvider="DefaultSiteMapProvider" enabled="true">

      <providers>

        <add name="DefaultSiteMapProvider" type="System.Web.XmlSiteMapProvider" siteMapFile="Web.sitemap"

             securityTrimmingEnabled="true" />

      </providers>

    </siteMap>

 

Add some roles to your web.config that protect certain areas

  <location path="~/Private">

    <system.web>

      <authorization>

        <deny users="*"/>

        <allow roles="admin"/>

      </authorization>

    </system.web>   

  </location>

 

Add a SiteMapDataProvider and a menu to your form that uses your SiteMapDataProvider:

            <div class="clear hideSkiplink">

                <asp:SiteMapDataSource ID="siteMapDataSource" runat ="server" ShowStartingNode="false" />

                <asp:Menu ID="NavigationMenu" runat="server" CssClass="menu" EnableViewState="false"

                    IncludeStyleBlock="false" Orientation="Horizontal" DataSourceID="siteMapDataSource">

<%                    <Items>

                        <asp:MenuItem NavigateUrl="~/Default.aspx" Text="Home"/>

                        <asp:MenuItem NavigateUrl="~/About.aspx" Text="About"/>

                    </Items>–%>

                </asp:Menu>

 

(Note that I left in the out of the box VS2010 template items for reference)

Voila – menu trimming

Behind the scenes, ASP.NET runtime knows to look for Web.Sitemap and then to look in your web.config for the roles

 

Once you move to MVC2, I thought all hope was lost.  No more server controls.  No more auto menu trimming.  No more free ice cream.  But, I was wrong.  You can use ASP.NET Server controls in your MVC2 project and things work just fine.   This is what I did:

I added a site map

<?xml version="1.0" encoding="utf-8" ?>

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >

  <siteMapNode url="" title=""  description="">

    <siteMapNode url="" title="Home"  description="">

      <siteMapNode url="Home/Index" title="Index"  description="" />

      <siteMapNode url="Home/About" title="About Us"  description="" />

    </siteMapNode>

    <siteMapNode url="" title="User Input"  description="">

      <siteMapNode url="UserInput/Index" title="Index"  description="" />

    </siteMapNode>

    <siteMapNode url="" title="Private" description="">

      <siteMapNode url="Private/CurrentTime" title="Current Time"  description="" />

    </siteMapNode>

  </siteMapNode>

</siteMap>

 

The first thing to realize is that you are no longer mapping to physical file locations – you are still using the routing engine.  Note that my siteamp does not have a .aspx suffix nor a \Views subdirectory listed.  Also, if you have the file location on disk but no controller, you get a 404:

I then added the same SiteMapProvider and Location syntax to the web.config.  The then added the SiteMapDataSource to the Master page with the menu.

            <div id="menucontainer">

                <form runat="server">

                    <asp:SiteMapDataSource runat="server" ID="smds" ShowStartingNode="false" />

                    <asp:Menu runat="server" ID="aspmenu" DataSourceID="smds" />

                </form>

<%                <ul id="menu">             

                    <li><%: Html.ActionLink("Home", "Index", "Home")%></li>

                    <li><%: Html.ActionLink("About", "About", "Home")%></li>

                </ul>–%>

            </div>

 

(Note that I left in the out of the box VS2010 template items for reference)

(also note that I had to add a form tag around the provider and menu)

I ran it – to my <slight> surprise, it worked – sorta:

I worry about the formatting later – at least it is showing up.  Alas, no menu trimming though!

Interestingly, looking at the HTTP via Fiddler, you can see the view state:

 Here are the problems:

·         Hard-Coded URLs in the sitemap

·         Permissions tied to File System locations

·         View State in MVC – Say it aint’s so!

 

I wonder if there is a way to create a SiteMap provider based on the Routing Engine?  A quick search showed this one  here and here.

But I wanted to try to extend the XMLSiteMapProvider to account for the routes.  But then, it is not an XMLSiteMapProvider.  In fact, it is a RoutingEngineSiteMapProvider.

My next blog post continues this idea/rabbit hole.

 

MVC Gators and VS2010

I start with an opening statement like this on a View:

</head>

<body>

    <% using (Html.BeginForm()) { %>

</body>

</html>

 

And then I add a closing gator

<% } %>

 

As soon as I hit enter to the closing gator, VS2010 reformats the code to this:

<body>

    <% using (Html.BeginForm())

       { %>

    <% } %>

</body>

 

Note how the opening gator gets moved down a line.

I think this is better b/c it is more in-line with our Server-side best practices – though it is against most Javascript best practices (and the examples in the book).  I assume there is a setting in VS2010 to not automatically put in the line break…

Also, note to self:

If you write your gator like this:

<%= Html.Label(TempData["message"].ToString()); %>

 

You will get an error message like this:

Remove the semicolon at the end and things work.  The “=” in the Gator means you don’t use a semicolon at the end…

Export To Excel in MVC

I ran into the need to export a table to Excel in a MVC application.  A quick search on Bing showed a couple of different options.  For example, Steven Walther had the most complete solution found here but it had waaay to much code.

My original code in a web form application is much more compact:

        private void ExportTimesToExcel()

        {

            Response.ContentType = "application/vnd.ms-excel";

            Response.Charset = "";

            this.EnableViewState = false;

 

            StringWriter stringWriter = new StringWriter();

            HtmlTextWriter textWriter = new HtmlTextWriter(stringWriter);

 

            HtmlForm form = new HtmlForm();

            this.Controls.Add(form);

            form.Controls.Add(this.SwimmerTimeGridView);

            form.RenderControl(textWriter);

 

            Response.Write(stringWriter.ToString());

            Response.End();

        }

 

So I thought if there was a way to duplicate that in MVC.  I ran across a good starting point here.

public class ExcelResult : ActionResult

{

      public string FileName { get; set; }

      public string Path { get;set; }

 

      public override void ExecuteResult(ControllerContext context)

      {

            context.HttpContext.Response.Buffer = true;

            context.HttpContext.Response.Clear();

            context.HttpContext.Response.AddHeader("content-disposition", "attachment; filename=" + FileName);

            context.HttpContext.Response.ContentType = "application/vnd.ms-excel";

            context.HttpContext.Response.WriteFile(context.HttpContext.Server.MapPath(Path));   

      }

}


 

And here is the function to get the File

public ExcelResult GetExcelFile()

{

      return new ExcelResult

                  {

                        FileName = "sample.xls", Path = "~/Content/sample.xls"

                  };

}

 

And here is a MVC View control that calls it

<%= Html.ActionLink("Download Excel", "GetExcelFile", "Home")%>

 

So I needed to meld together some separated parts.

They key is this line:

context.HttpContext.Response.WriteFile(context.HttpContext.Server.MapPath(Path));   

The problem is that I don’t have an Excel file to start with so I can’t use Write File.  I first thought of writing a stream of XML that Excel recognizes.  So what is the fastest way to get XML from a Data Table?  I can’t use the web form trick of this

form.Controls.Add(this.SwimmerTimeGridView);

            form.RenderControl(textWriter);

 

because the controller doesn’t know anything about how the views are rendering the model.  It could use a Table, it could use a series of labels, etc…

I then thought (briefly) about looping through some LINQ  that is hitting the entire model – and realized that I didn’t want to do that (that is what Steve did)

I then thought – wait a second.  <insert second here> ADO.NET has a XML from DataTable.  If I had a model with the data as a DataTable, I can render the stream out as XML and everything should work…

Step #1: Add a ADO.NET DataSet

 
 

 

Then

Step #2: Create that Excel Class

    public class ExcelResult : ActionResult

    {

        public string XMLStream { get; set; }

        public string FileName { get; set; }

 

        public override void ExecuteResult(ControllerContext context)

        {

            context.HttpContext.Response.Buffer = true;

            context.HttpContext.Response.Clear();

            context.HttpContext.Response.AddHeader("content-disposition", "attachment; filename=" + FileName);

            context.HttpContext.Response.ContentType = "application/vnd.ms-excel";

            context.HttpContext.Response.Write(XMLStream);

        }

    }

 

Step #3: Call it from the Controller

 

        public ExcelResult GetExcelData()

        {

            Northwind northwind = new Northwind();

 

            string xmlStream;

            using (StringWriter sw = new StringWriter())

            {

                northwind.Tables[0].WriteXml(sw);

                xmlStream = sw.ToString();

            }

 

 

            return new ExcelResult

            {

                FileName = "sample.xls",

                XMLStream = xmlStream

            };

 

Step #4: Hook up a link to try it out

    <%= Html.ActionLink("Download Region Info To Excel", "GetExcelData", "Region")%>

 

The first try I got this:

And the result was this:

Ooops – Looks like the DataTable is not like Linq to SQL or Entity Framework – I actually have to code up the loading of it.  I added this code to load the data table

            RegionTableAdapter regionTableAdapter = new RegionTableAdapter();

            Northwind.RegionDataTable regionDataTable = regionTableAdapter.GetData();

 

Getting Closer

I have the data, Excel is launching, but Excel is not recognizing the XML as XML:

So the last thing I have to do is change the extension to .xml

            return new ExcelResult

            {

                FileName = "sample.xml",

                XMLStream = xmlStream

            };

 

and boom goes the dynamite (assuming the user has .xml hooked to open as Excel)

 

MVC Ajax/Json and Serialization

One of the biggest learning curves for me over the last week is how to pass data from the client to the server using Ajax and Json in an MVC solution.  As I can tell, there are 3 main patterns:

·         Individual parameters

·         Complex object that is serialized

·         Abstract Collection or array

MVC uses:

·         Request.Form[“x”] where x is the name of the property to assign to the object

·         UpdateModel(x) where x is the name of the class you want to update.  Behind the scenes, MVC hooks up the proprieties from the form collection to the proprieties in that object.  Therefore, the name of the property must match exactly between the form and the object

·         Or just pass in the object to the parameter.  Behind the scenes, MVC assigns the values to the properties, serializes the object, and throws it into your parameter

The first option, Request.Form[“x”] where x is the name of the property to assign to the object:

For example:

        [HttpPost]

        public ActionResult Create()

        {

            try

            {

                Region region = new Region();

                region.RegionID = Int32.Parse(Request.Form["regionId"]);

                region.RegionDescription = Request.Form["regionDescription"];

 

                //Insert Logic Here

                return RedirectToAction("Index");

            }

            catch

            {

                return View();

            }

        }

 

But you can’t have 2 methods with the same interface, so you can’t have this also:

        public ActionResult Create()

        {

            return View();

        }

 

So you can drop the one for the Get – but then every get requires an input.  So you are stuck, unless you muck about in the routing.

Alternatively, you can use the default and pass in a variable and not use it – which is what MVC does out of the box with the formCollection.  I passed in an Id for the heck of it:

        [HttpPost]

        public ActionResult Create(int? id)

        {

            try

            {

                Region region = new Region();

                region.RegionID = Int32.Parse(Request.Form["regionId"]);

                region.RegionDescription = Request.Form["regionDescription"];

 

                //Insert Logic Here

                return RedirectToAction("Index");

            }

            catch

            {

                return View();

            }

        }

 

And looking at the watch, you can see that the Form collection is being populated:

 

This is all well and good, but does not help me with a JSON request (and least not directly) because there is no Form Collection to be had. 

Interestingly, when making a method with the class as a parameter, MVC does a Json call behind the scenes.  For example, consider this method that returns a View:

        [HttpPost]

        public ActionResult Create(Region region)

        {

 

            //Insert Logic Here

 

            return View();

        }

 

Check out the base value: JsonSerialization:

So I wondered if MVC can do it, why can’t I?  Can I send the exactly same Json values and have it parse?

I wrote some JQuery with Ajax like so:

    <script type="text/javascript">

        function CallService() {

            var regionId = $("#RegionID").val();

            var regionDescription = $("#RegionDescription").val();

            var postData = { RegionID: regionId, RegionDescription: regionDescription };

            $.ajax({

                type: "POST",

                url: "/Region/Create",

                data: postData,

                dataType: "json"

            });

        }

    </script>

 

I then fired up Fiddler and find out:

Here is the request/response:

 

 And Holy Cow – It worked!  Check out a Quick Watch from my controller:

 
When using Json and Ajax, all you need is an object on the client, explicitly assigning  the parameter values, and have a matching object on the controller’s parameters.  I have not investigated default values, missing values, and the like, but I am just excited to see this working.