Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια

C# and .NET Tips and Tricks

Quests in programming in .NET

Ιούνιος 2013 - Δημοσιεύσεις

Implementing a JSON REST service with ASP.NET MVC

Two years ago, I have written a post about implementing a REST service using WCF. Back then, I didn't know that I was referring to services over the HTTP protocol which are not necessarily REST. Nevertheless, since it seems (from my blog analytics point of view) that people out there when they search for REST services actually imply services over the HTTP protocol or not SOAP more generally I kept the same title in this post.

The point is that you have some kind of client code in javascript and you need to implement in ASP.NET MVC a bunch of services that support getting/putting data from/to your database. In this post we will see how to take advantage of ASP.NET MVC 3 to implement such a JSON service and explore how you can pass data back and forth. I could write this post for ASP.NET MVC4 but in many ways I believe that knowning how to do that in ASP.NET MVC3 helps you understand a lot of the automations that the new MVC version has brought to the picture. Taking also advantage of the WebAPI in ASP.NET MVC4 is an option as long as you realize that the WebAPI supports and sometimes enforces some rules related to the pure "REST" protocol which are not always required.

So in this blog post, simplicity and crude direct appoach are the two motivators behind the proposed solution.

Create a new empty ASP.NET MVC 3 project (empty). Get rid of all the "Contents" folder and leave only the "jquery.min" definition in the Scripts folder (we are keeping this for testing our service)

Create a Controller named "ServicesController" for the services and a controller named "TestingController" for the tests.

Getting .NET objects as JSON (Demo1 Action)

Create and action named in both the "Services" and the "Testing" controllers. Create a view for the "Demo1" action in the "Testing" controller as follows:

    $(document).ready(function () {
        $.get('@Url.Action("Demo1","Services")', {Param1:12,Param2:'John'}, function (data) {
            console.log(data);
        });
    });				
				

In order to support this king of request the passes the parameters "Param1,Param2" to the service and has the JSON object in the "data" parameter the "Demo1" action in the "Services" controller is as follows:

public class Demo1Class
{
    public string Name { get; set; }
    public string Surname { get; set; }
    public List<int> SomeList { get; set; }
}

public JsonResult Demo1(int? Param1,string Param2)
{
    Demo1Class Obj = new Demo1Class();
    Obj.Name = Param2;
    Obj.Surname = Param2;
    Obj.SomeList = new List<int>();
    Obj.SomeList.Add(Param1.GetValueOrDefault());
    return Json(Obj, JsonRequestBehavior.AllowGet);
}
				

Note that with define the parameters as nullable so the action can run even if the client has not supplied them. Also note that there is no need to define the return class. We could just write the code below and still get the required result:

public JsonResult Demo1(int? Param1,string Param2)
{
	List<int> SomeList=new List<int>();
	SomeList.Add(Param1.GetValueOrDefault());
	return Json(new{Name=Param2,Surname=Param2,SomeList=SomeList}, JsonRequestBehavior.AllowGet);
}
				

Sending .NET objects (Demo2 Action)

Now let's say you have the following BLOCKED SCRIPT

$(document).ready(function () {
    var client = {
        name: 'John',
        surname: 'Panagopoulos',
        age: 37,
        values:[11,22,111,2,87]
    };
    $.get('@Url.Action("Demo2","Services")', { id: 11, client: client }, function (data) {
        console.log(data);
    });
});			
				

Developing the following service action (Demo2) will not work.

public class Demo2Class
{
    public string name { get; set; }
    public string surname { get; set; }
    public int age { get; set; }
    public List<int> values { get; set; }
}
public JsonResult Demo2(int? id, Demo2Class client)
{
    // Some server side logic
    return Json(new { result=true }, JsonRequestBehavior.AllowGet);
}

				

This maps the names of the parameters and the properties of the object one by one with the ones passed from the javascript. But it does not work well with the object due to a limitation in the ASP.NET MVC model binder. There are many solutions to that. For me the most straightforward is to include a small jquery extension called $.toDictionary (see also this post) in your html and wrap the parameters with this as follows:

