Skip to contentSkip to author details

WebAPI

A 3-post collection

Running a .NET Core 2.0 WebApi app on the Raspberry Pi (Raspbian)

Written by Michael Earls
 .NET Core  .NET  WebAPI  raspberry pi  programming

I wanted to create a web api app that answered calls on my Raspberry Pi. The first step I learned was how to install and configure .NET core 2.0 on the Raspberry Pi.

Note - .NET Core only runs on the Raspberry Pi 2 or 3. It will not run on the Raspberry Pi Zero or Zero W.

To get this working, I followed these great instructions from Jeremy Lindsay:

Running a .NET Core 2 app on Raspbian Jessie, and deploying to the Pi with Cake

Once I had this template installed, I simply created a new .NET Core web api app:

Note - Make sure you install the .NET core 2.0 SDK before attempting any of this. .NET Downloads

dotnet new webapi -n WebApiApp

I added the following line of code to the Program.cs file. This will ensure that the Pi answers to all host names (so I can access it from other computers other than localhost).

WebHost.CreateDefaultBuilder(args)  
    .UseStartup()
    .UseUrls("http://*:5000") // add this line
    .Build();

I then copied the following files and folders from the directory created in the sample from the article above to my new WebApiApp folder:

  • build.cake
  • tools
  • publish

I opened up build.cake and changed the correct app name to the name of the project. Here are my configuration settings:

///////////////////////////////////////////////////////////////////////  
// ARGUMENTS (WITH DEFAULT PARAMETERS FOR LINUX (Ubuntu 16.04, Raspbian Jessie, etc)
///////////////////////////////////////////////////////////////////////
var runtime = Argument("runtime", "linux-arm");  
var destinationIp = Argument("destinationPi", "192.168.1.113");  
var destinationDirectory = Argument("destinationDirectory", @"/home/pi/DotNetConsoleApps/WebApiApp");  
var username = Argument("username", "pi");  
var sessionname = Argument("sessionname", "Raspberry Pi");  
var executableName = Argument("executableName", "WebApiApp");

I ensured that the /home/pi/DotNetConsoleApps/WebApiApp directory existed on the Raspberry Pi and then ran the build script from the Powershell terminal:

../build

This used cake to clean, build, and deploy my web api app onto my Raspberry Pi.

Once this was complete, I switched to my PuTTY terminal and typed in ./WebApiApp to start the Web Api app. It started listening on port 5000. I was able to access the Web Api from a browser on my PC by using the IP address of the Raspberry Pi:

http://192.168.1.113:5000/api/values

This displayed the default project api controller output of the template app created in the earlier step.

I can't believe how easy this was. .NET core is really improving the development workflow immensely over previous versions of .NET. This was so much better than what came before.

Update: I was able to get an LED wired up to the WebApi by using this great article from Carlos Mendible:

Note - When you use the Gpio library, you will need to start your WbApiApp using sudo ./WebApiApp due to the need to access IO pins

Toggle Raspberry Pi GPIO Pins with ASP.NET Core 2.0

I wired the LED to physical pin 11 on the Pi. Here's my controller (not much different from his sample):

using System.Collections.Generic;  
using Microsoft.AspNetCore.Mvc;  
using Unosquare.RaspberryIO;  
using Unosquare.RaspberryIO.Gpio;

namespace WebApi.Controllers  
{
    [Route("api/[controller]")]
    public class GpioController : Controller
    {
        // GET api/values
        [HttpGet]
        public IEnumerable Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [HttpGet("{value}")]
        public string Get(bool value)
        {
            var pin = Pi.Gpio.Pin00;
            pin.PinMode = GpioPinDriveMode.Output;
            pin.Write(value);
            return $"pin {pin.BcmPinNumber} set to {value}";
        }
    }
}

Raspberry Pi with LED wired to WebApi (not pictured) The state of the LED after sending a true to the gpio api method.


Basic Authentication with AngularJS and WebAPI Part 2 - The Angular Client

Written by Michael Earls
 AngularJS  ASP.NET  featured  security  WebAPI

Update: I’m an Angular newbie. I’ve learned a bit about Angular JS since this was written. As such, I don’t recommend using $scope as I did, I recommend using Controller as. I also believe that there may be a replacement for $broadcast, but I’m not sure.

Here is a great blog entry about some common Angular JS mistakes from Jeremy Likness.

In part 1, I linked to a few blog entries about getting Basic authentication to work with AngularJS. I outlined what was required to make the suggested idea work in ASP.NET WebAPI, but I didn’t detail what was required in the AngularJS client. The blog entries that I linked to were also very light on details, so I thought I’d put together this blog post to show an end-to-end solution for this problem.

This project is available on GitHub at https://github.com/cerkit/BasicAuthWebApiSample.git

I’m missing a few features that were intended to be included due to my newbie status with AngularJS. In particular, I do not currently have a way to save the failed requests for later to retry them after the user successfully logs in. That will probably have to wait until I get better with AngularJS. Also, there may be a better way to inject the credentials into the web request other than putting the code into the controller. I’ll try to improve on this model at a later date.

