Working with Github private repository using bash on Windows 10

There are times, we want to collaborate with other stakeholders in Github in a private manner. Meaning, we need to work and collaborate on a private Github repository. If you have a private Github private repository ready for collaboration, the most proven way to work with that is to leverage one of the following two options.

  1. Leverage SSH keys at the Github account level. So that you can work with Github private repository using SSH keys. The whole idea is that you will be generating an RSA key pair using SSH Key gen utility, add the private key portion of the key pair to the SSH agent and upload the public key portion of the key pair to the Github account settings. The advantage of this approach is that you have one SSH key defined at the Github account level to manage or work with all the private Github repositories created under that account.githubsshkey
  2. Leverage Deploy Keys at the individual repository level. I have learnt that a Deploy Key can be associated with only one Github repository at this point in time. githubdeploykey

The advantage of the second approach is that you can have a dedicated  key or set of deploy keys for individual repositories.

In this post, i’ll be covering the option #1. Basically i will leverage bash on windows 10 to work with private github repository using SSH keys. My windows 10 is already set up with Ubuntu 18.0.4 for Windows sub-system for linux.  I’m not covering the steps for setting up bash on Windows 10 using Windows subsystem for linux. You can refer microsoft documenation for that. Let’s move to the SSH set up process for Github.

Navigate to the directory in windows 10, where you want to generate SSH key pair.

pic1

Type ‘bash’ on the command prompt. It will launch the bash shell on windows 10. Basically the Windows folder that you have pointed will be mounted to the ubuntu 18.0.4 bash shell.

Now you can generate the SSH key pair using ‘ssh-keygen’ utility.

ssh-keygen -t rsa -b 4096 -C “your_email@example.com

Enter the name of the file for saving the key pair and provide any arbitrary passphrase when prompted.

pic2

Start the ssh on the bash shell. We need to explicty start it, because the run levels of this is different from a standard ubuntu desktop OS. I have learnt that the SSH agent does not get started automatically when you invoke bash on windows 10, unlike a standard ubuntu desktop OS.

eval $(ssh-agent -s)

pic3

Add the private key portion of the generated key pair to the SSH agent.

ssh-add keyname

If you getting a permission error for the generated key pair, the key will not get added successfully to the agent.

pic4

Even if you try to modify the permission of the key using ‘chmod 400’ or ‘chmod 600’ on the mounted directory, it won’t be successful. Becuase i’ve learnt that changing file permissions using chmod on the mounted directory (from windows 10) does not work.

The best way to fix this is to copy the key to a folder under the ubuntu user root directory, not to any windows mounted directory on bash.

Check if the directory ~/.ssh already exists on the bash shell. If not, explicitly create a directory ~/.ssh and exit the bash shell.

Again, navigate to the directory in windows 10 where the key pairs are generated and launch bash from there.

copy private key to ~/.ssh

pic5.JPG

Navigate to ~/.ssh and change permissions using any one of the following commands.

chmod 400 sundargitsshkey

chmod 600 sundargitsshkey

pic6

Copy the public key of the generated key pair (with ‘.pub’ suffix) to New –> SSH Key under Github account settings. Basically copy the content of the public key using any of the text editors and paste there in textbox available in New –> SSH Key under Github account settings.

Navigate to the SSH config file located in ‘/etc/ssh/ssh_config’ and add an entry for ‘IdentityFile ~/.ssh/sundargitsshkey’

sudo nano ssh_config

pic7

Start the SSH agent explicitly.

eval $(ssh-agent -s)

Verify the connectivity to Github using this command ‘SSH -T git@github.com’. You need to user the Github user name as ‘git’. If you try to use your actual Github user name, you’ll get errors.

It will ask you to confirm to accept the warning on authenticity of github.com. Accept it and provide passphrase for private key file when prompted. You’ll get the confirmation for successful authentication to make SSH calls into Github account from your bash shell.

pic8

Now you do git clone, commit and push to any number of repositories under your Github account using SSH, be it a private repository or public repository. This completes the post on working with Github private repository using bash on Windows 10.

 

Installing Mono framework and MonoDevelop IDE on Ubuntu 18.0.4

I’m exploring a lot on .NET cross platform development these days. One of the option other than .NET core, is to leverage Mono framework. Mono framework and MonoDevelop IDE also helps us to develop cross-platfrom .NET applications.  Here are the steps i followed to set up Mono framework and MonoDevelop IDE on Ubuntu 18.0.4.

