Archive Page 2

Beyond Configuring Web Services in WCF 4.5

In my previous post, I looked at how easy it was to add a basic HTTP Web Service to a Web site in the beta of the .NET Framework 4.5 through code: Just add a shared/static method called Configure to your service and put some code in it to configure the ServiceConfiguration object passed to the method. In fact, because of the defaults that WCF 4.5 takes for a WCF service in a Web Site you don’t really need to add any code at all. In my example I did add some code to explicitly enable my service as a basic HTTP Web Service. I also chose to configure the service to return a contract and verbose error messages (both of which are turned off by default) to support testing.

But the power of WCF is in providing multiple ways of accessing the same code–as a basic Web Service or as a high performance TCP-based service. Adding TCP access requires a change in the project type:  Testing a TCP-based service from Visual Studio is awkward (at best). Instead, you’ll want to create a WCF Service library where you service is hosted by WAS rather than IIS. While that makes testing your TCP access is simplified, the defaults don’t give you a service automatically and you’ll need to use a few more lines of code.

After creating your WCF Service library project add a new WCF Service to it, giving the service some meaningful name (I used “CustomerService”). Then, to demonstrate the power of configuring by code, go to your app.config file and delete the entire system.model element. You’re now ready to control your service from code.

These two lines of code make your service available as a Web Service and as a TCP-based service (which will have orders-of-magnitude better performance than the HTTP-based Web service):

PublicSharedSub Configure(sc AsServiceConfiguration) 
sc.EnableProtocol(New BasicHttpBinding)  
sc.EnableProtocol(New NetTcpBinding) 

While that (in theory) makes your service accessible, it doesn’t make the information about the service (the metadata) available. As a result, you won’t be able to either use Visual Studio’s WCF Test Client or be able add a service reference for your service to another project by using the Add Service Reference dialog’s Discover button. To enable the metadata you use the same code that I had in my previous post but with one extra line of code that specifies the address where the metadata is available. In that line you create a System.URI object specifying the address (the address must reference your computer name but the port and service name are up to you) and use it to set the HttpGetUrl property:

Dim behavior As New Description.ServiceMetadataBehavior 
behavior.HttpGetEnabled = True 
behavior.HttpGetUrl = New System.Uri("http://localhost:1868/Customers") 
sc.Description.Behaviors.Add(behavior) 

You also need to add endpoints for HTTP and TCP access to your service. For that, you use the AddServiceEndpoint method on the ServiceConfiguration object passed to your Configure method. The first parameter to the AddServiceEndpoint is the type of the interface that your service implements (“ICustomers” in this example), the second parameter is the binding class for the endpoint, and the final parameter is the address itself (make sure that you use different addresses for each endpoint):

sc.AddServiceEndpoint(GetType(ICustomerService), 
         New BasicHttpBinding(), 
         "http://localhost:1868/Customers") 
sc.AddServiceEndpoint(GetType(ICustomer), 
         New NetTcpBinding(),  
         "net.tcp://localhost:1867/Customers")

