ASP.Net core 2.0 docker container debugging

I was recently working on setting up a Docker container to run “ASP.Net core 2.0” website in debug mode. I was able to run in regular container hosting mode but after following a tutorial for ASPNet core 1.1, I tried to follow the steps and failed. Since I was new with Docker so it took a while to get it working but here is what I had to do make it work:

Original debugging tutorial suggested:

  1. Create a Docker file with this specific command for CLR debugger:
RUN apt-get update && apt-get install -y unzip

WORKDIR /clrdbg

RUN curl -SL \
        https://raw.githubusercontent.com/Microsoft/MIEngine/getclrdbg-release/scripts/GetClrDbg.sh \
        --output GetClrDbg.sh \
    && chmod 700 GetClrDbg.sh \
    && ./GetClrDbg.sh -v latest -l . \
    && rm GetClrDbg.sh

2. Add following to launch.json file:

"pipeTransport": {            
                "pipeProgram": "/bin/bash",            
                "pipeCwd": "${workspaceRoot}",            
                "pipeArgs": ["-c",            
                    "docker exec -i dev_debug_1 /clrdbg/clrdbg --interpreter=mi"]
            }            

There were two issues. Apparently “clrdbg” doesn’t work with Dotnet core 2.0 (C#) anymore and other issue was that “pipeTransport” now requires debugger path attribute.

Solution:

1. In your docker file, use following command for “vsdbg” (instead of clrdbg):

RUN apt-get update && apt-get install -y unzip

WORKDIR /vsdbg

RUN curl -SL https://aka.ms/getvsdbgsh | bash /dev/stdin -v latest -l /vsdbg

    2. Use following for “pipeTransport” in launch.json for (“.net launch web”)debugging support:

"pipeTransport": { 
   "pipeProgram": "docker", 
   "pipeCwd": "${workspaceRoot}", 
   "pipeArgs": ["exec -i dev_debug_1"], "debuggerPath": "/vsdbg/vsdbg", "quoteArgs": false }

Then just click the “debug run” button in Visual Studio Code, it should work if the container is already running.

Advertisements

Build boost RegEx

I am using the boost library in the persistO ORM with the new C++ features. Everything was working good until I decided to use the ‘RegEx” library to search & replace text in a string. My assumption was that it will just work by adding the library link, like all other boost features were working but it didn’t. I searched the internet and found out that I will need to build the library with my compiler. I couldn’t find any good link to do it easily, except the link which gave a clue to right direction.

I needed the following steps from this article to get it fixed:

  1. Ran “Visual Studio Command Prompt” from tools folder in my VS installation as admin
  2. cd’ed to boost root
  3. Run bootstrap.bat from command line

It took 15-20 minutes for the compiler to compile the whole thing and at the end it generated the library files in:

<boost root>\stage\lib

The next change I required was to change the following libs name:

libboost_regex-vc-mt-1_49          ->   libboost_regex-vc110-mt-1_49
libboost_regex-vc-mt-gd-1_49     ->     libboost_regex-vc110-mt-gd-1_49

Then add the “\stage\lib” path to the project library path.

C++ user library path for Linux

I have just started to learn programming in C++ for Linux platform. I am using QT to create the shared library project and tried to link it with the QT GUI application. As I came from Windows platform, so I was assuming that I will compile the library and it will generate some (.a) file, just like the (.dll) file on Windows platform. But my first mistake was that I started with “Shared LIbrary” project and compiling it doesn’t generate a (.a) file and I didn’t know about the (.so) files. Well it took me quite a while to learn about it through googling but I was glade to finally fix the linking of static and shared linked library on Linux.
In the example below, I will be using the following library file name and path.

Library Name: libTestLogic
Library Extensions: (.a) for static library and (.so) for shared library
Library Path: /home/MyUser/TestPro/TestLogicProject

Static Library Reference in QT .pro file
Open the .pro file of QT GUI App and add following lines. It will be enough to use the static file:

INCLUDEPATH += /home/MyUser/TestPro/TestLogicProject
LIBS += -L/home/MyUser/TestPro/TestLogicProject -lTestLogic

Shared Library
Open the .pro file of QT GUI App and add following lines. This is same as static library:

INCLUDEPATH += /home/MyUser/TestPro/TestLogicProject
LIBS += -L/home/MyUser/TestPro/TestLogicProject -lTestLogic

then we need to open the “MakeFile” in the GUI app folder and find the line for “-rpath”. If it already has library path then add a “:” and the shared library path there. An example of this will be:

LFLAGS        = -Wl,-rpath,/home/MyUser/qtsdk2010/qt/lib:/home/MyUser/TestPro/TestLogicProject

This -rpath is passed to gcc to link the .so and .so.1 files.

Another option for shared library is to specify this library path in the ld.so.conf. That will make sure that we don’t have to modify the MAKE file every time when we reference our same shared library from more projects.

sudo /etc/ld.so.conf

after adding the path to library on a new line in that file, save the file and running following command to configure the linker run-time bindings.

sudo ldconfig

Configure MySQL Database Driver for QT

I am working on a QT project on Ubuntu and I needed to use the MySql database driver for it. In previous versions of QT, it used to be the default installed library but with QT 2010.2 installation (4.6 and above), it is not the default installation. So, it requires to configure the MySql header files and then configure the QT to use the file. Here are the steps which worked for me.

1. First of all, we need to install the MySql Deveoper Libraries on Ubuntu. This will be required by QT to compile the MySql driver.

sudo apt-get install libmysqlclient15-dev

2. After this installation is successful. It will create the folder “/usr/incluce/mysql” in the Ubuntu installation and it will also install the lib files in “/usr/lib/mysql”. We will need this to compile the QT MySql driver:

cd $QTDIR/src/plugins/sqldrivers/mysql
qmake "INCLUDEPATH+=/usr/include/mysql" "LIBS+=-L/usr/lib/mysql -lmysqlclient_r" mysql.pro
make

3. After this, just need to compile the QT code using the “QMYSQL” driver.

ExtJs Grid Dynamic Columns

I had to use ExtJs grid in my recent MVC project. The grid and all other controls are really good, both functionality and usability wise but I stuck into the problem when I needed to make the grid columns dynamic. Most of the examples I found on forums and online tutorials were about using it with fix definition of columns. After searching forums and blogs on Internet, I was able to fix the issue but I realized that there is no thorough tutorial or help to address this issue for ASP.Net MVC. In this blog, I will be giving a complete end to end solution to use dynamic grid columns from ASP.Net. It can be further improved and make more dynamic but it will fulfill most of the requirements.

First of all, I found this ExtJs extension method on ExtJs forums. I didn’t save the link otherwise I would have added the link to that post here. This script needs to be just saved in .js file and referenced from the code. It will take care of most of the heavy lifting on the client side.
Although most of the code is same as I copied it from the forums but I modified the “DynamicColumnModel” function to add my own code for handling the “Column” metadata sent from server. I have commented those line in the code so it can be modified if JSon result returning from server is not in the same format as mine.

//*****************************************
//ExtJS method for dynamic columns
//*****************************************
Ext.data.DynamicJsonReader = function(config)
{
    Ext.data.DynamicJsonReader.superclass.constructor.call(this, config, []);
};

Ext.extend(Ext.data.DynamicJsonReader, Ext.data.JsonReader, {
    getRecordType: function(data)
    {
        var i = 0, arr = [];
        for (var name in data[0]) { arr[i++] = name; } // is there a built-in to do this?

        this.recordType = Ext.data.Record.create(arr);
        return this.recordType;
    },

    readRecords: function(o)
    { // this is just the same as base class, with call to getRecordType injected
        this.jsonData = o;
        var s = this.meta;
        var sid = s.id;

        var totalRecords = 0;
        if (s.totalProperty)
        {
            var v = parseInt(eval("o." + s.totalProperty), 10);
            if (!isNaN(v))
            {
                totalRecords = v;
            }
        }
        var root = s.root ? eval("o." + s.root) : o;

        var recordType = this.getRecordType(root);
        var fields = recordType.prototype.fields;

        var records = [];
        for (var i = 0; i < root.length; i++)
        {
            var n = root[i];
            var values = {};
            var id = (n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
            for (var j = 0, jlen = fields.length; j < jlen; j++)
            {
                var f = fields.items[j];
                var map = f.mapping || f.name;
                var v = n[map] !== undefined ? n[map] : f.defaultValue;
                v = f.convert(v);
                values[f.name] = v;
            }
            var record = new recordType(values, id);
            record.json = n;
            records[records.length] = record;
        }
        return {
            records: records,
            totalRecords: totalRecords || records.length,
            totalProperty: 'totalRecords'
        };
    }
});

Ext.grid.DynamicColumnModel = function(store)
{
    var cols = [];
    var recordType = store.recordType;
    var fields = recordType.prototype.fields;

    //for dynamic columns we need to return the columnInfo from server so we can build the columns here.
    //in this example, the ResultData is a JSON object, returned from the server which contains a ColumnInfo
    //object with "fields" collection. Each Field in Fields Collection holds the information column
    //we are using the "renderer" here as well to show one important feature of displaying the MVC JSon Date
    $.each(store.reader.jsonData.ResultData.columnInfo.fields, function(index, metaValue)
    {
        cols[index] = { header: metaValue.header, dataIndex: metaValue.dataIndex, width: metaValue.width,
            sortable: metaValue.sortable, hidden: metaValue.hidden,
            renderer: function(dtData) { if (metaValue.renderer) { return eval(metaValue.renderer + "('" + dtData + "')"); } else return dtData; }
        };
    });

    Ext.grid.DynamicColumnModel.superclass.constructor.call(this, cols);
};
Ext.extend(Ext.grid.DynamicColumnModel, Ext.grid.ColumnModel, {});
//*****************************************
//End of dynamic columns
//*****************************************

One of the issues which I had faced when using the ExtJs Grid with ASP.Net MVC was the date format of Json serializer. It was returning the date as a special value of “/Date(xxxxx)” format and it needed to be converted before displaying it on the Grid. This is where the “renderer” property of columns comes into play. I had passed the name of the renderer from ASP.net code so there are no long list of checks in the javascript code. It will just call the “eval” and execute whatever server render method is specified. In case of dates, I am using the following javascript code to parse and convert the date into short date time format.

//this method is used to convert the MS JSON date format to the ExtJS Grid Date Column Value
function dateFormatter(dt)
{
    /// <summary>this method is used to convert the MS JSON date format to the ExtJS Grid Date Column Value</summary>
    /// <param name="dt">Actual JSON Date Value</param>
    try
    {
        //microsoft JSON date format needs to convert into Javascript date
        var newdata = dt.replace(/\/Date\((-?[0-9]+)([+-][0-9]+)?\)\//g, "new Date($1)");
        newdata = eval('(' + newdata + ')');
        return newdata.format('m/d/Y');
    }
    catch (e)
    {
        return dt;
    }
}

Enough of ExtJs Code :). Now let’s look at some server side code which will help us build the dynamic columns and the meta data for ExtJs. First thing which I needed was to convert the datatable into an object which can be serialized by Json. If you try to serialize a datatable with ASP Json serializer then it will through the “circular reference” error so this utility method will take the datatable and convert it into a list which can be easily serialized.

/// <summary>
/// Normalizes the datatable into simple collection of row objects, that later on can be used to create the JSON object.
/// </summary>
/// <remarks>
/// whenever we need to return the datatable from view as a JSON object, then we need to first convert that datatable into a collection of rows so that it can be properly serialized.
/// </remarks>
/// <param name="dt">Source datatable that will be used to create the rows collection.</param>
/// <returns></returns>
protected List<Dictionary<string, object>> GetNormalizedRows( DataTable dt )
{
    List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
    Array.ForEach(
        dt.Select(),
        row =>
        {
            Dictionary<string, object> Dictionary = new Dictionary<string, object>();
            foreach ( DataColumn col in dt.Columns )
                Dictionary.Add( col.ColumnName, row[col] );
            rows.Add( Dictionary );
        }
    );
    return rows;
}

Once we have the helper method ready to convert our datatable, we can write a “Controller” action, which will be called from the UI to access the data for the grid.

/// <summary>
/// This method will execute the SQL Query to create the Search results.
/// </summary>
/// <returns></returns>
[HttpPost]
public ActionResult GetData( string anyServerData )
{
        //Execute the query and return the data.
        Datatable resultTable = <get your data from server>;

        //datatables can't be serialized as JSON object, so we need to normalize them and also we need to pass the column meta
        //data information to only show specific grid columns.
        return JSon( new ResultData {
	 new
        {
            GridData = GetNormalizedRows( resultTable ),
            columnInfo = GetColumnMetaData( resultTable )
        } } 
	);
}

That method was really simple and if you have been following it then there was another helper method used in it to get the column meta data, “GetColumnMetaData”. This method will simply loop through the table, create the meta data objects for the ExtJs. It will set the required fields which we need in ExtJs to create the columns.

/// <summary>
/// Extracts the column meta data for ExtJS grid. 
/// </summary>
/// <param name="searchResult"></param>
/// <returns></returns>
private Dictionary<string, object> GetColumnMetaData( DataTable searchResult )
{
    Dictionary<string, object> metaData = new Dictionary<string, object>();
    List<Dictionary<string, object>> colMeta = new List<Dictionary<string, object>>();
    Dictionary<string, object> colDefinition = new Dictionary<string, object>();

    //loop through each datatable column. Get the column name type and other meta specific information and store them in this specific 
    //format so that it can be used by the ExtJS grid on client side.
    foreach ( DataColumn col in searchResult.Columns )
    {
        colDefinition = new Dictionary<string, object>();
        colDefinition.Add( "header", col.ColumnName );
        colDefinition.Add( "dataIndex", col.ColumnName );
        colDefinition.Add( "width", 100 );
        colDefinition.Add( "sortable", true );
        colDefinition.Add( "hidden", false );

	//for datetime columns, we need to render them specially as the date returned from MVC Json is not in format to display to the user
        if ( col.DataType == typeof( DateTime ) )
            colDefinition.Add( "renderer", "dateFormatter" );

        colMeta.Add( colDefinition );
    }

    metaData.Add( "fields", colMeta );
    metaData.Add( "root", "ResultData" );
    metaData.Add( "totalProperty", "results" );
    metaData.Add( "id", "id" );

    return metaData;
}

Finally, to make these all pieces to work, we need to make an AJAX call from client to this Controller action. Any button or link on client can be used to attach a click event handler and in that event handler, we can create the ExtJs store and grid.

//attach a function to the click of HTML Element
$("#btnGetData").click(LoadGridData);

//This will make an AJAX call to the server, passing all the form data and get the result of the search.
function LoadGridData(e)
{
    /// <summary>This will make an AJAX call to the server, passing all the form data and get the result of the search.</summary>
    /// <param name="e">Event object for the clicked Element.</param>

    e.preventDefault();

    //show the AJAX loader... the code is in my previous posts. it is not required so it can be removed if not needed
    objUIHelper.ShowAJAXLoader(true);

    //create the data store to load the data from AJAX web call
    jstore = new Ext.data.Store({
        proxy: new Ext.data.HttpProxy({ url: 'MyController/GetData', method: 'POST' }),
        reader: new Ext.data.DynamicJsonReader({ root: 'ResultData.GridData' }),
        remoteSort: false
    });

    //in case of any AJAX call exception, hide the uiBlocker and show the error message	
    jstore.on('loadexception', function(event, options, response, error)
    {
        //unblock the UI, another helper method to remove the ajax loader
        objUIHelper.HideAJAXLoader();
        
        //show the server error... 
        alert( response.responseText );
    });

    //we need to set the extra params here so it can be used on the grid refresh click
    jstore.on('beforeload', function()
    {
        jstore.baseParams = {
            anyServerData: $("#myHTMLForm").serialize()
        };
    });

    //after the data load in store, create the grid and display the data
    jstore.on('load', function(gridStore)
    {
        //remove any exisitng items from grid div. Grid div is a placeholder to show the extJsGrid
        $("#grid").empty();

        // Reset the Store's recordType
        gridStore.recordType = gridStore.reader.recordType;
        gridStore.fields = gridStore.recordType.prototype.fields;

        //create the paging toolbar
        var bar = new Ext.PagingToolbar({
            store: gridStore,
            pageSize: resultPageSize,
            displayInfo: true,
            displayMsg: 'Displaying record {0} - {1} of {2}',
            emptyMsg: 'No rows to show'
        });

        // Create the grid and bind it with the data store.
        grid = new Ext.grid.GridPanel({
            store: gridStore,
            cm: new Ext.grid.DynamicColumnModel(gridStore),
            selModel: new Ext.grid.RowSelectionModel({ singleSelect: true }),
            enableColLock: true,
            renderTo: 'grid',
            width: 940,
            autoHeight: true,
            title: 'Results',
            bbar: bar,
            pageSize: resultPageSize
        });

        // render the grid on UI
        grid.render();

        //unblock the UI
        objUIHelper.HideAJAXLoader();
    });

    //store's load will call the web URL and load the data
    jstore.load({
        params: {
            start: 0,
            limit: resultPageSize
        }
    });
}

MVC Action Authroization

One good option to apply the action level authorization is to subclass the “AuthorizeAttribute” and in the “AuthorizeCore” method, check for user authorization. If we are using the “Form” authentication then simply we can return “false” and it will redirect the user to the Login Form. In case of windows authentication and running on IIS, it will just keep displaying the Windows Login dialog to the user, so it is better to redirect the user to an Error View for windows Authentication.

[AttributeUsage(AttributeTargets.Method, AllowMultiple=false)]
public class AuthorizeAction : AuthorizeAttribute
{
    private int currAction;

    public AuthorizeAction( int currAction )
    {
        this.currAction = currAction;
    }

    protected override bool AuthorizeCore( HttpContextBase httpContext )
    {
        //check "currAction" against custom database user authroization and set the allowed variable
	bool allowed = true;

	//if user is not authanticated then return the error
        if ( !httpContext.User.Identity.IsAuthenticated )
            allowed = false;

        if ( ! allowed )
        {
            //if it's an AJAX call then simply return the error to the client and show error dialog there
            if ( !string.IsNullOrEmpty( httpContext.Request.Headers["X-Requested-With"] ) && httpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest" )
                return false;
            else
            {
                //in case of a normal URL access, redirect to the special error controller/action.
                httpContext.Response.Redirect( "~/Error/UnAuthorized/" );
                return true;
            }
        }
        else
        {
            return true;
        }
    }
}

Generate HTML string for a MVC View

Sometimes you don’t want to render the view on the standard output stream but you need it to return the output HTML of a view for a JSON call. So, instead of adding the ActionResult of that view to the JSON property, we can force the view to return the output as a string and pass that string as one of the JSON property.
Following Code sample can be used to retrieve the HTML string of a given view and pass the model data to it. The controller context is a required parameter and it can easily be retrieved by the controller.ControllerContext property of the caller.

/// <summary>
/// Generates the HTML string represenation, of a target view.
/// </summary>
/// <param name="c">Controller context is required.</param>
/// <param name="viewName">Target view name.</param>
/// <param name="data">Data object for the view.</param>
/// <returns>HTML string output of the actual view.</returns>
protected string ConvertViewToHtmlString( ControllerContext c, string viewName, object data )
{
    if ( data != null )
    {
        //set view data notifications
        ViewData.Model = data;

        StringWriter output = new StringWriter();
        //find the view to general html string
        ViewEngineResult result = ViewEngines.Engines.FindView( c, viewName, "" );
        ViewContext viewContext = new ViewContext( c, result.View, ViewData, TempData, output );

        try
        {
            //render the view to stringWriter, rather than on Response stream
            result.View.Render( viewContext, output );
        }
        finally
        {
            //release the view so that it can be used by other controllers
            result.ViewEngine.ReleaseView( c, result.View );
        }

        //html string for the view
        return output.ToString();
    }
    else
        return "";
}