a)Set up mono repository for ubuntu 18.0.4

sudo apt-key adv –keyserver hkp://keyserver.ubuntu.com:80 –recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF

 
echodeb https://download.mono-project.com/repo/ubuntu stable-bionic main” | sudo tee /etc/apt/sources.list.d/mono-official-stable.list

sudo apt update

b)Install required packages

Install the package mono-devel to compile the code.
sudo apt install mono-devel

Install the package mono-complete to install everything.
sudo apt install mono-complete

Install the package mono-dbg to get the debugging symbols for framework libraries.
sudo apt install mono-dbg

Install package referenceassemblies-pcl for PCL compilation support (this gets installed if your install mono-complete).
sudo apt install referenceassemblies-pcl

Install package ca-certificates-mono to get SSL certificates for https connection (this gets installed if your install mono-complete).

sudo apt install ca-certificates-mono

Install pakage mono-xsp4 to run ASP.NET applications.
sudo apt install mono-xsp4

c)Install monodevelop IDE

The pre-requisite for installing MonoDevelop IDE is to set up the  mono repository for ubuntu 18.0.4 (mentioned in step #a). Then proceeed to IDE installation using apt-get package manager.

sudo apt-get install monodevelop

 

 

 

How to SSH into virtual box guest VM from host

I have set up a virtual box guest VM running ubuntu 18.0.4. I tried to SSH into the ubuntu guest VM from host. It did not work. Here are the simple steps to enable SSH to access ubuntu guest VM from host.

By default, when we create a virtual machine in virtual box, it will come up with a pre-configured NAT adapter.

virtualbox NAT

This will provide the internet connection to the guest VM. This is not enough for enabling SSH. Power off the virutal machine, open network settings in virtual box and add a host only adapter.

Host only adapter

Go to File –> Host Network Manager  and make sure that the selected network adapter for host only network is enabled with DHCP configuration.

DHCP1

DHCP2

The virtual machine that is configured with this Host only network adapter can receive static ip addresses in the range of lower bound and upper bound mentioned in this configuration. In this  case, it is between 192.168.57.3 and 192.168.57.254 (both bounds inclusive).

Switch on the virtual machine and log in.

We need to make changes to the network interfaces file of ubuntu, to reflect the host only adapter and the static ip for the VM.

Navigate to /etc/network/interfaces and add the following lines.

auto enp0s8
iface enp0s8 inet static
address 192.168.57.3
netmask 255.255.255.0

In mycase the host only network adapter is assigned as enp0s8 in the guest VM. In your case, it may be same or different. Based on that set it appropriately.

The next step is to install the openssh server. Run the following commands in the terminal.

auto eth1
iface eth1 inet static
address 192.168.57.4
netmask 255.255.255.0

Restart VM and we can the static IP address of 192.168.57.4 assigned to it.

SSH from host. It should be successful.

SSH guest VM

This completes the post of enabling SSH for ubuntu 18.04 guest VM running in virtual machine.

Docker error response from daemon client.Timeout exceeded

I was trying to set up Docker in my machine running ubuntu 18.0.4. I got this error “Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)”, while issuing ‘Docker login’ command from the terminal.

Screenshot from 2018-12-25 13-05-10.png

I have learnt that the fix for this issue is to add couple of more entires in the resolve.conf file.

Navigate to /etc/resolv.conf

Add the following nameserver entries

nameserver 8.8.8.8

nameserver 8.8.4.4

docker dns change.png

After making this change, i was able to successfuly login to docker hub from the terminal.

 

 

Enable static website hosting in S3

AWS Simple Storage Service (S3) offers one of the powerful capability to host static websites. In this post let’s cover the steps for the same.

Create a sample bucket by name ‘mytestdomain.com’. The convention is that bucket name should match with the website domain name.

In this case the domain name for the static website is mytestdomain.com. The S3 bucket should match that name.

image

Enable public read access to this bucket.

image

Enable static web site hosting for the bucket by selecting ‘Use this bucket to host a static website’ and specifying the index document and error document.


image

Upload the index.html and error.html file and grant the public read access to it. Now access the static website url

provided by S3. It should be in this format.

http://s3bucketname.s3-website-region.amazonaws.com/

It should render the index.html in the browser

image

To render this website with the actual domain name, we need to leverage Route 53 DNS service offered by AWS.

Create a hosted zone for our custom domain.

image

Once the hosted zone is created, S3 presents with list of name servers. It should be mapped with the domain registrar for routing the request through Route 53.

The next step is to create a Record Set for the Hosted Zone bye selecting the Alias Target to the S3 bucket enabled for static website hosting.

image

It takes few minutes for the record set changes to get propagated. After that try accessing the website domain url. It should render the index page. This completes this article.





Client.Timeout exception in docker client

I was trying to pull some docker images from DockerHub. I got this error message “Client.Timeout exceeded while waiting headers”.

image

After doing a bit of debugging and going through online forums, i tried this option of changing the DNS server to Fixed  and restarted the Docker engine.

image

After that I was able to execute all the Docker commands successfully.

image

Back to blogging

For almost three years I have not used this space for sharing my thoughts on technology. I could not do this for various reasons. In a span of three years lot has happened in my professional life and I’ve switched planes and nowadays I’ve diversified myself by exploring into open source technologies as well. We live an interesting time where we see a tremendous explosion in new technologies especially Artificial Intelligence, Big Data, Machine Learning etc. I will be sharing my experiences on what i work and learn from a developer standpoint. Stay tuned !!!

Overview of ASP.NET MVC Views and HTML Helpers

In ASP.NET web forms the request to an URL goes to a physical file on the web server. In ASP.NET MVC application the request to an URL does not represent a physical file, rather it invokes a method in a class (controller action). A controller action in an ASP.NET MVC application typically returns a View most of the times, however it can also perform other actions like returning a file or re-directing to another controller action.

A sample Controller action looks like below

http://serverurl/ControllerName/ActionName

http://serverurl/Home/Index

Home is the default controller that we will get when we create an ASP.NET MVC application in Visual Studio. Index is the default controller action that comes default in Visual Studio.

ASP.NET MVC framework works based on certain conventions. For every controller a sub-folder gets created under Views. For every controller action, a .cshtml file gets created under the respective sub-folder inside Views folder.

Now let’s move to understand HTMLHelpers. ASP.NET web forms have server controls which is used for data entry and UI form processing. In ASP.NET MVC we don’t have server controls, we need to rely on HTML Controls for data entry and UI form processing.

1. BeginForm

The BeginForm helper method denotes the start of an HTML form and it renders an HTML form element. The BeginForm method has 13 overrides and the i’m using the following  version of override in this post

   @using (Html.BeginForm("Index", "Home", FormMethod.Post))
        { 
        
        }

2.RadioButton helper

The Radio button helper helps us to render a RadioButton control. It can be bounded to a model property, which also can be set with values and group for the RadioButton.

 Male @Html.RadioButtonFor(model => model.Sex,"Male")
                Female @Html.RadioButtonFor(model => model.Sex, "Female")

3.Textbox helper

The @Html.EditorFor helper supports us to render a TextBox control for data capture. It can be bound to a model property.

        @Html.EditorFor(model => model.Age)

4.DropDownListControl

The @Html.DropDownListfor helper control supports us to render a dropdownlist control. It can be databound to a IEnumerable>T> which needs to be type casted as SelectList, while performing data binding.

 @Html.DropDownListFor(model => model.PolicyType, ViewData["PolicyType"] as SelectList)

5.CheckBox Control

The @Html.CheckBox control support us to to render a CheckBox control. It can be data bound to a boolean property in the Model.

@Html.CheckBoxFor(model=>model.ReceiveMails)

6.Label Control

The @Html.Label control supports us to render a Label control, whose literal value is bound from a string property in the Model.

 @Html.LabelFor(model => model.Age, new { @class = "control-label col-md-2" })

 

7. ActionLink Control

The @Html.ActionLink control supports us to link to an action method in a controller when the link is clicked.

  @Html.ActionLink("Back to List", "Index")

With the above briefing, i will be creating a View to capture the details for generating an InsuranceQuotation. The Model object definition looks like below :-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MVCDemo2.Models
{
    public class InsurancePolicy

    {

        public string FirstName { get; set; }
        public string LastNane { get; set; }
        public int Age { get; set; }
        public string Sex { get; set; }
        
        public string PolicyType { get; set; }

        public int PolicyTerm { get; set; }
        public int SumAssured { get; set; }

        public bool ReceiveMails { get; set; }


    }
}

My end goal is to create a View (shown below) to capture the details for generating Quotation.

image

The definition of my View ‘GenerateQuote.cshmtl’ looks like below :-