There is an annoyance when you go to test your service: In a Service Library, in the absence of any entries in the config file, the test client can’t retrieve the information about the service. You’ll first get a dialog that the “WCF Service Host cannot find any service metadata”–just click the No button to continue. When the Test Client appears, it won’t display any services. You’ll need to go to the Test Client’s File menu and select Add Service to display the Add Service dialog box. In the box, enter the URL you used to set the HttpGetUrl property followed by “?wsdl” (e.g. “http://localhost:1868/Customers?wsdl”—and make sure you type the URL exactly the way it appears in your code). When you click the OK button, the Test Client will finally grab the service information and you’ll be able to test your service. The good news here is that, once you enter the URL with ?wsdl successfully, you won’t have to enter it again (you will still need to go through all the dialogs, though).

And there you go: With less than a dozen lines of code you’ve configured a service as both a basic HTTP service and TCP-based service. Adding additional access methods (e.g. named pipes, advanced web services, https) should just consist of enabling the protocol with the EnableProtocol method and adding a compatible endpoint.

As before, your best Learning Tree source for WCF information is Programming WCF Web Services for .NET: A Comprehensive Hands-On Introduction.

Peter Vogel

One Line of Code to Configure WCF 4.5

The WCF 4.5 beta simplifies configuring WCF, provides better support for code-based configuration, and makes it easier to do code-based configuration in Web sites. Don’t get me wrong: I like the WCF configuration files but, I gather, I may be in a minority. Many developers prefer to configure their WCF services from code where possible. Unfortunately, one of the places where that isn’t possible is the most common place to host WCF services: in a Web application (well, I’m told it was possible but only in the sense that it’s possible to remove your own appendix).

WCF 4.5 (at least, in the beta) provides a simple solution: Add a static/shared method called Configure to your service class and fill it with the code required to configure your service. WCF will call that Configure method at the appropriate moment and pass the method an instance of the ServiceHost class. In your Configure method, you can work with that ServiceHost to configure your service.

What’s especially impressive is how simple it is. The default settings alone mean that if you add an svc file to your Web site then you have a Web Service. You can make that explicit, however, with a single line of code. This example makes the service containing this method available as a Web Service with no WCF-related tags required in the config file at all:

Public Shared Sub Configure(sc AsServiceConfiguration) 
 sc.EnableProtocol(NewBasicHttpBinding()) 
End Sub 

You can configure these services by instantiating behavior classes, configuring them, and adding them to the ServiceConfiguration’s Description property’s Behaviors collection. That’s a good thing because, while my previous example was all the code you need (in fact one more line than you needed), it’s probably not all the code you want, for two reasons.

Configuring the Service

First, with just that code you won’t be able to retrieve the WSDL contract for this service (what WCF refers to as service’s “metadata”) so you won’t be able to use Visual Studio’s WCF test client (you also won’t be able to use the Discover button in Visual Studio’s Add Service Reference dialog). For testing purposes, and until you can save to a separate file the WSDL contract that you can give to the developers building the clients/consumers for this service, you’ll want to configure your service to return a WSDL contract. To tell your service to make its metadata available you add code like the following to your Configure method. This code creates a ServiceMetadataBehavior object, sets its HttpGetEnabled property to True (that actually turns on the feature), and add the configured behavior to the Behaviors collection:

Dim behavior As New Description.ServiceMetadataBehavior 
behavior.HttpGetEnabled = True 
sc.Description.Behaviors.Add(behavior) 

Second, by default, WCF services don’t return a lot of information in their exception messages. That’s a good thing: While that information is very useful in debugging, it probably isn’t something you want to share with the general public. However, in testing, you probably do want that those chattier error messages and you can enable the with this code in the Configure method:

Dim debugBehavior As New Description.ServiceDebugBehavior 
debugBehavior.IncludeExceptionDetailInFaults = True 
sc.Description.Behaviors.Add(debugBehavior) 

But both of these changes highlight an issue with code-based configuration. In production, you probably don’t want your service freely giving up its contract to whoever asks for it. Instead you probably want to control access to your service’s contracts so that you have some idea who’s using your service and can contact those users when you’re making changes to your service. And you certainly don’t want to send out those verbose error messages from your production system. So, before moving your service to production you’re going to want to change the values used in this code.

The problem is that, with the code I’ve used here, there’s no simple way to inspect the assembly you’re deploying to production to determine if the settings are correct: the code is compiled and is unreadable. One of the nice features of the config files is that you could inspect them (and even change them) with Notepad. The right answer is probably to move settings that will change from one installation to another (e.g. test and production) into your AppSettings where you’ll still have visibility to them.

Many of Learning Tree’s courses touch on WCF but your best source for information is Programming WCF Web Services for .NET. It’s four intensive days of everything you’d want to know about WCF.

Peter Vogel

How to Use ViewModels Without Sacrificing Encapsulation

I have been using ASP.NET MVC extensively over the past year, and the more I use it, the more I like it. However, there remain a couple of things that bug me. One is the fact that the built-in validation doesn’t work with repeating forms. The other is the “best practice” of placing Data Annotations on a ViewModel class.

For me, validation rules belong on the business object itself, not on the ViewModel. One of the key benefits of encapsulation is that we reduce code duplication. If we don’t encapsulate the validation rules inside the object, then we are doomed to repeat them once for every presentation layer. Data Annotations in an MVC ViewModel are not available to a WPF UI. Not only does this lead to redundancy, it increases the risk of inconsistencies cropping up between UI.

So no problem, you might think. All we have to do is add the Data Annotations to the Model itself, and then add the Model as a property of the ViewModel.

Okay, let’s try that.

Here is the Model:

BasicClass simple C# class

And here is the ViewModel:

The ViewModel class

This looks straightforward enough. But look at what happens when we ask Visual Studio to scaffold the View:

View scaffolding

What happened to our “Basic” Model property? It’s not there. The scaffolding only seems to work for simple properties.

Okay, so let’s add the details of the Model to the View. In fact, let’s cheat. We’ll get Visual Studio to scaffold the inner Model for us. First we’ll create a throwaway View. Then we copy the contents of the form and paste it into the View that’s typed to the ViewModel. All we have to do then is change the lambda expressions to point at model.Basic rather than just model:

Full scaffolding

Problem solved. The View now contains the data we need and also respects our data annotations…

This means we can pass the ViewModel through to a Controller method and pick up the Model we need via the ViewModel’s “Basic” property. There’s only one problem:  How do we use the UpdateModel() method when we’re only interested in a property on the object passed to the method, rather than the whole object? Fortunately, Microsoft anticipated the need and there’s an overload on UpdateModel() that allows us to specify a prefix. In this case, not surprisingly, the HTML helpers have inserted the prefix “Basic”:

UpdateModel() with second argument

As you can see, the Model has successfully been bound, so we now have a mechanism for taking advantage of ViewModels without sacrificing encapsulation.

Kevin Rattan

For related information, check out Building Web Applications with ASP.NET MVC from Learning Tree.

Managing Screen Updates When Loading UI Controls Using Ajax

I came across an interesting problem recently while working on www.cocktailsrus.com. I was adding a new rating system allowing members to rate cocktails on a scale of 1-5. I wanted to do something that was accessible, but also visually appealing and appropriate, so that this:

radio buttons

could easily and accessibly be converted into this:

rating plugin with images

The answer, of course, was to write a jQuery plugin that would be called on document.ready() and convert the default radio-buttons to active images – but only for users who have JavaScript enabled. I duly wrote the plugin, and it does everything I intended (e.g. you can customize the images, change the maximum number on the scale etc.). It’s free for anyone to use, and you can download it here.

However, during testing I came across a problem. The site makes extensive use of Ajax, and when the partial page downloads to the client the radio buttons are briefly visible before being replaced by the images. The problem is that the screen is being updated before document.ready() runs.

The obvious solution is to use a callback. I use two different Ajax methods – the built-in jQuery .load() method and .ajaxSubmit() (part of the jquery form plugin). Both have callbacks that run when the Ajax call returns, like this:

$(‘article’).load(url, function () {

$(‘#ScoreSection’).rate();

});

Unfortunately, while this looked like a promising solution, the problem remained: there is a perceptible delay between the DOM updating and the callback running. Once again, the user sees the radio-buttons briefly before they are replaced. So how to fix the problem?

The answer lies in an old animation technique – make the change off-screen and only make it visible after it has completed. In this case, that means:

  1. Use jQuery to create an empty div element and assign the result to a variable
  2. Assign the return from the Ajax call to the variable
  3. Run the plugin against the updated variable
  4. Update the DOM with the variable

With .load():

var $temp = $(‘<div />’);

$temp.load(url, function () {

   $(‘#ScoreSection’, $temp).rate();

   $(‘article’).html($temp);

});

With .ajaxSubmit():

var $temp = $(‘<div />’);

$form.ajaxSubmit({ target: $temp,

   success: function () {

     $(‘#ScoreSection’, $temp).rate();

     $(‘article’).html($temp);

}

});

Using this technique, the images replace the radio-buttons before they become visible, even when using Ajax. For an extra refinement, add a test inside document.ready() to make sure that the original method is only invoked if the Ajax callback has not already run. In this case, that’s a simple matter of testing the visibility of the radio-buttons, and only running the .rate() method if they’re visible.

Kevin Rattan

For other related information, check out these courses from Learning Tree:

jQuery: A Comprehensive Hands-On Introduction

Building Web Applications with ASP.NET and Ajax

Building Web Applications with ASP.NET MVC

Validating That At Least One TextBox Has Content

I came across an interesting little validation problem on my current project. The site is for members only – and in order to become a member, you need to be nominated. You can provide either one or two nominators, but you must provide at least one.

So how to force users to enter text in either of two TextBoxes? RequiredFieldValidators won’t do, because either one can be left empty. Yet at least one must be completed. Clearly this is a job for CustomValidators.

The client-side and server-side code are both fairly straight-forward, but I thought someone out there might find it useful, so here it is.

First of all, the CustomValidators in the ASPX page:


<asp:CustomValidator ID=”Nomination1CustomValidator” runat=”server” Display=”None” ValidateEmptyText=”true” ClientValidationFunction=”CheckNominations” ErrorMessage=”At least one nomination must be provided” ControlToValidate=”Nominated1TextBox” OnServerValidate=”Nomination2CustomValidator_ServerValidate”></asp:CustomValidator>


<asp:CustomValidator ID=”Nomination2CustomValidator” runat=”server” Display=”None” ValidateEmptyText=”true” ClientValidationFunction=”CheckNominations” ErrorMessage=”" ControlToValidate=”Nominated2TextBox” OnServerValidate=”Nomination2CustomValidator_ServerValidate”></asp:CustomValidator>

Note the empty ErrorMessage in the second validator. Combined with display=”none’, that means our ValidationSummary control is only going to display one error message to the user, making it much less confusing. Also notice that ValidateEmptyText is set to true – otherwise, our code will never run.

Then the JavaScript. We’re validating two controls, so even though we use the standard signature the validators are expecting, we’re only interested in the args. I set the TextBoxes’ ClientIDMode to static and used jQuery to get the controls.  (I use jQuery for pretty much all my client-side code).

function CheckNominations(sender, args) {
  if ($(‘#Nominated1TextBox’).val() == “”
      && $(‘#Nominated2TextBox’).val() == “”) {
        args.IsValid = false;
  }
   else {
args.IsValid = true;

   }

}

And, of course, we also need to implement the server-side code for a complete solution:

If String.IsNullOrEmpty(Me.Nominated1TextBox.Text) And
String.IsNullOrEmpty(Me.Nominated2TextBox.Text) Then
        args.IsValid = False
Else
        args.IsValid = True
End If

So now the user must fill in one of the TextBoxes, but can pick either one.  I have been using ASP.NET MVC a lot recently, and it’s nice to go back to Web Forms and see how very easy it is to take built-in controls like the custom validator and use them to meet your specific needs.

Kevin Rattan

For related information, check out these courses from Learning Tree:

Building Web Applications with ASP.NET and Ajax

jQuery: A Comprehensive Hands-On Introduction

Retrieving Data with a JavaScript MVC Framework

This is part of series of posts on building reliable, testable Ajax-enabled applications using a JavaScript MVC framework. In my first post, I discussed why this was a key technology and set up my initial server-side resources in an ASP.NET MVC application. The second post created the test framework for the application, using QUnit for the client-side code and Visual Studio for the server-side code. My last post started to provide the pay-off for all that work: integrating the client-side ViewModel’s data and methods with HTML.

The point of this application is to have the user select a customer from a dropdown list and display the information for that customer, retrieved from the server. Using Knockout as a framework for implementing the MVVM pattern, I’ve created a client-side Customer ViewModel written in JavaScript that exposes three properties (CustId, CompanyName, and City) and the functions to retrieve a Customer (getCustomer) and delete a Customer (deleteCustomer). I’ve also wired up the properties to controls on the page.

But I’ve left out one important part: integrating the code that actually retrieves the data from the server into events in the page. In this post, I’ll take care of two topics: adding a dropdownlist that displays all the customers in the Northwind database and retrieving the appropriate customer object from my server when the user selects a customer from the list. Unlike my previous posts, however, I’ll defer showing the TDD code that proves the code works to the end of the post.

Creating the DropDown List

My first step is to define the dropdown list. In my client-side ViewModel I need a property that will expose the list of Customer objects that I retrieve. I add that to the list of properties that I defined in my ViewModel again using one of Knockout’s functions. Because I’m working with multiple objects, I use Knockout’s observableArray function:

this.Customers = ko.observableArray();

Technically speaking, I probably don’t need to use observableArray here. The observableArray function gives me two-way databinding: changes to the Customers property will be reflected in the page and changes to the array in the page would be reflected in the property. Right now, I don’t intend to let the user add or remove Customers from this property so using observableArray is probably providing more functionality than I need. However, the syntax for updating “observable” properties is different from updating a standard variable: I’m using observableArray here because it makes my life easier to use Knockout’s observable functions on all of my ViewModel’s properties instead of just some of them.

Also on the client, I need a function that uses jQuery’s getJson method to retrieve the customer objects that will populate the property. I add the following function to my client-side Customer ViewModel to do that. In the function, I use my controller variable to build the URL that retrieves the list of Customer objects from the right controller. Once I’ve retrieved the array, I update my Customers property with it:

this.getCustomers = function () {
         $.getJSON("/" + Controller + "/GetAllCustomers",
				null,
				function (custs) {
                        self.Customers(custs);
                    }
                 );
    };

With the client-side code created, I need the server-side method in my controller that returns the JSON objects that will populate the dropdownlist. Rather than return the whole Customer object, I’ll create an anonymous object that holds just the values the dropdownlist needs—CustomerId and CompanyName:

public ActionResult GetAllCustomers()
{
  using (northwndEntities ne = new northwndEntities())
  {
    var res = from c in ne.Customers
	select new  {cName = c.CompanyName, cId = c.CustomerID};
    return this.Json(res.ToArray(), JsonRequestBehavior.AllowGet);
   };
}

My final step in displaying these customers is to bind a dropdownlist on the page and bind it to the Customers property I’ve created on my ViewModel. That markup looks like this:

<select data-bind="options: Customers, 
                    optionsText: 'cName', 
                    optionsValue: 'cId', 
                    optionsCaption: 'Select a  Customer'">
</select>

I’m using several of Knockout’s bindings here to tie the list to the property:

  • options: this binding is passed the name of the property on my ViewModel that holds the list of objects to be used to populate the dropdown list.
  • optionsText/optionsValue: These bindings specify which property on the object are to be used for the text and value attributes in the list. The text attribute specifies the property to be displayed to the user while the value property specifies the property to be passed to any related function
  • optionsCaption: Specifies the value to be displayed in the list when it’s first displayed

I don’t need the selectedOptions binding that lets you specify the list’s current selected value through a property on the ViewModel.

Retrieving the Customer Object

Now I need a client-side method to retrieve the customer object from the server. I write that method so that it accepts a customer Id and updates the ViewModel’s properties with the retrieved data:

this.getCustomer = function (custId) {
        $.getJSON("/" + Controller + "/CustomerById/" + custId,
		null,
		function (cust) {
                self.CustId(cust.CustomerID);
                self.CompanyName(cust.CompanyName);
                self.City(cust.City);
        }
       );
    };

I can’t however, wire this method up to my dropdown list directly. Here’s the syntax that ties the list to a function called fetchCustomer on my ViewModel that runs as soon as the user selects an item in the list:

<select data-bind="event: {change: fetchCustomer}, 
                   options: Customers, …

I’m using Knockout’s event binding which lets me specify an event (change, in this case) to a method (fetchCustomer). Unfortunately, there’s no provision in this binding to pass a parameter to the fetchCustomer function. However, when a function is called through Knockout’s binding process, the function is passed two parameters. The second paremeter includes information about the event and through that parameter’s target property I can access the element that fired the event. From there it’s just a short step to retrieving the current value on the element that invoked the function through its value property.

This code gets the currently selected value from the dropdownlist that calls the function and passes that value to my getCustomer function:

this.fetchCustomer = function (ignore, event) 
    {
      this.getCustomer(event.target.value);
    };

Which raises the question of why have the fetchCustomer method at all? Why not call the getCustomer function from the dropdownlist binding and just extract the selected value from the second parameter? I don’t know that I have a good answer for that question. I’m could say that I’m trying to create a testable ViewModel and the more functions that I have that are tied to my View, the harder it is to test the ViewModel. However, a test for a method like fetchCustomer isn’t hard to construct—this code would do the trick:

var eventTest = { target: { value: "ALFKI"} };
cust.fetchCustomer(null, eventTest);

Still, I’m happier isolating any code that seems to me is related to the user interface into its own methods so I’ll continue with this design.

As I said at the start of this series, Learning Tree has several excellent courses in this area. In Canada, I teach both Learning Tree’s ASP.NET MVC course (which has a chapter on TDD in ASP.NET MVC) and its Design Patterns and Best Practices course (which goes into TDD in more depth). But Learning Tree also has related courses that I don’t get to teach, including ones on JavaScript and jQuery.

There’s lots more I could do here. With Knockout it’s easy to enable and disable portions of your page by binding them to properties on your ViewModel. I also haven’t tried to create or manage multiple objects on the page. However, I have convinced myself (and, hopefully, you) that there’s at least one MVC/MVVM framework out there that lets you create applications in a testable, reliable way even when your application includes client-side code.

Test Code

And here’s the code that I used to test my code. First, the test for client-side code that returns the list of customers:

test("Get All Customers",
                  function () {
                  stop();
                  cust = new Customer("Test");
                  cust.getCustomers();
                  setTimeout(function () 
                            {
                             equals(cust.Customers().length, 2, 
                                        "All customers not retrieved");
                             start();
                            },
                        3000);
                  }
    );

Now the mock server-side method that I used to with that client-side test code:

public ActionResult GetAllCustomers()
{
  List<Customer> custs = new List<Customer>();
  Customer cust = Customer.CreateCustomer("PHVIS", 
              "PH&V Information Services", null);
  cust.City = "Regina";
  custs.Add(cust);
  cust = Customer.CreateCustomer("Other", "Other one", null);
  cust.City = "Winnipeg";
  custs.Add(cust);
  return this.Json(custs.ToArray(), JsonRequestBehavior.AllowGet);
}

Finally, the test code for the production version of the server-side method:

[TestMethod]
public void GetAllCustomersTest()
{
  HomeController hc = new HomeController();
  System.Web.Mvc.JsonResult jres = 
                (System.Web.Mvc.JsonResult) hc.GetAllCustomers();
  dynamic res = jres.Data;
  Assert.AreEqual(96, res.Length, "Unable to retrieve all customers");
}

How To Post To A Remote Server From An ASP.NET Web Form

I recently came an across an interesting problem: I had to post an ASP.NET Web Form to a third party Web site. It turns out to be quite a tricky thing to do – so I thought I’d share my solution with you in case you ever need to do the same thing.

First off: why did I want to post on rather than back?

I am in the process of taking over responsibility for an existing Web site. The site integrates with a bank to take credit cards – and the data needs to be posted.

So why not just use HttpWebRequest?

Because the user has to leave the site, pay and then come back – bringing return parameters back with them.

Ok – so how did the current site work?

It cheated. It’s an ASP.NET Web Forms site, but the page that does the posting is actually PHP!

So – what exactly is the problem with just switching to an ASP.NET Web Form?

Actually, there are several:

  1. ASP.NET Web Forms post back to the same page (or, at a pinch, to other pages on the same server). They don’t post on to third party web sites.
  2. The remote server requires set names for the posted fields – and ASP.NET Web Forms changes these on the client. This problem had two sub-problems:
    1. I had to use runat=”server” controls because the values were dynamic, and
    2. It turns out that ClientIDMode=”Static” fixes IDs, but not names

Q: So how did I make it work?

A: By using jQuery

Here’s what I did:

  1. Added a label telling the user that they needed JavaScript to pay by credit card (or they could pay by bank instead)
  2. Hid the label using jQuery, then showed a button (input type=”button”, not submit) and set its click event to….
  3. Rewrite the form’s action so that it posted to the remote address
  4. Rewrite the control names so that they met the remote sites requirements.
  5. Remove the unwanted form elements such as __VIEWSTATE
  6. Submit the form

Then all I had to do was test it – which I did by creating a page to echo the newly posted values back to the (which also meant I had to set EnableViewStateMac=”false” on the test page).

Here is the JavaScript:

$(function () {
$(‘#needJavaScript’).hide();
$(‘#buttonSubmit’).show().click(function () {
$form = $(‘form:first’);
$form.attr(‘action’, “test.aspx”);
$(‘#__VIEWSTATE, #__EVENTTARGET, #__EVENTARGUMENT’).remove();
$(‘input:hidden’).each(function () {
var original = $(this).attr(‘name’);
var improved = original.substring(original.lastIndexOf(“$”) + 1, original.length);
$(this).attr(‘name’, improved);
});
$form.submit();
});
});

So there you have it – a way to post to a remote server from an ASP.NET Web Forms Web site.

Kevin Rattan

For other related information, check out these courses from Learning Tree:

Building Web Applications with ASP.NET and Ajax

jQuery: A Comprehensive Hands-On Introduction

Integrating Knockout into a Page

In these posts, I’m working through a process that enables me to implement an MVC/MVVM design pattern in my JavaScript code. In my first post, I discussed why I care (primarily to create a testable application) and set up my server side test functions. In the following post, I started creating the client-side ModelView that wrapped up both the Customer data that I wanted to display and the function that would retrieve the data from the server. I also created the test page that would demonstrate that the client-side Javascript ViewModel worked correctly. Now that I know that code works, it’s time to integrate it into a real page. Again, I’m going to take a Test Driven Development approach.

Creating Server-side Resources

My ViewModel’s getCustomer function will use jQuery’s getJson function to retrieve a Customer object. However, the server-side method I accessed from my test page returned a mock Customer object. For the real application, I need a method that returns a real Customer object. I’ll need to test that new Action that returns an actual Customer object, of course, so I add a Test project to my solution with a reference to my ASP.NET MVC project. This test runs the Action method that will (eventually) return the Customer object, catches the result and, through a Dynamic variable, checks to see if it returned the right result:

[TestClass]
public class CustomerMVVM
{
   [TestMethod]
   public void TestRetrieveCustomer()
   {
    HomeController  hc = new HomeController();
     System.Web.Mvc.JsonResult  jres = (System.Web.Mvc.JsonResult) 
        hc.CustomerById("ALFKI");
     dynamic res = jres.Data;
     Assert.AreEqual("Berlin", res.City, "Unable to retrieve customer");
   }
}

Eventually, the Action method in my Controller that passes the test looks like this:

publicActionResult CustomerById(string id)
{
 using (northwndEntities ne = new northwndEntities())
 {
  Customer cust = (from c in ne.Customers
                       where c.CustomerID == id
                    select c).FirstOrDefault();
  ne.Detach(cust);
  return this.Json(cust, JsonRequestBehavior.AllowGet);
  };
}

That’s all I need in my Controller for now, so I’ll return to working in my client.

Binding Data from the ViewModel to the Page

In my View, I need to add a reference to the JavaScript file I created that holds my ViewModel code. I don’t want to put this reference in my Layout View because I only need this code in a few pages. Fortunately, when I set up my Layout View, I added a RenderSection statement in its <head> element. So, in my Customer View, I just need to insert that section with the script reference that I need:

@section Header 
{
 <script src="@Url.Content("~/Scripts/CustomerViewModel.js")" 
    type="text/javascript"></script>
}

In the page, I need to do two things to start using my ViewModel. First, I need to activate Knockout so that it will handle moving data from my ViewModel to elements on the page (and moving data from the elements on the page back to my ViewModel). I do that by instantiating my ViewModel and passing it to Knockout’s applyBindings method as soon as the page is fully loaded. I also set my controller variable so that I when I start accessing my client-side methods, the URL will point to the right controller:

<scripttype="text/javascript">   
    controller = "Home";
    $(function () {
        var cust = new Customer();
        ko.applyBindings(cust);
    });
</script>

I now need to tie the properties on my ViewModel to elements on my page—in this case, I’ll tie most of my data to <input> elements. To make that happen I add the data-bind attribute to the <input> element specifying which of Knockout’s bindings I want to use and the name of the property I’m binding to. Knockout’s text binding is the most useful since it works with both input and span elements (I could also have used Knockout’s value binding). The one exception to tying my data to input elements is my Customer Id property—I don’t want to allow users to update the Customer Id property (at least, not in the initial display) so I use a span element to display it. The following markup ties three elements are to the CustomerId, CompanyName, and City properties on the ViewModel I passed to Knockout’s applyBindings function:

<p>Id: <spandata-bind="text: CustId" /> </p>
<p>Name: <inputtype="text" data-bind="text: CompanyName" /> </p>
<p>City: <inputtype="text" data-bind="text: City" /> </p>

Binding Functions in the ViewModel to the Page

But I’m not limited to binding properties to elements. I can also bind functions on my ViewModel to events fired in the browser. For instance, I want to have a button on the page that allows users to delete the currently displayed customer. First, in my ViewModel I add a new function that calls a server-side method to handle deletions. In this method, I use my controller variable and my ViewModel’s CustId property (through the self variable I set up earlier) to build the URL I use to access the server-side method:

this.deleteCustomer = function () 
   {
    $.getJSON("/" + controller + "/DeleteCustomerById/" +  self.CustId,
         null,
         function (flag) 
              {
              if (flag) 
               {
                 self.CompanyName = "";
                 self.City = "";
               }
               else
	       {
                 alert("delete failed");
               }
              }
             );
    };

Which means that I need to create a mock server-side method to test this method against:

publicActionResult DeleteCustomerById(string id)
{
  return this.Json(false, JsonRequestBehavior.AllowGet);
}

I also need another test function on my test page to test my client-side code:

asyncTest("Delete Customer", function () {
            stop();
            expect(2);
            controller = "Test";
            cust = new Customer();
            cust.getCustomer("ALFKI");
            setTimeout(

			function () {
                            equals(cust.CustId(),"ALFKI", "Customer retrieved");
                            cust.deleteCustomer("ALFKI");
                            setTimeout(

			function () {
                                    equals(cust.CustId(),"", "Customer not deleted");
                                    start();
                                },
                                1000);
                         start();
                        },
                        1000);
        }
        );

Once my client-side code has passed all my tests, I move on to the server to create the production version of the DeleteCustomerById method. In true TDD fashion, I first create a test for the server-side method:

[TestMethod]
public void TestDeleteCustomer()
{
 HomeController hc = new HomeController();
 System.Web.Mvc.JsonResult jres = (System.Web.Mvc.JsonResult)hc.DeleteCustomerById("ALFKI");
				dynamic res = jres.Data;
 Assert.AreEqual(false, res, "Unable to delete customer");
}

Using that test to prove my code works, I create the Action method to use in production:

public ActionResult DeleteCustomerById(string id)
{
  try
  {
    using (northwndEntities ne = new northwndEntities())
    {
      Customer cust = (from c in ne.Customers
                    where c.CustomerID == id
                    select c).FirstOrDefault();
      ne.DeleteObject(cust);
      returnthis.Json(true, JsonRequestBehavior.AllowGet);
    };
  }
  catch
 {
      return this.Json(false, JsonRequestBehavior.AllowGet);
  }
}

The last step is to bind my deleteCustomer function I’ve just added to my ViewModel to the click event of a button. As with binding data, I use the data-bind attribute but this time I use Knockout’s click binding specifying the function on my ViewModel that the button’s click event is to call:

<button type="button" 
    data-bind='click: deleteCustomer'>Delete Customer</button>

However, while I can manipulate the Customer object on my page, I haven’t actually written the code to retrieve that Customer object. That’s in my next post.

Creating a Testable Client-side ViewModel with Knockout

In my previous post, I discussed why I a JavaScript MVC or MVVM framework is essential: It lets you prove, quickly and conveniently, that your code works so that you can assemble applications out of reliable components. In that post I also started on a project to show how one of those frameworks—Knockout—supports the MVVM design pattern. I also created the server-side methods that my application (an ASP.NET View that displays information for a customer selected by the user) would need. However, what I created were mock functions that I could use for testing. In this post, I’ll start to create the client-side resources my application would need while still focussing on testing the code.

Setting Up the Client

My first step on the client (after adding the Knockout library to my Scripts folder, of course) is to add the necessary script references to my layout page to support using Knockout. For testing purposes, I also include a RenderSection that will allow me to selectively add script references on a View-by-View basis. This basic set of references is used by every View:

<head> <meta charset="utf-8" />  
 <title>@ViewBag.Title</title> 
 <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />  
 <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>  
 <script src="@Url.Content("~/Scripts/knockout-2.0.0.js")" type="text/javascript"></script>
 @RenderSection("Header",false) 
</head> 

With those references in place I’m ready to start generating some client-side code. First, I add a Javascript file to my Scripts folder to hold the Customer ViewModel that I’ll developer. Again, to support testing, I add a variable called controller to the file that will let me redirect my server-side requests to my mock methods:

var controller = ""; 

Now I can (finally) start defining my ViewModel, beginning with the properties that hold the data my page will both display and allow users to update. I define those properties using Knockout’s observable function:

var Customer = function (custIdIn) { 
 this.CustId = ko.observable(); 
 this.CompanyName = ko.observable(); 
 this.City = ko.observable(); 

Using the observable function gives me two-way databinding (the ViewModel automatically updates the View’s elements, the View’s elements automatically update the ViewModel). Other Knockout functions support handling arrays and computed values. I don’t have to use the observable function—if I only wanted the data to flow from my Customer ViewModel to the elements on my page, I could skip using the observable function.

I also define a variable to refer to the current value of this (my ViewModel). I’ll need a reference to my ViewModel later and defining self at this point in the ViewModel’s code bypasses any of the ways that this gets redefined:

var self = this; 

My next step is, still in my Customer ViewModel, to define a function that uses jQuery’s getJSON method to retrieve data from my server-side methods. I’m going to call this function getCustomer and have it retrieve the Customer object from my server-side methods. Once the JSON object is retrieved, the code updates my ViewModel’s properties from the JSON object’s properties. This is one of the places that I use the self variable I defined earlier to avoid problems with this being redefined. I also use my controller variable to define the URL used to access the service:

this.getCustomer = function (custId) {
  $.getJSON("/" + controller + "/CustomerById/" + custId, 
 null, 
 function (cust) { 
 self.CustId(cust.CustomerID); 
 self.CompanyName(cust.CompanyName); 
 self.City(cust.City); } ); }; 

Because my CustId, CompanyName, and City properties are really Knockout observable functions, I must use the syntax shown here to update their values. This ensures, for instance, that changes to the CompanyName and City properties will automatically be reflected in any elements in my page that the properties are databound to.

Testing a JavaScript ViewModel

I’ve got enough functionality written at this point to begin testing (too much, actually, for a real TDD approach—I should have started writing my tests before I put any code in my getCustomer function). In my last post, I defined a controller (TestController) and an action method (CustomerViewModelTest) to use for testing. I can now create the View that will be called from that action method (CustomerViewModelTest.cshtml). I use QUnit for testing client-side code, so I need to add the files Qunit needs (a JavaScript file and a CSS file) to my application. However, I’d prefer not to download those files on every page so I don’t add those references my layout View. Instead, in my test View, I add the references to the Header section that my Layout View references. I also add a reference to the JavaScript file holding my Customer ViewModel that I want to test:

@{ ViewBag.Title = "Customer ViewModel Tests"; } 
@section Header { 
 <script src="@Url.Content("~/Scripts/CustomerVieModel.js")" type="text/javascript"></script>  
 <link href="@Url.Content("~/Content/Tests/qunit.css")" rel="stylesheet" type="text/css" />  
 <script src="@Url.Content("~/Scripts/qunit.js")" type="text/javascript"></script>  
} 

In the body of my page, I add in the headers that QUnit needs to execute and display test results:

<form action="/Test/index">
 <h1 id="qunit-header">Customer MVVM Tests</h1>
 <h1 id="qunit-bannder"></h1>
 <div id="qunit-testrunner-toolbar"></div>
 <h2 id="qunit-userAgent"></h2>
 <ol id="qunit-tests"></ol>
</form> 

I can now test my ViewModel using QUnit’s test function. I set my controller variable to direct all my getJson requests to the mock methods on my Test controller. I use jQuery to prevent my tests from running until the page is fully loaded:

controller = "Test"; $(function () { 

That test consists of instantiating my Customer ViewModel, calling its getCustomer method passing a customer Id, and checking to see if the ViewModel’s properties were updated correctly. Since I’m making an asynchronous server-side call, I can’t simply call my getCustomer method and check the property results—my test code might run faster than my server-side call and check the property before the result is returned. To get around that, I use QUnit’s asyncTest and JavaScript’s setTimeout functions to wait for one second before checking the result using QUnit’s equals function:

var cust; test("Get Customer", 
 function () { 
 stop(); 
 cust = new Customer("Test"); 
 cust.getCustomer("ALFKI"); 
 setTimeout( function () { 
 equals(cust.City(), "Regina", "Customer not retrieved"); 
 start(); }, 
 3000); } ); 

I can now run my tests and see the results by calling my CustomerViewModel action method on my TestController (and, of course, my test passes the first time).

At this point I have a testable ViewModel but, of course, that’s not much good unless it supports a real page. That’s what I’m going to look at in my next post. But with this framework in place, I know that I’m building my page with something that works.

If you’re looking for a course with a good introduction to TDD in Visual Studio, Learning Tree’s Design Patterns and Best Practices in .NET course is a good choice. However, Learning Tree’s ASP.NET MVC course devotes a whole chapter to TDD with ASP.NET MVC.

Peter Vogel

Creating Testable Applications with a JavaScript MVC Framework

I love test driven development because, assuming that I’m going to test my code at all, the TDD frameworks make testing much easier and faster—much faster than running the whole application in order to test a few lines of code, for instance. The problem is that my usual JavaScript + jQuery coding practices defeat TDD.

My usual practice is to present users with a page where, for instance, they can select a customer from a dropdown list in order to see the information on that customer. In my JavaScript code, I use the customer Id from the dropdown list to access a service that returns the appropriate JSON object. I then start moving that data to the page using jQuery to select the elements that I want to update with data from the JSON object. And this is where the wheels fall off, at least as far as TDD goes: I can’t claim that I’ve tested my code unless I’ve tested the jQuery code and I can’t test my jQuery code without providing the page with the elements that my jQuery code is updating.

But this is exactly the problem that the Model-View-Controller design pattern is intended to solve: Have all the code/logic in the controller where it can be tested with TDD; have a separate View that is too simple to have much wrong with it and, as a result, doesn’t require testing. What I want, then, is an MVC framework that lets me put all my JavaScript code in a Controller that doesn’t need a View to be tested. Then, in my View, I want to integrate with my controller in a declarative “code-free/logic-free” way that doesn’t require testing. Oh, sure, in my View I can still have what I call “blunders” (e.g. misspelled text; the right data in the wrong place) but I can’t have logic errors that require debugging.

There are several frameworks that will do that. Lately, I’ve been using one of them—Knockout—on a project for one of my clients. Knockout implements the MVVM pattern which includes a ViewModel object that wraps up both the code and the data that drives your View creating, in the ViewModel, a very testable object. Knockout also provides declarative databinding to elements in my page to move data to my elements without code. In addition to Knockout’s basic functionality there’s lots to like about Knockout. For instance, it’s very easy to implement: download the Knockout library from knockoutjs.com, add it to your Scripts folder, and add a script reference to your page. Knockout also relatively agnostic about how you retrieve your data, making it easy to integrate with either WCF or ASP.NET MVC. I’m going to do this in easy stages, starting with this post that sets up my server-side resources.

Setting Up the Server

As an example, I’m going to walk through creating a page with Knockout using ASP.NET MVC. Since, with TDD, I begin with my tests, I first a controller called Test to my application, with an action method to support displaying a View that will let me test my client-side Customer ViewModel:

public class TestController : Controller {
 public ActionResult CustomerViewModel() {
 return View();
} 

My client-side Customer ViewModel is going to need to retrieve Customer objects from my server. Since I’m working in ASP.NET MVC, I’ll add an action method to my controller to support that. However, I’ll just return some mocked up objects for testing purposes. This ensures that, when I’m testing my Customer ViewModel, I really am only testing my Customer ViewModel and not my server-side code or database connection. That mock method looks like this:

public ActionResult CustomerById(string id) {  
 Customer cust = Customer.CreateCustomer(id, "PHVIS", null); 
 cust.City = "Regina";  
 return this.Json(cust, JsonRequestBehavior.AllowGet); 
} 

Learning Tree has several excellent courses in this area. I get to teach both Learning Tree’s ASP.NET MVC course and its Design Patterns and Best Practices course. But Learning Tree also offers courses on JavaScript and jQuery.

Peter Vogel

« Previous PageNext Page »


Learning Tree International

.NET & Visual Studio Courses

Learning Tree offers over 245 IT and Management courses, including a full curriculum of over 15 .NET training options.

Free White Papers

Questions on current IT or Management topics? Access our Complete Online Resource Library of over 65 White Papers, Articles and Podcasts

Enter your email address to subscribe to this blog and receive notifications of new posts by e-mail.

Join 9 other followers

Follow Learning Tree on Twitter

Archives

Do you need a customized .NET training solution delivered at your facility?

Last year Learning Tree held nearly 2,500 on-site training events worldwide. To find out more about hosting one at your location, click here for a free consultation.
Live, online training

Follow

Get every new post delivered to your Inbox.