To start, let’s take a look at the .config for the app.

/*  
* $http interceptor. 
*
* On 401 response - it stores the request and broadcasts 'event:auth-loginRequired'. 
*/ 
angular.module('app').config(function ($httpProvider){  
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
var interceptor = ['$rootScope', '$q', function (scope, $q) {  
    function success(response) { return response; } 
    function error(response) { 
        var status = response.status; 
        if (status === 401) { 
            var deferred = $q.defer(); 
            var req = { 
                config: response.config, deferred: deferred 
        }; 
        //scope.requests401.push(req); 
        scope.$broadcast('event:auth-loginRequired'); 
        return deferred.promise; 
    } 
    // otherwise return $q.reject(response); 
    } 
    return function (promise) { 
            return promise.then(success, error); 
        } 
    }]; $httpProvider.responseInterceptors.push(interceptor); 
});

Notice that I add a header on line 7 that sends the XMLHttpRequest to the server. If you’ll remember from the last post, this will cause the server to send an “xBasic” authentication method, thereby bypassing the browser’s built-in security dialog. This will allow us to answer the 401 Unauthorized response with our own login dialog.

Here is the template for the login dialog:

<div class="modal h1">  
    <div class="h2 container alert-info modal-body" data-backdrop="static">                 
        Login <div class="alert-danger">{{error}}</div> 
        <ng-form class="form-horizontal"> 
        Username: <input class="form-control" ng-model="username" />                    
        Password: <input class="form-control" type="password" ng-model="password" /> 
        <button class="btn-default" ng-click="login(username, password)">Login</button> 
        </ng-form> 
     </div> 
</div>

This contains the modal class that the dialog requires to be a modal dialog. In order for the dialog to be opened, a request has to be made to an $http resource. This is done by the main controller, but the actual work is done by an $httpProvider interceptor. You can see the interceptor definition on lines 8-27 of the above code. Notice that when the status of a request is 401, it fires the auth-loginRequired event. This indicates that the dialog needs to be shown. This event is answered by a directive that then launches the dialog. Here is the directive:

angular.module('app').directive('loginDialog', function () {  
        return { 
            templateUrl: 'app/templates/loginDialog.html', 
            restrict: 'E', 
            replace: true, 
            controller: 'CredentialsController', 
            link: function (scope, element, attributes, controller){
                scope.$on('event:auth-loginRequired', 
                    function () { 
                        console.log('got login event');     
                        element.modal('show'); 
                    });  
                    scope.$on('event:auth-loginConfirmed',
                        function () { 
                            element.modal('hide');                            
                            scope.credentials.password = ''; 
                        }); 
            } 
        } 
    });

The CredentialsController performs the login:

function CredentialsController($scope, $http, $cookieStore, Base64) {  
        $scope.login = function (userName, password) { 
            var encodedUserNameAndPassword = Base64.encode(userName + ':' + password); 
            $http.defaults.headers.common['Authorization'] = 'Basic ' + encodedUserNameAndPassword; 
            $cookieStore.put('basicCredentials', encodedUserNameAndPassword);  
            $http.get(baseUrl + '/Values') 
                .success(function() { 
                    $scope.$broadcast('event:auth-loginConfirmed');  
                    $scope.password = ''; 
                }) 
                .error(function() { 
                    $scope.error = 'Invalid Login'; 
                }); 
        }; 
    };

Notice that the login method calls the event for auth-loginConfirmed. This will cause the modal dialog to be hidden. It is also answered by the SampleController so that it can refresh its data.

We’ll then see the login-dialog directive being used at the bottom our index.html page. This is there just so that we can respond to the event and show the dialog.

<html ng-app="app">  
    <title>Sample Angular Client for Basic Authentication</title> 
    <meta name="description" content=""> 
    <meta name="viewport" content="width=device-width, initial-scale=1"> 
    <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
    <link rel="stylesheet" href="css/normalize.css"> 
    <link rel="stylesheet" href="css/main.css"> 
    <!-- Latest compiled and minified CSS for Bootstrap --> 
    <link href="css/bootstrap.min.css" rel="stylesheet" /> 
    <!-- Optional theme --> 
    <!--<link href="css/bootstrap-theme.min.css" rel="stylesheet" />--> 
    <link href="css/bootstrap.flatly.min.css" rel="stylesheet" /> 
    <script src="js/vendor/modernizr-2.6.2.min.js"></script> 
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.js"></script> 
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular.js"></script>
    <script>window.jQuery || document.write('<script src="js/vendor/jquery-1.10.2.min.js"></script>')</script>
    <script src="js/plugins.js"></script> 
    <script src="js/bootstrap.min.js"></script> 
    <script src="js/vendor/angular-resource.min.js"></script>
    <script src="js/vendor/angular-cookies.min.js"></script> 
    <script src="js/vendor/angular-timer.min.js"></script> 
    <script src="app/app.js"></script> 
    <script src="app/factories/base64-factory.js"></script> 
    <script src="app/controllers/controllers.js"></script>  
    <body ng-controller="SampleController"> 
        <div class="h2 label-info">{{currentUser | uppercase}}</div> 
        <ul> 
            <li ng-repeat="value in Model"> {{value}} </li> 
        </ul> 
        <button class="btn-default h2" ng-click="logout()">Logout</button>     
        <login-dialog />  