@model MVCDemo2.Models.InsurancePolicy

@{
    ViewBag.Title = "GenerateQuote";
}

<h2>GenerateQuote</h2>



@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>InsurancePolicy</h4>
        <hr />
        @Html.ValidationSummary(true)

        <div class="form-group">
            @Html.LabelFor(model => model.FirstName, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.FirstName)
                @Html.ValidationMessageFor(model => model.FirstName)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.LastNane, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.LastNane)
                @Html.ValidationMessageFor(model => model.LastNane)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Age, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Age)
                @Html.ValidationMessageFor(model => model.Age)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Sex, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                Male @Html.RadioButtonFor(model => model.Sex,"Male")
                Female @Html.RadioButtonFor(model => model.Sex, "Female")
                @Html.ValidationMessageFor(model => model.Sex)
            </div>
        </div>

        

        <div class="form-group">
            @Html.LabelFor(model => model.PolicyType, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(model => model.PolicyType, ViewData["PolicyType"] as SelectList)
                @Html.ValidationMessageFor(model => model.PolicyType)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.PolicyTerm, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.PolicyTerm)
                @Html.ValidationMessageFor(model => model.PolicyTerm)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.SumAssured, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.SumAssured)
                @Html.ValidationMessageFor(model => model.SumAssured)
            </div>
        </div>

        <div class="form-group">

            @Html.LabelFor(model=>model.ReceiveMails)
            @Html.CheckBoxFor(model=>model.ReceiveMails)
           
        </div>

            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Create" class="btn btn-default" />
                </div>
            </div>
        </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

This completes this article. My next post on ASP.NET MVC is here.

 Subscribe to my blog

Various options of passing data from ASP.NET MVC Controller to View

In ASP.NET MVC framework, we have got various options for passing data from Controller to View. Some of the options that i know and used are listed below :-

1. Use a strongly typed model object

2. Use a dynamic type (using @model syntax)

3.Use a ViewBag

This article focuses on explaining the above three methods of passing data from Controller to View.  Let’s create a simple ASP.NET MVC application to demo this one. Since there is a Cricket world cup fever going now, i will be creating a sample MVC application to display list of countries.

I’m adding the below model to the project

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; 

namespace MVCDemo1.Models
{
    public class Countries
    { 

        public String Name { get; set; }
        public string Group { get; set; }
        public string DressColor { get; set; }
        public int NoOfTropies { get; set; }
    }
} 

I’ll be creating a new controller by name Country to handle various types of views(strongly typed views, loosely typed views and views accessing viewbag objects directly for the model Countries.

In the CountryController.cs, i’m setting up the values for CountryCollection

List<Countries> oCountries = new List<Countries> { 
        new Countries{Name="India",NoOfTropies=2,Group="A",DressColor="Blue"},
        new Countries{Name="Australia",NoOfTropies=3,Group="B",DressColor="Yellow"},
        new Countries{Name="SouthAfrica",NoOfTropies=0,Group="C",DressColor="Purple"}

        };

1.Use a strongly typed model object to pass data from Controller to View

In this approach, I’m adding a Controller action by name ‘StrongView’ to return the View for ActionResult.

public ActionResult StrongView()
        {

            return View(oCountries);

        }

Right click on the controller action and Add a View by choosing the Model class, which makes it a Strongly typed view.

image

Run the Solution and the View with CRUD operations look like below.

image

At the top of the View, model is referenced strongly which makes it Strongly typed View.

@model IEnumerable<MVCDemo1.Models.Countries>

Now, let’s move to the approach #2.

 

2. Use a dynamic type (@model syntax) to pass data from Controller to View

Let’s add another controller action by name ‘LooseView’ for passing loosely typed objects from Controller to View.

 public ActionResult LooseView()
        {

            return View(oCountries);
        
        }

Right click on the Controller action, Add View and do not choose any model class, that will make it as dynamically typed.

image

At the top of the View add a reference to dynamically typed view and Grab the Model data from dynamic object.

@model dynamic
@{
    ViewBag.Title = "LooseView";
}

<h2>LooseView</h2>

@foreach(var oCountry in Model)
{
    @oCountry.Name;
}

image

Now let’s move to the approach #3.

3. Use ViewBag to pass the data from Controller to View

Now let’s add a Controller action by name ‘ThirdView’ which sets the Country Collection and returns the View.

  public ActionResult ThirdView()
        {
            ViewBag.Countries = oCountries;
            return View();

        }

Let’s add a View by name ‘ThirdView’

image

I’ll be fetching the Model object from ViewBag and rendering it in the View.

@{
    ViewBag.Title = "ThirdView";
}

<h2>ThirdView</h2>

@foreach (var oCountry in ViewBag.Countries)
{
    @oCountry.Name;
}

image

 Subscribe to my blog

How to get list items in SharePoint 2013 Online using CSOM

In this post, we’ll see how we can fetch the list items of a SharePoint list in SharePoint 2013 online using REST. For the purpose of demonstration, I’ll be using a SharePoint hosted app.

Launch Visual Studio 2013.

File –> New –> Office/SharePoint –> Apps and name it as ‘GetListItemsREST’

I will be accessing the following REST endpoint for getting a web title

https://yoursite.sharepoint.com/_api/web/lists/GetByTitle(‘Shared%20Assets’)/items.

Since the call is initiating from AppWeb to HostWeb, it will present a classical cross-domain scenario, where I will be using the SP 2013 javascript cross-domain libraries to manage this call.

After creating the App project in Visual Studio 2013, the following points need to be considered.

a)The App Permission need to be left with default setting of Internal.

