Sunday, June 24, 2012

Including a Web API in knockout (going from hard coded to dynamic) (Part 1)

Technologies

ASP.NET MVC 4.0 Release candidate, Web API, Knockout.js, C#

Goal

Make a web architecture that separates the API from the UI and will move toward mobile.  Use the technologies listed above, together.  Move toward using Upshot.js, Entity Framework, and Knockout mapping if they help.

Background

In my last post I got Knockout working in MVC 4.0.  I’m happy with that but the way the sample was created that I was following, it was hard-coding the JSON on the client:
$(function () {

    var data = 
        [
            { Id: 1, Name: "Ball Handling" },
            { Id: 2, Name: "Passing" },
            { Id: 3, Name: "Shooting" },
            { Id: 4, Name: "Rebounding" },
            { Id: 5, Name: "Transition" },
            { Id: 6, Name: "Defense" },
            { Id: 7, Name: "Team Offense" },
            { Id: 8, Name: "Team Defense" }
        ];

    var viewModel = {

        tags: ko.observableArray(data),
        tagToAdd: ko.observable(""),

        //behaviors
        addTag: function () {
            this.tags.push({ Name: this.tagToAdd() });
            this.tagToAdd("");
        }

    };

    ko.applyBindings(viewModel);

});

Since I want to have a dynamic application that has a database and a web API, I need to make sure that I can get data from my server.  And I don’t know how to do that.  So here’s how!

What I want to do is replace the block where var data = “bla bla bla” with var data = data from my web API.  But first I need a web API.  Well, good thing, I already created a new Web API project in Visual Studio, so if I’m smart enough, I should just be able to call it………

wr1b1zhf

Getting it done, the steps


My first question is how does the UI “see” the API?  In particular, what’s the API’s address if Visual Studio has a dynamic server name like localhost:30983445. 

I ran into this page about single page web apps and thought to myself that maybe I had been doing it wrong.  Maybe I want to create a single-page web application and all of this wiring exists!?

So I started learning more about SPA (Single Page Applications) by watching this video with Steve Sanderson.  It’s an architecture.

So I went to my Visual Studio to find the SPA template and it was not there.  So I did some searching and found on this forum this, "Alright folks.. I found the answer. Single page templates have been withdrawn from MVC4 RC release and will not be available in the final release too. The team have identified that there are incompatibilities and they would like to work on it further before its released."  Son of a!!!!!!!!!

The page also gave instructions on how to hack around it so I started doing that.

I installed the Single Page Application Nuget Package (details on this page) into my non-Web API project.

It seems to have done it’s job.  I noticed it uninstalled some knockout stuff.  I hope that’s not an issue:
Successfully uninstalled 'jQuery 1.6.2'.
Successfully uninstalled 'knockoutjs 2.0.0'.

I was psyched to download a demo SPA app from Bart Jolling but it didn’t run.  I figured it had to do with the move from Beta to release candidate.  So I kept watching the video.

At 21 minutes, 40 seconds in the video, Steve says that Web API URLs have  a /API prefix.  So maybe this is the answer to my question.  I go and test this a little.

I started thinking that the place I need to implement my knockout is in my Web API project.  It turns out the the Web API projects can be both the web API and client.  I don’t know how good this practice is but it gets me past this current scenario so I move all of my modifications from the other project into my Web API project to see if I’m at least on the same, stable ground there.

I add the scripts that I think I have to have to _Layout.cshtml:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/themes/base/css", "~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
</head>
<body>
    @RenderBody()

    @Scripts.Render("~/bundles/jquery")
    <script type="text/javascript" src="http://github.com/downloads/SteveSanderson/knockout/jquery.tmpl.js"></script>
    <script type="text/javascript" src="~/Scripts/knockout-2.1.0.js"></script>
    <script type="text/javascript" src="~/Scripts/knockout.mapping-latest.js"></script>
    @RenderSection("scripts", required: false)
</body>
</html>

I went into the Index.cshtml page and tried to paste my same code but it was angry.  So I started to think maybe it would work if the more robust Mobile Template was the main project and it had the Web API stuff embedded in it.  This is seeming more plausible: from that project I get this option:

5xo2ppkf

So I decided to try to solve my project within the Mobile template to make it have a web API inside of it.  My goal was to only prove that I could get anything from my web API so I just pasted in the stuff from the default ValuesController that comes out of the box in the Web API template:
public class ValuesController : ApiController
{
    // GET api/values
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET api/values/5
    public string Get(int id)
    {
        return "value";
    }

    // POST api/values
    public void Post(string value)
    {
    }

    // PUT api/values/5
    public void Put(int id, string value)
    {
    }

    // DELETE api/values/5
    public void Delete(int id)
    {
    }
}

Now I needed to test if I would be able call /api/values/get/5 and have it return “values”.  (or even if that URL existed).  At this point I deleted the API project since I was no longer planning to use it and wanted a clean solution and no noise.  So I was very stoked to see this:

image

It’s returning XML from my Web API within my Mobile App.  It’s looking good.

Continued in next post….(I ran out of space on this Blogger site!!!!!!!!! WTH).

No comments: