Looking deep inside OData Controllers

ASP.NET 4.5 has three different class which we can inherits to implements the controllers: Controller, ApiController and ODataController.

In the latest applications that I implemented, because they were SPA, I used rarely the classic Controller (know as MVC controllers) and I developed a huge number of ApiController and ODataController.

The first ones are used to implements the WEB APIs and the second ones if we want a controller that implements OData protocol.

In this post I want to talk about the main architectural differences between these two typologies and the different behaviour inside the source code.

ApiExplorer

The first difference between them is that the ODataController class has the ApiExplorer setting IgnoreApi=true; this is useful to disable the inspection and don’t retrieve the list of the action to the clients that request it:


[ApiExplorerSettings(IgnoreApi = true)]

This is correct when we talk about of libraries like Swagger, that inspect the entire list of the Web APIs in the application and exposes the documentation about those.

With this default setting, the program by default won’t show the documentation for these controllers.

ODataFormattingAttribute

All the OData Controllers has a custom ODataFormattingAttribute applied by default.

This attribute deal with the parsing of the url parameters and send the results in the correct format.

For example, it’s able to parse the OData $format query option (used to specify the format of the results), format the results like xml, json or raw as well as read the OData Metadata header parameter in the request and define the data to be send.

This attribute override the default action value binder with a PerRequestActionValueBinder and the default negotiator with a PerRequestContentNegotiator as well;  these actions have a specific action selector for the OData requests and a negotiator that uses a per-request formatter for the content negotiation.

ODataRoutingAttribute

The main duty of the ODataRoutingAttribute is to override the default action selector with the specific ODataActionSelector, that meet with the routing conventions and formats.

This selector retrieves the path of the request by using a class ODataPath, that represents the path with additional informations about the Edm type and the entity set.

It retrieves the odata routing conventions from the request as well.

Then, with the path and the conventions it retrieves the action to execute in the controller context.

The last duty is instantiate an ODataProviderValueFactory, a custom class that extendes the ProviderValueFactory that parse and retrieves the routing conventions from the OData url.

Results

The last two stuff added to the ODataController are two methods that send the results to the client.

These methods uses a CreatedODataResult class that format the response according with the OData standards.

Then the header with the location informations is added and the content with the informations about EntitySet, Model, Url is created.

 

 

 

 

Advertisements
Looking deep inside OData Controllers

Typescript checking with TSLint

TSLint is a linter for Typescript, then a program that analyse our code to find potential errors and make the code more readable.

The very nice feature is that TSLint has a separate json file, named tslint.json, to configure the analisys process and allow us to setup the rules; we need to put this file in the root of the project and tslint will use that to read the settings.

Once defined the configuration, we’ll embed this in a task runner process like Gulp and we’ll have a complete process to fix all the typescript projects.

TSLint installation

First of all, we need to install the TSLint npm package and the Gulp TSlint plugin:

npm install tslint –save-dev

npm install gulp-tslint –save-dev

These packages will be added to the package.json file in the root of the project.

TSLint configuration

You need to add tslint.json file in the root of the project and compile that; there are many options that you can specify, the nomenclature is clear and it’s very easy to understand what a specific option means.

After some test, this is the configuration file applied:

{
"rules": {
"align": [ true, "arguments", "parameters", "statements" ],
"class-name": true,
"comment-format": [ true, "check-lowercase", "check-space" ],
"curly": true,
"eofline": true,
"indent": [ true, "spaces" ],
"interface-name": [ true, "always-prefix" ],
"jsdoc-format": true,
"label-position": true,
"label-undefined": true,
"member-access": true,
"member-ordering": [
true,
{
"order": "fields-first"
}
],
"no-any": false,
"no-arg": true,
"no-conditional-assignment": true,
"no-consecutive-blank-lines": true,
"no-construct": true,
"no-constructor-vars": true,
"no-debugger": true,
"no-duplicate-key": true,
"no-duplicate-variable": true,
"no-empty": true,
"no-eval": true,
"no-inferrable-types": false,
"no-internal-module": true,
"no-require-imports": true,
"no-shadowed-variable": true,
"no-string-literal": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unreachable": true,
"no-unused-expression": true,
"no-unused-variable": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"no-var-requires": true,
"one-line": [ true, "check-catch", "check-else", "check-finally", "check-open-brace", "check-whitespace" ],
"quotemark": [ true, "double" ],
"radix": true,
"semicolon": [ true, "always" ],
"switch-default": true,
"triple-equals": true,
"typedef": [ true, "arrow-parameter", "call-signature", "member-variable-declaration", "parameter", "property-declaration", "variable-declaration" ],
"use-strict": [ true, "check-function", "check-module" ],
"variable-name": [ true, "check-format", "allow-leading-underscore", "ban-keywords" ],
"whitespace": [ true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type" ]
}
}

TSLint gulp task

The Gulp plugin need to be added to the gulpfile.js file:


'use strict';

var gulp = require('gulp'),
...
tslint = require('gulp-tslint')

gulp.task('tslint', function () {
gulp.src(config.ts)
.pipe(tslint({
formatter: 'verbose'
}))
.pipe(tslint.report({
emitError: true,
sort: true,
fullPath: true,
reportLimit: 10
}))
});

We have some options that we can specify for the report, the reportLimit is very useful when you execute the task for the first time and the report is too long.

Now, you can execute the task with the command:

gulp tslint

In the console the analisys report will be showed:

tslint_report

You can find the project here.

 

 

 

 

 

 

Typescript checking with TSLint

Bootstrapping an Angular 2 application

In an Angular 2 application we have different options to load application and modules, and one of these is SystemJS.

This is an open source project that give us the ability to load bunch of modules and define for each one the corresponding default main module.

Therefore you can use this library to define a default main module for an Angular 2 application; the first step is install this with npm, by adding as a dependency in the package.json file of the project:


{
 ...
 },
 "license": "ISC",
 "dependencies": {
 ...
 "systemjs": "0.19.27",
 ...
 },
 "devDependencies": {
 ...
 }
}

This library allows you to configure you application startup and defaults by using a specific json file.

The file that we need to create is called systemjs.config.js:

(function (global) {
 var map = {
 'app': 'app',
 ...
 };
 var packages = {
 'app': { main: 'main.js', defaultExtension: 'js' },
 ...
 };
var config = {
 map: map,
 packages: packages
 };
 System.config(config);
})(this);

Notice that one of the packages property is app, that is our app selector, and for that we specify the main property, that is the default loader; you can also use this file to configure other stuff, such as bundling or other default main modules.

The last step is create the loader file, that we can call, for example, Main.ts:

import { bootstrap } from '@angular/platform-browser-dynamic';
import { AppComponent } from './App.Component';
bootstrap(AppComponent);

With the last row, we will load as default the AppComponent, that is the main component of our app.

Finally, this is the App.Component.ts file:

import { Component } from '@angular/core';

@Component({
 selector: 'app',
 templateUrl: 'app/views/app.html'
})

export class AppComponent {
 title: string = 'New App';
}

The selector property of the component is the value that we have assigned in the fourth row of the systemjs.config.js above.

 

Bootstrapping an Angular 2 application

Using Gulp in an ASP.NET 4.5 application

The use of a task runner in an ASP.NET application provide a series of advantages about concatenating and minifying CSS and Javascript application files and offers a real and valid alternative to the ASP.NET optimization framework.

One of the most recent task runner is Gulp, that using code over configuration for more readable syntax and node streams for better performances at build time.

Web application

If the referenced project is an ASP.NET 4.5 application, the first steps are adding two files in the project; the first is package.json:

npm

And the second is gulpfile.js:

gulp

Node.js installation

The primary step is to install Node.js, the server-side javascript runtime which will be used by Gulp.

Node.js installation is very simple and offer a GUI to do that; once installed, the next step is the Gulp installation.

Gulp

Npm is the package manager of Node.js and it can be used to install Gulp; a package could be installed locally (in the application folder under node_modules) or globally (the folder specified in the NODE_PATH environment variable); with this second option the package could be used later for other applications.

Therefore, Gulp should be installed globally; opening a command prompt you can perform the installation with the option g (global):

npm install gulp -g

If the project is shared with other developers, is recommended to add gulp as a development dependency of the project; in order to do that, run this command:

npm install gulp –save-dev

Once installed the package.json file will be changed with the new reference of Gulp.

{
"version": "1.0.0",
"name": "ANGULAR-SIGNALR",
"devDependencies": {
"gulp": "^3.9.1"
}
}

Inject

With Gulp inject plugin is possible to manage the js/css references in the application main page.

For example, you can use this plugin to inject javascript files of an angular application in the main page.

In order to do that, you need to first install the plugin:

npm install –save-dev gulp-inject

Than you need to include the plugin in the gulpfile.js and write the task:

'use strict';

var gulp = require('gulp'),
inject = require('gulp-inject')

var config = {
js: 'App/**/*.js',
dist: './dist',
indexDev: 'index.dev.html'
}

//Inject
gulp.task('inject', function (cb) {
var target = gulp.src(config.indexDev);
var sources = gulp.src([config.js]);

return target.pipe(inject(sources))
.pipe(gulp.dest('.'));
});
// End inject

And in the index.dev.html body add the injection placeholders:

<body ng-app="angularSignalR">
<!-- inject:js -->
<script src="/App/App.js"></script>
  <script src="/App/Commons.js"></script>
<script src="/App/Controllers/ModalsController.js"></script>
  <script src="/App/Controllers/OrdersController.js"></script>
<script src="/App/Directives/DecimalNumberValidationDirective.js"></script>
  <script src="/App/Services/NotificationsService.js"></script>
<script src="/App/Services/OrdersService.js"></script>
  <script src="/App/Models/Order.js"></script>
<!-- endinject -->
</body>

Once inject task will be executed, it’ll retrive all javascript file from config.js path and inject them into the html page, between the corrispondent placeholders.

Minification

This is the process to minify vendor css, javascript vendor libraries and javascript application files.

You need to install some plugins:

npm install gulp-clean-css –save-dev

npm install gulp-useref –save-dev

npm install gulp-if –save-dev

npm install gulp-rename –save-dev

Add the new task to the gulpfile.js:

//Useref
gulp.task('useref', ['inject'], function () {
var source = gulp.src('index.dev.html');

return source
.pipe(useref())
.pipe(gulpif('*.css', cleanCss()))
.pipe(gulpif('*.js', uglify()))
.pipe(gulp.dest(config.dist));
});
//End Useref

Add the useref build placeholders in the index.dev.html body:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Angular SignalR Application</title>

<!-- build:css Content/lib.min.css -->
	<link href="/Content/bootstrap.css" rel="stylesheet" />
	<link href="/Content/ui-bootstrap-csp.css" rel="stylesheet" />
	<link href="/Content/loading-bar.css" rel="stylesheet" />
	<link href="/Content/toaster.css" rel="stylesheet" />
<!-- endbuild -->

<!-- build:js Scripts/lib.min.js -->
<script src="/Scripts/jquery-2.2.1.js"></script>
  <script src="/Scripts/jquery.signalR-2.2.0.js"></script>
<script src="/Scripts/bootstrap.js"></script>
  <script src="/Scripts/q.js"></script>
<script src="/Scripts/angular.js"></script>
  <script src="/Scripts/angular-resource.js"></script>
<script src="/Scripts/angular-animate.js"></script>
  <script src="/Scripts/angular-ui-router.js"></script>
<script src="/Scripts/angular-ui/ui-bootstrap.js"></script>
  <script src="/Scripts/angular-ui/ui-bootstrap-tpls.js"></script>
<script src="/Scripts/loading-bar.js"></script>
  <script src="/Scripts/toaster.js"></script>
<!-- endbuild -->
</head>
<body ng-app="angularSignalR">
<toaster-container></toaster-container>

<section class="container">
<div ui-view=""></div>
</section>

<!-- build:js Scripts/app.min.js -->
<!-- inject:js -->
<script src="/App/App.js"></script>
  <script src="/App/Commons.js"></script>
<script src="/App/Controllers/ModalsController.js"></script>
  <script src="/App/Controllers/OrdersController.js"></script>
<script src="/App/Directives/DecimalNumberValidationDirective.js"></script>
  <script src="/App/Services/NotificationsService.js"></script>
<script src="/App/Services/OrdersService.js"></script>
  <script src="/App/Models/Order.js"></script>
<!-- endinject -->
<!-- endbuild -->
</body>
</html>

As you can see, useref is a very powerful plugin; combining that with clean-css and uglify (plugin for minification) permit to generate minified files with few lines of code.

The final index.html page will be generated in dist subdirectory:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Angular SignalR Application</title>

	<link rel="stylesheet" href="Content/lib.min.css">

<script src="Scripts/lib.min.js"></script>
</head>
<body ng-app="angularSignalR">
  <toaster-container></toaster-container>

  <section class="container">

<div ui-view=""></div>

  </section>

  <script src="Scripts/app.min.js"></script>
</body>
</html>

The useref palceholders has been replaced with minified files.

Move result files

The index.html page generated in the dist directory have to be moved in the root directory and the css/js file in the Content/Scripts folders.

You need to install two plugins:

npm install gulp-rename –save-dev

npm install gulp del –save-dev

In order to moving the files, implementation of different tasks is needed:

//Move/Rename
gulp.task('renameIndexDist', ['inject'], function (cb) {
return gulp.src(config.dist + '/' + config.indexDev)
.pipe(rename({
basename: 'index'
}))
.pipe(gulp.dest(config.dist));
});

gulp.task('removeIndexDist', ['renameIndexDist'], function (cb) {
return del([config.dist + '/' + config.indexDev], { force: true });
});

gulp.task('copyDist', ['removeIndexDist'], function () {
return gulp.src(config.dist + '/**/*.*')
.pipe(gulp.dest('.'));
});

gulp.task('moveDist', ['copyDist'], function () {
return del([config.dist], { force: true });
});

gulp.task('renameIndexDev', ['inject'], function () {
return gulp.src('./' + config.indexDev)
.pipe(rename({
basename: 'index'
}))
.pipe(gulp.dest('.'));
});
//End Move/Rename

The task is composed of different subtasks; the first is renameIndexDist, that rename dist/index.dev.html file to dist/index.html; removeIndexDist remove the old index file, than copyDist move the files and modeDist delete dist directory as final step.

RenameIndexDev is a task that will be called in debug mode, when dist directory is not generated and index.dev.html is not minified.

Build configuration

The minification of javascript files is essentially in a release configuration, but not in debug mode, where unminify files are more useful for debugging.

To do that, it’s necessary to distiguish the configuration in the gulpfile.js and execute the correct tasks.

By open the project settings in Visual Studio, it’s possible to define a post-build event command:

build

In the gulpfile.js, add the environment parameter check:

gulp.task('scripts', function () {
if (process.env.NODE_ENV == 'Debug') {
gulp.start('inject', 'renameIndexDev');
}
else {
gulp.start('inject', 'useref', 'moveDist');
}
});

You can find the project here.

Using Gulp in an ASP.NET 4.5 application