<AppPrincipal>
    <Internal/>
  </AppPrincipal>
  

With this setting, the SharePoint hosted app will have access to the Host Web by default.

b)The App need to be given full-control permission for site-collection. Otherwise, it will not be able to fetch the fields collection.

<AppPermissionRequests>
    <AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="Read" />
    <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="Read" />
    <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web/list" Right="Read" />
  </AppPermissionRequests>

c)The executor object need to be instantiated with the parameter of ‘AppWebUrl’, not the ‘HostWebUrl.  (you’ll see more detailed code in the coming sections). If you instantiate it with ‘HostWebUrl, you will get an error like ‘App web not found’

var executor = new SP.RequestExecutor(AppWebUrl);

d)To access the HostWeb rest end points the url property in the cross-domain call need to be set in this fashion.

AppWebUrl + "/_api/SP.AppContextSite(@target)/web/lists/GetByTitle('Site%20Assets')/items?@target='" + HostWebUrl

Open the App.js and paste the following code

'use strict';

var context = SP.ClientContext.get_current();
var user = context.get_web().get_currentUser();
var HostWebUrl;
var AppWebUrl;


// This code runs when the DOM is ready and creates a context object which is needed to use the SharePoint object model
$(document).ready(function () {
    //getUserName();

    HostWebUrl =
                decodeURIComponent(
                    RetrieveQueryStringParameter("SPHostUrl")
            );
    AppWebUrl =
        decodeURIComponent(
            RetrieveQueryStringParameter("SPAppWebUrl")
    );

    var scriptbase = HostWebUrl + "/_layouts/15/";
    $.getScript(scriptbase + "SP.RequestExecutor.js", execCrossDomainRequest);

});


function successHandler(data) {

    var jsonObj = JSON.parse(data.body);
    var results = jsonObj.d.results;
    var resultcount = results.length;
    var finalresult;

    var i;
    var tempobject;


    for (i = 0; i < resultcount - 1; i++)
    {
        tempobject = results[i];
        finalresult = finalresult+ "Item title is" + tempobject["Title"] + "Item id is " + tempobject["Id"];
        
    }
   
    document.getElementById("message").innerText = finalresult;
  

   
    
   
    
}



function errorHandler(data, errorCode, errorMessage) {


    document.getElementById("message").innerText = "failure";

}

function RetrieveQueryStringParameter(ParamsforRetrieval) {
    var params =
        document.URL.split("?")[1].split("&");
    var strParams = "";
    for (var i = 0; i < params.length; i = i + 1) {
        var singleParam = params[i].split("=");
        if (singleParam[0] == ParamsforRetrieval)
            return singleParam[1];
    }
}

function execCrossDomainRequest() {

    var executor = new SP.RequestExecutor(AppWebUrl);

    executor.executeAsync({
        url: AppWebUrl + "/_api/SP.AppContextSite(@target)/web/lists/GetByTitle('Site%20Assets')/items?@target='" + HostWebUrl + "'",
        method: "GET",
        headers: {
            "accept": "application/json;odata=verbose",
            
        },
        success: successHandler,
        error: errorHandler
    });

}

Run the above piece of code and you will be see the below result.

image

 Subscribe to my blog