$(document).ready(function () {
    var client = {
        name: 'John',
        surname: 'Panagopoulos',
        age: 37,
        values:[11,22,111,2,87]
    };
    $.get('@Url.Action("Demo2","Services")',$.toDictionary({ id: 11, client: client }), function (data) {
        console.log(data);
    });
});			
				

Note that this can work even if you have nested objects.

Alternatively, you can send the previous request via POST as follows (the ajax command is used in this case so you can also set the cache parameter)

$.ajax({
    url: '@Url.Action("Demo2Post","Services")',
    type: "POST",
    data: $.toDictionary({ id: 11, client: client }),
    success: function (data) {
        console.log(data);
    },
    cache: false
});
				

Your service method in this case is the same as the previous one with the only difference that you need to decorate the action with the [HttpPost] attribute.

And this is it. Now you know how to send,get results from actions that return JSON data using either GET or POST. The demo project can be downloaded here

Posted: Τετάρτη, 26 Ιουνίου 2013 10:26 πμ από iwannis | 0 σχόλια
Δημοσίευση στην κατηγορία:
An introduction to creating scalable Single Page Applications with Knockoutjs and SASS

Everyone who develops web applications (or websites in general) knows that the basic tools for creating simple "Single Page Applications" are HTML5, CSS3, JQuery and a server side framework (such as ASP.NET MVC) for serving data to AJAX requests. Although those are sufficient for implementing SPAs, they tend to lead to implementations that violate basic software design principles, leading to designs that are not easily scalable, difficult to debug and overly complicated.

In this post we will see how we can take advantage of the Knockoutjs and Syntactically Awsome StyleSheets - SASS frameworks in order to design SPAs that respect:

  • The "Single Responsibility Princile - SRP" that states that each software module should be responsible for only one thing in your code. In our case, we will implement the Model-View-View-Model pattern using the Knockoutjs framework to clearly separate the logic that drives the workings of UI from the logic that provides the data/behavior for the UI
  • The "Do not Repeat Yourself Principle - DRY" that states that there should not be any repetition in the implementation of any behavior/logic in your code (or for the fun of it, your implementation should be dry). We will see how "wet" CSS3 stylesheets are becoming and we will use the SASS Framework in order to make them as dry as possible

We will implement a simple SPA of a calculator that performs basic operations (+,-,/,*) and also has one extra operation that requests the calculation to be performed "server side" thus needing the use of an AJAX request in order to get the results.

The initial implementation

Our HTML5 will be as follows:

<div class="container">
    <div class="header">
        <div class="text">
            Demo Calculator Engine
        </div>
    </div>
    <div class="display">
        <input class="operand1 operand" type="text" value="0" />
        <div class="operator">+</div>
        <input class="operand2 operand" type="text" value="0" />
        <div class="result">0</div>
    </div>
    <div class="actions">
        <button class="addition actionButton">+</button>
        <button class="subtraction actionButton">-</button>
        <button class="division actionButton">/</button>
        <button class="multiplication actionButton">x</button>
        <button class="serverOp1 actionButton">o</button>
        <button class="equals actionButton">=</button>
    </div>
    <div class="footer">
        <div class="text">
            (c) 2013 - Ioannis Panagopoulos
        </div>
    </div>
</div>
				

We have separated the "container" div into four zones. The first has the header of the SPA, the second holds the two input boxes for the operands ("operand1","operand2"), shows the operator ("operator") and the result ("result"). The third zone has the buttons that define the operations and change the "operator" in the UI accordingly and the "=" button that performs the operation and updates the result. The last zone is the footer. The CSS3 that beautifies the HTML above is as follows (only some fragments are shown here):

.container{
    width:500px;
    height:280px;
    font-family:Helvetica, Arial, 'DejaVu Sans', 'Liberation Sans', Freesans, sans-serif;
    font-size:14px;
}
.container .header{
    height:60px;
    background-color:#cccccc;
}
.container .header .text{
    font-size:24px;
    text-align:center;
    padding-top:13px;
    color:black;
    font-weight:700;
}	
...		
.container .footer{
    border-top:1px solid #cccccc;
    padding-top:5px;
}
.container .footer .text{
    text-align:center;
}	
...
				

The logic expressed in jQuery is as follows:

$(document).ready(function () {
    $(".container").css('font-size', '30px');
    var operation = undefined;
    var operand1 = 0;
    var operand2 = 0;
    var result = 0;
    function selectOperation(op) {
        operation = op;
        $(".operator").html(operation);
    }
    $(".addition").click(       function () {selectOperation("+");});
    $(".subtraction").click(    function () { selectOperation("-"); });
    $(".division").click(       function () { selectOperation("/"); });
    $(".multiplication").click( function () { selectOperation("x"); });
    $(".serverOp1").click(      function () { selectOperation("o"); });

    $(".equals").click(function () {
        operand1 =parseFloat($(".operand1").val());
        operand2 = parseFloat($(".operand2").val());
        if (operation == "+") result = operand1 + operand2;
        if (operation == "-") result = operand1 - operand2;
        if (operation == "x") result = operand1 * operand2;
        if (operation == "/") result = operand1 / operand2;
        if (operation == "o") {
            $.get('@Url.Action("SOp1","Demo")', {operand1:operand1,operand2:operand2}, function (data) {
                result = data;
                $(".result").html(result);
            });
        }
        $(".result").html(result);
    });
});				

The problems

Is our CSS3 DRY? Not at all. First, the CSS rules repeat the class and id names again and again for each rule (see how the "container" class name is repeated again and again in the CSS). Also, if we want to have a specific property value that we want to use in many rules we have to repeat it in every rule (see the "#cccccc" color value in the CSS file of the example). Moreover, if you want to use ems instead of pixel units to make your view easily scalable, you need to have all your dimensions expressed in ems by using a calculator to convert every value expressed in pixels based on the current font size in each element. But this is obviously a nightmare since, first you are accustomed to work with pixels not ems and second because if you decide to change the font size you have to perform all the em calculations all over again! All the above statements prove that your CSS design, no matter how hard you try, will always be wet.

How about the logic expressed in javascript? Well here you have other issues. First, we will all agree that if someone reads the logic, it is not obvious right away tha this is a calculator. The fact that the user "clicks" a button is a UI concern. The operation performed when the user clicks the button is not a UI concern. But both are mixed in our implementation. Element class and id names are a UI concern and not the application logic's concern. If a designer changes a class name to suit his/her needs the logic will break. Also, we spend a lot of code getting and putting values to our UI elements. All the above also prove that our logic does not obey the SRP principle.

The solutions

To make our CSS stylesheed dry we just need to use the SASS framework. The three powerful features that will come handy for our needs are shown in the following SASS code:

$width:960;
$backcolor: #cccccc;
$baseFont:14;

@function em($target, $context: $baseFont) {
    @return ($target / $context) * 1em;
}

.container{
    font-family:Helvetica, Arial, 'DejaVu Sans', 'Liberation Sans', Freesans, sans-serif;
    font-size:$baseFont * 1px;

    width:em(500);
    height:em(280);

	.header{
		background-color:$backcolor;
		height:em(60);
		.text{
			font-size:em(24);
			text-align:center;
			padding-top:em(13,24);
			color:black;
			font-weight:700;
		}
	}
	...					
				

First, we can define variables for the property values that will get repeated within our CSS ($width,$backcolor) soliving the problem of repeating them again and again. Second, we can nest our rules avoiding the repetition of the selector names (.header is in the .container now so the .container selector is not repeated twice). Third we can define functions that will be executed to provide the property values. Here we have implemented the em function that gets a pixel value and converts it to em based on the supplied font size in pixels. Therefore we can keep working with pixel values with just enclosing them in the em function and the SASS will convert them to ems when needed.

Those three small changes have just made our CSS dry! But wait a minute. How is this converted to CSS? The conversion is not done online but during deployment therefore you do not need to worry about your client having to install something or about any impact in performance. A very useful addin that does that on the fly while you develop in VS2012 is Mindscape's Web Workbench. You write your rules say in a demo.scss file (the SASS code file), you include the demo.css file in your HTML and the tool does the conversion whenever you save the .scss file effectively recreating the actual .css file.

Now let's move to the logic of the application.

Knockoutjs is a framework that lets us implement the MVVM pattern. Therefore we can create a javascript object where all the logic of the UI will reside as follows:

	
var ipplos = ipplos || {};
(function () {
    "use strict";

    ipplos.calculatorViewModelFactory = function (viewModelParameters) {
        return {
            operation: ko.observable(''),
            operand1: ko.observable('0'),
            operand2: ko.observable('0'),
            result: ko.observable(0),
            selectOperation: function (op) {
                this.operation(op);
            },
            performOperation: function () {
                var operand1F = parseFloat(this.operand1());
                var operand2F = parseFloat(this.operand2());

                if (this.operation() == "+") this.result(operand1F + operand2F);
                if (this.operation() == "-") this.result(operand1F - operand2F);
                if (this.operation() == "x") this.result(operand1F * operand2F);
                if (this.operation() == "/") this.result(operand1F / operand2F);
                if (this.operation() == "o") {
                    var _this = this;
                    $.get(viewModelParameters.sop1ServiceURL, { operand1: this.operand1(), operand2: this.operand2() }, function (data) {
                        _this.result(data);
                    });
                }
            }

        }
    }
})();
				

We create a factory (calculatorViewModelFactory) in the "ipplos" namespace that returns an object which is our viewmodel. As you can see this model conveys much more clearly the purpose of the logic by defining the properties and the functions that are used. This factory is thus highly reusable. The only artifacts that we can detect in its code, are those strange ko.observable wrapper functions which are the knocknoutjs way of defining a property that will provide notifications for the UI that it has changed value in order for the latter to update itself.

Having defined that class, then we just need to create an object of that class passing some parameters if needed (usually the ones that will be created server side by some Razor syntax) and attach it to a toplevel element of our view (the HTML5 file) using the ko.applyBindings function as follows (the parameter in this example is the URL of the server side operation endpoint):

	
var viewModelParameters = {
    sop1ServiceURL: '@Url.Action("SOp1","Demo")'
};

var VM = ipplos.calculatorViewModelFactory(viewModelParameters);
ko.applyBindings(VM, $(".container")[0]);
				

Now from within our HTML we can specify "bound" elements to the properties of this object. For example:

<div class="display">
    <input class="operand1 operand" type="text" data-bind="value:operand1" />
    <div class="operator" data-bind="text: operation"></div>
    <input class="operand2 operand" type="text" data-bind="value: operand2" />
    <div class="result" data-bind="text: result"></div>
</div>
<div class="actions">
    <button class="addition actionButton" data-bind="click: function () { selectOperation('+'); }">+</button>
    <button class="subtraction actionButton" data-bind="click: function () { selectOperation('-'); }">-</button>
    <button class="division actionButton" data-bind="click: function () { selectOperation('/'); }">/</button>
    <button class="multiplication actionButton" data-bind="click: function () { selectOperation('x'); }">x</button>
    <button class="serverOp1 actionButton" data-bind="click: function () { selectOperation('o'); }">o</button>
    <button class="equals actionButton" data-bind="click: performOperation">=</button>
</div>
					
				

All the "data-bind" attributes tie a property of the element with the value of the property of the object viewmodel. For example "data-bind='value:operand1'" states that the value of the input element should reflect always the value of the property "operand1" of the viewmodel and vice-versa. Or the "data-bind='click:performOperation'" means that when the event click is produced by the element, the function "performOperation" should be called from the viewmodel.

And this is it! With just the use of the knockoutjs framework we have eliminated all element class,id names from our logic, have clearly specified the behavior of the system in a reusable javascript class and do not have to write any code to transfer data from or to the UI elements. Thus, we can safely say that our implementation now obeys the "Single Responsibility Principle".

And this is it. Two frameworks, the knockoutjs and the SASS framework have helped as reach a much more better implementation in terms of code quality. The resulting code is much more resuable, less prone to bugs and easier to change. The full code of this demo can be downloaded here.