Since we’re using the SampleController, let’s take a look at what it does to get the data:

var baseUrl = 'http://localhost:49587/api';  
    angular.module('app').controller('SampleController', function ($scope, $http, $cookieStore, Base64) { 
        $scope.refreshData = function () { 
            //Used to display the data 
            if ($cookieStore.get('basicCredentials')) {
                $http.defaults.headers.common['Authorization'] = 'Basic ' + $cookieStore.get('basicCredentials'); 
            } 
            $http.get(baseUrl + '/Values')
                .success(function (data) { 
                    $scope.Model = data; 
                    $scope.loading = false; 
                    $scope.currentUser = Base64.decode($cookieStore.get('basicCredentials')).split(':')[0]; 
                }) 
                .error(function () { 
                   $scope.error = "An Error has occurred while loading data";
                   $scope.loading = false; 
                }); 
        } 
        $scope.loading = true; 
        $scope.refreshData(); 
        $scope.logout = function () {
            $cookieStore.remove('basicCredentials'); 
            $scope.currentUser = null; 
            $scope.Model = null; 
            $http.defaults.headers.common.Authorization = '';
            $scope.refreshData(); 
        } 
        $scope.updateValue = function (model) { 
            $http.put(baseUrl + '/Values', model); 
            window.setTimeout(function () { 
                $scope.refreshData() 
            }, 1000);  
        } 
        $scope.$on('event:auth-loginConfirmed', function () {
            $scope.refreshData(); 
        }); 
    });

The refreshData() function checks to see if there’s a credentials cookie. If so, it sends the credentials along in the Authorization header. This is the part that should be changed. I think it needs to go in the interceptor, but I haven’t quite figured out how to do it. After setting credentials, the controller has various functions for dealing with the data. It also sets the currentUser property on the scope so that it can be displayed on the home page.

This should illustrate the end-to-end process of enabling basic authentication on an AngularJS application when used with ASP.NET WebAPI.

I’ve been very happy with the results. Just make sure you secure all of this behind SSL.


Enabling Basic Authentication for Angular and jQuery clients for your ASP.NET WebApi

Written by Michael Earls
 ASP.NET  featured  security  WebAPI

I have been working on a WebAPI for a client over the past few months and I’ve successfully implemented Basic authentication on my WebAPI and connected to it using a Xamarin Android client.

I’ve come to a point where I need to start supporting AngularJS clients, but I don’t like how the browsers each have their own default login dialogs that are ugly. I found a great blog entry solving this exact issue, but the author wrote their server side in Sinatra.

Here is the blog entry with the situation and solution:

http://olefriis.blogspot.com/2014/01/http-basic-authentication-in-angularjs.html

You’ll need to implement Basic authentication on your WebAPI to make this work. To implement Basic authentication on your ASP.NET WebAPI, follow the instructions here:

http://www.asp.net/web-api/overview/security/basic-authentication

One thing to make sure you do (in Web.config) is change the

type="WebHostBasicAuth.Modules.BasicAuthHttpModule, BasicAuth"

to reflect the project name and binary name of your project (your’s shouldn’t be named WebHostBasicAuth.Modules.BasicAuthHttpModule. It will be the name of your project instead.

type="{ProjectName}.Modules.BasicAuthHttpModule, {BinaryName}

It turns out that the changes required to make the solution outlined in Ole Friis Østergaard’s post is very easy to implement in ASP.NET.

Here is the code you need to change in the Basic Authentication Implementation from above:

// If the request was unauthorized, add the WWW-Authenticate header  
// to the response. 
private static void OnApplicationEndRequest(object sender, EventArgs e)  
{
    var response = HttpContext.Current.Response; 
    // see if the request sent an X-Requested-With header (Non-Browser request - 
    // used by jQuery and Angular implementations to prevent the browser from 
    // presenting the default Login dialog) 
    var request = HttpContext.Current.Request; 
    string authType = "Basic"; 
    if (response.StatusCode == 401) 
    { 
        if (request.Headers.AllKeys.Contains("X-Requested-With")) 
        { 
            if (request.Headers["X-Requested-With"] == "XMLHttpRequest") 
            { 
                authType = "xBasic"; 
            } 
        } 
        response.Headers.Add("WWW-Authenticate", string.Format("{0} realm="{1}"", authType, Realm));
    } 
}

That’s it! Now, when you pass in the X-Requested-With header value of "XMLHttpRequest", you’ll get back a WWW-Authenticate header with a type of “xBasic” instead of “Basic”. That will cause the browser to ignore the request and suppress the login dialog, letting you display your own pretty dialog.

I have started a GitHub project that has my Sample WebAPI in it. I’ll be updating that to include the AngularJS code as I create it to demonstrate exactly how to pull this off since Ole’s post is light on details.

Here is the GitHub project:

https://github.com/cerkit/BasicAuthWebApiSample.git