Sunday 13 October 2019

Using TagBuilder in MVC

I have been started programming MVC again at work after many years focusing more on WPF. So I came accross a class called 'TagBuilder'. This is a handy class for generating markup programatically. Let us create a HTML helper that renders an image tag. It can use TagBuilder to achieve this. First off, we create the HTML helper like this:
using System.Web;
using System.Web.Mvc;

namespace HelloTagBuilderDemo.Helpers
{
    /// <summary>
    /// Sample usage of TagBuilder in MVC
    /// </summary>
    public static class HtmlHelpers
    {
        /// <summary>
        /// Generates an IMG element which is self-closing and uses as src the given path pointing to an image file with a relative path within the web application
        /// and with alternate text
        /// </summary>
        /// <param name="path"></param>
        /// <param name="alternateText"></param>
        /// <returns></returns>
        // ReSharper disable once UnusedParameter.Global
        // ReSharper disable once InvalidXmlDocComment
        public static IHtmlString Image(this HtmlHelper htmlHelper, string path, string alternateText)
        {
            var builder = new TagBuilder("img");
            // ReSharper disable once StringLiteralTypo
            builder.Attributes.Add("src", VirtualPathUtility.ToAbsolute(path));
            builder.Attributes.Add("alt", alternateText);
            var markupResult = builder.ToString(TagRenderMode.SelfClosing);
            return new MvcHtmlString(markupResult);
        }
    }
}

We make use of the VirtualPathUtility.ToAbsolute method to convert a virtual path to an absolute path. Then we make use of the html helper inside a MVC view like this:

@{
    ViewBag.Title = "Home Page";
}

@using System.Web.Mvc.Html
@using HelloTagBuilderDemo.Helpers


<div class="jumbotron">
    <h1>ASP.NET</h1>
    <p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
    <p><a href="https://asp.net" class="btn btn-primary btn-lg">Learn more »</a></p>
</div>

<div class="row">
    <div class="col-md-4">
        <h2>Getting started</h2>
        <p>Harold is at it again, making clones of himself to inflict multiple pain.</p>                
    </div>
    <div class="col-md-4">
        @Html.Image(@"~/Images/haroldatitagain.jpg", "Harold")
    </div>
</div>
And now we have our resulting HTML helper at display, showing also in the screen grab the markup the HTML helper generated for us. [1] Tagbuilder on MSDN: https://docs.microsoft.com/en-us/dotnet/api/system.web.mvc.tagbuilder?view=aspnet-webpages-3.2

Sunday 29 September 2019

Deleting a set of databases with similar names with T-SQL

Devops Sunday. If you end up having many databases in SQL Server and want to get rid of them by matching their names, this T-SQL should help you out.

use master
go
declare @tablestoNuke as table(db nvarchar(100))
insert into @tablestoNuke
select name from sys.databases  
where name like '%SomeSimilarDbNameSet%'
declare @nukedb as nvarchar(100)
declare @nukesql as nvarchar(150)

declare nuker cursor for
select db from @tablestoNuke

open nuker
fetch next from nuker into @nukedb

while @@FETCH_STATUS = 0 
begin
set @nukesql = 'drop database ' + @nukedb
exec sp_executesql @nukesql
fetch next from nuker into @nukedb
end

close nuker
deallocate nuker

print 'All done nuking'


The T-SQL uses a cursor to loop through the database names fetched from sys.databases view on master db and then uses exec sp_executesql to delete the databases, by dropping them.

Tuesday 24 September 2019

Getting started with tests on controllers in AngularJs

Some notes - I had to work with AngularJs tests today and needed to look into Jasmine and mocking enough and import enough to have running tests. I use the Chutzpah test runner to run the Jasmine Tests. The unit test below should get you started writing tests for controllers in AngularJs. The key concepts is to import jQuery, Bootstrap, Angular Animate, Angular-Mocks and your module and controller through using the reference path syntax at the top and then define a beforeEach that capture the _$controller_ and $_rootScope_ variables and using $rootScope.$new() to create a scope. But in my case I also had to specify a provided factory 'bootstrappedData' since my controller reads the 'model' property inside that. By specifying the value this provided factory returns at the top of each tests, I got the amount of DRY I needed to get started testing. I had to this since my controller got the data in an indirect manner, using he factory. I then create a new instance of the controller after updating the 'bootstrappedData' factory.

/// 
/// 
/// 
/// 
/// 
/// 
/// 

describe('someController works', function () {
    beforeEach(module('app'));
    var $scope;
    var $rootScope;
    var $controller;
    var $bootstrappedData;
    var $repository;
    var ctrl;
    var provide;

    beforeEach(module(function ($provide) {
        provide = $provide;
      
    }));

    beforeEach(module(function ($provide) {
        $provide.factory('repository', function () {
            return {
                model: {
                }
            };
        });
    }));

    beforeEach(inject(function (_$controller_, _$rootScope_) {
        $controller = _$controller_;
        $rootScope = _$rootScope_;
        scope = $rootScope.$new();

    }));

    it('Creates the AngularJs controller someController', function () {
        provide.factory('bootstrappedData', function () {
            return {
                model: {
                }
            };
        });

        ctrl = $controller('someController', { $scope: scope });
        expect(ctrl).not.toBe(null);

    });

    it('Method someproperty returns expected', function () {
        provide.factory('bootstrappedData', function () {
            return {
                model: {
                    SomeProperty: '3'
                }
            };
        });
        ctrl = $controller('KontrollskjemaController', { $scope: scope });
        var someprop = scope.isSomeConditionalPropertyReturningTrueIfSomePropertyIsThree;
        expect(someprop).toBe(true);
    });

});


A tip is to add a file called Chutzpah.json and ignoring well known Javascript libraries to only run code coverage on your own code:

{
  "CodeCoverageExcludes": [ "*\\jquery.js", "*\\angular.js", "*\\bootstrap.min.js", "*\\jquery*", "*\\angular-animate.min.js" ]
  //"CodeCoverageIncludes": [ "*\\*Spec.js" ]
}