Dev Blog - Johan Danforth

I'm Johan Danforth and this is my dev blog - a mix of .NET, ASP.NET, Rest, Azure and some other random coding stuff.

  • Build and Debug ASP.NET MVC 5 Framework Web Application 4.x in VS Code

    Some of us are stuck with older, brownfield web projects based on Framwork 4.x that has to be supported yet for a while. But we’ve also tasted the sweetness of the still not bloated (dream on suckers, it will be bloated) VS Code and want to use it while it’s still pristine and fast. But is it possible?

    Yes, it’s possible

    It requires some editing with the launch.json and tasks.json files in the .vscode folder. Hang on and note that I just got this running last night.

    Fist, open the folder where your “old” web application is located. In the same directory as your .sln file, create a folder named .vscode. In the .vscode folder, a file called tasks.json, which describes one or more build steps.

    tasks.json

    {

        "version": "2.0.0",

        "tasks": [

            {

                "label": "build",

                "type": "shell",

                "command": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Professional\\MSBuild\\Current\\Bin\\msbuild.exe",

                "args": [

                    "${workspaceFolder}/WebApplication1/WebApplication1.csproj",

                    "/t:build",

                    "/p:GenerateFullPaths=true",

                    "/p:Configuration=Debug",

                    "/consoleloggerparameters:NoSummary"

                ],

                "group": {

                    "kind": "build",

                    "isDefault": true

                }

                "presentation": {

                    "reveal": "silent"

                },

                "problemMatcher": "$msCompile"

            },

        ]

    }


    Of course, you will have to replace “WebApplication1” with your project name, and you may also have to change the path to which ever msbuild.exe you want or need to run (bold, italic above).

    To build i VS Code, press CTRL+SHIFT+B and your project should do just that. The task we defined is set to be the default, so VS Code will not ask you for anything, just build. Hopefully.

    Run in IIS Express, 64-bit

    To run this application in IIS Express, add the following task to tasks.json “tasks” array:

    tasks.json (part)

            … stuff before…

            {

                "label": "iisexpress",

                "type": "shell",

                "command": "C:\\Program Files\\IIS Express\\iisexpress.exe",

                "args": [

                    "/path:${workspaceRoot}\\WebApplication1",

                    "/port:5006"

                ],

                "presentation": {

                    "reveal": "silent"

                },

                "problemMatcher": "$msCompile"

            },
           …stuff after…


    Again – replace “WebApplication1” with your project name.

    Note that the iisexpress.exe we point at MUST be the 64-bit version, or we won’t be able to debug later on. The 64-bit version is located in c:\program files\ directory, and the 32-bit version in – you guessed it – the c:\program files(x86)\ directory.

    To get IIS Express going from VS Code, press CTRL+SHIFT+P, to bring up the command prompt, then type/select “Tasks: Run Task” and select “iisexpress”.

    You should see something like this in the VS Code terminal window (you may have to bring it up):

    Starting IIS Express ...
    Successfully registered URL "
    http://localhost:5006/" for site "Development Web Site" application "/"
    Registration completed
    IIS Express is running.
    Enter 'Q' to stop IIS Express


    You can now open a browser and point at http://localhost:5006, your web application should hopefully start.

    Debugging

    Debugging in VS Code is defined in the launch.json file. VS Code has to “attach” to the iisexpress.exe process. So create a launch.json file in .vscode directory, and add this:

    launch.json

    {

        "version": "0.2.0",

        "configurations": [

          {

            "name": ".NET Attach",

            "type": "clr",

            "request": "attach",

            "processName": "iisexpress.exe",

          }

        ]

      }

     


    To “attach” and debug our running application. Press F5 in VS Code. If all is well, the debugger should start running, and you should be able to set breakpoints and whatnot. I’ve not looked at how to debug *.cshtml files yet, but I’m sure it can be done if needed.

    Build, Run and Browse

    It’s possible to do build, run in iis express and start Chrome/Edge in one step for convenience. This is my full tasks.json file for that. On F5 it will run the default task “build run browse” which depends on the tasks “build”, “iisexpress” and “browser”. You might want to exclude the “browser” subtask, but here it is:

    {

        // See https://go.microsoft.com/fwlink/?LinkId=733558

        // for the documentation about the tasks.json format

        //https://bigfont.ca/debug-an-iis-express-web-application-from-vs-code/

        //appcmd add site /name:"WebApplication1" /bindings:https/*5006:localhost /physicalPath:C:\code-test\framework\WebApplication1\WebApplication1\obj\Debug\Package\PackageTmp

        //"C:\Program Files (x86)\IIS Express\appcmd.exe" add site /name:"WebApplication1" /bindings:https/*5006:localhost /physicalPath:C:\code-test\framework\WebApplication1\WebApplication1\obj\Debug\Package\PackageTmp

        "version": "2.0.0",

        "tasks": [

            {

                "label": "build run browse",

                "dependsOn": [

                   "build",

                   "iisexpress",

                   "browser"

                ],

                "group": {

                   "kind": "build",

                   "isDefault": true

                }

            },

            {

                "label": "build",

                "type": "shell",

                "command": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Professional\\MSBuild\\Current\\Bin\\msbuild.exe",

                "args": [

                   "${workspaceFolder}/WebApplication1/WebApplication1.csproj",

                   "/t:build",

                   "/p:GenerateFullPaths=true",

                   "/p:Configuration=Debug",

                   "/consoleloggerparameters:NoSummary"

                ],

                "group": "build",

                "presentation": {

                   "reveal": "silent"

                },

                "problemMatcher": "$msCompile"

            },

            {

                "label": "iisexpress",

                "type": "shell",

                "command": "C:\\Program Files\\IIS Express\\iisexpress.exe",

                "args": [

                   "/path:${workspaceRoot}\\WebApplication1",

                   "/port:5006"

                ],

                "presentation": {

                   "reveal": "silent"

                },

                "problemMatcher": "$msCompile"

            },

            {

                "label": "browser",

                "type": "shell",

                "command": "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",

                "args": [

                   "http://localhost:5006"

               ],

               "problemMatcher": []

           }

       ]

    }

     

     

     

    Hopefully this might help some of you out there to use VS Code with Framework projects and transition over to .net 5 or 6. VS Code is still fast and really, really useful, though VS 2022 looks awesome and seems to outshine VS Code for me.

  • WebView2 Getting Started

    The Microsoft WebView2 control allows you to embed Web Tech in native applications. It’s miles better than the old web browser controls. The WebView2 control is based on the Chromium platform.

    The official docs for the control are found here: https://docs.microsoft.com/en-us/microsoft-edge/webview2/

    Pre-reqs

    Important note (as of 2021-01-20) - ensure you installed the following list of pre-requisites before proceeding:

    I suggest you visit https://www.microsoftedgeinsider.com/download and get the “Edge Canary Channel” that way.

    Install WebView2 SDK in Visual Studio

    Once you’ve created your WebForms or WPF project, install the Microsoft.Web.WebView2 package from Nuget:

    PM> Install-Package Microsoft.Web.WebView2

    Initializing WebView2 Control

    Much about the control is asynchronous, and to make sure the control is loaded and ready, add an InitializeAsync() method to your form constructor, and place the events of interest there, like so:

            public webView2TestForm()
            {
                InitializeComponent();
                InitializeAsync();
            }
    
            async void InitializeAsync()
            {
                webViewControl.NavigationCompleted += WebViewControlOnNavigationCompleted;
                webViewControl.WebMessageReceived += WebViewControlOnWebMessageReceived;
    
                await webViewControl.EnsureCoreWebView2Async(null);
            }
    
    

    Send Message to Web Page

    Easiest way to communicate between the web page and the native application is to send messages. From the native app:

    webViewControl.CoreWebView2.PostWebMessageAsString("proxy.object.added");
    

    To handle messages, the web page need some scripting:

            window.chrome.webview.addEventListener('message',
                event => {
                    console.log('Got message from host!');
                    console.log(event.data);
                    handleMessages(event.data);
                });
    
    

    Send Message to Host

    To send a message from the web page

    window.chrome.webview.postMessage('page.ready');
    

    To handle messages from web page in the host:

            private void WebViewControlOnWebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e)
            {
                var message = e.TryGetWebMessageAsString();
                switch (message)
                {
                    case "page.ready":
                        Trace.TraceInformation("Got page.ready message!");
                        break;
                    default:
                        Trace.TraceWarning("Unknown message received: " + message);
                        break;
                }
            }
    
    

    Proxy Objects

    One of the coolest features availeble is to send a “proxy object” from the native application to the web page. There are some limitations but powerful enough. The best info I’ve found is this: https://docs.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.addhostobjecttoscript 

    The class/object must be exposed as a COM object (!):

        [ClassInterface(ClassInterfaceType.AutoDual)]
        [ComVisible(true)]
        public class ProxyHostObject
        {
            // sample property
            public string Name { get; set; } = "Johan";
    
            // sample method
            public string GetName()
            {
                return Name;
            }
    
            // sample indexed property
            [System.Runtime.CompilerServices.IndexerName("Items")]
            public string this[int index]
            {
                get => _dictionary[index];
                set => _dictionary[index] = value;
            }
            private Dictionary<int, string> _dictionary = new Dictionary<int, string>();
        }
    
    

    The use of the ClassInterface attribute is discussed in the Edge github repo, because the AutoDual value is not recommended in the docs, and even deprecated in dotnet:

    Using AutoDual is strongly discouraged because of the versioning limitations described in System.Runtime.InteropServices.ClassInterfaceAttribute.

    The issue is discussed here: https://github.com/MicrosoftEdge/WebView2Feedback/issues/517

    To create and use the proxy object in the web page:

        async function handleMessages(message) {
            switch (event.data) {
            case 'proxy.object.added':
                {
                    const obj = window.chrome.webview.hostObjects.proxyobject;
                    console.log(obj);
    
                    var name1 = await obj.Name;
                    console.log('name prop: ' + name1);
                    var name2 = await obj.GetName();
                    console.log('name func: ' + name2);
    
                    obj.GetName().then(name => {
                        console.log("GetName promise name: " + name);
                    });
    
                    // Indexed properties
                    let index = 123;
                    obj[index] = "test";
                    let result = await obj[index];
                    console.log(result);
                }
                break;
    
            default:
                console.log("unknown message: " + event.data);
            }
        }
    
    
  • How to setup Continuous Integration and Deploy Pipeline for ASP.NET MVC Framework application to Azure Web App

    In this article I will try to explain in as few steps as possible a way to do CI and deploy from an Azure DevOps repository to an Azure hosted Web App. There are many ways to do this, but this worked for me (2021-01-18).

    I’m creating the CI from the Azure portal, but you can also do it more manually, like described by Scott Hanselman in this blog post, which can be useful to read through: https://www.hanselman.com/blog/azure-devops-continuous-builddeploytest-with-aspnet-core-22-preview-in-one-hour

    Tools and Frameworks used: Visual Studio 2019 Version 16.8.4, .Net Framework 4.7.2

    Pre-reqs: I assume you already have an Azure Web App registered that runs ASP.NET 4.8 or similar. Mine is called ‘ci-test-pipeline’. I also assume you already have a repository and a project in Azure DevOps, again, mine is called ‘ci-test-pipeline’. You can also have your repo in github, the steps should be similar. In this repo, I have a vanilla ASP.NET MVC application created and checked in. In my case ‘ci.test.pipeline.web’ in a ‘ci.test.pipeline’ solution:

    ci pipeline solution

    Initially the pipeline page in DevOps will be empty, unless you’ve already setup a pipeline. To create a CI pipeline you can go about it in a few different ways, but this article describes how to do it from the Web App page in Azure portal.

    Goto the Deployment Center page in the Web App menu, and select to create a Continous Deployment (CI / CD) deployment for ‘Azure Repos’.

    Then just follow the steps, it’s hard to do anything wrong as the wizard helps you with dropdowns along the way. Just make sure you select the correct repo and which ‘Web Application Framework’ you are using. In my case for an ASP.NET MVC .Net Framework solution, select ‘ASP.NET’.


    deplyment center


    deployment center 2

    deployment center 3

    deployment center 4

    Once the pipeline is created, it should look something like this on the deployment center page, with a message of a successful setup. This is still in the Azure portal, under your Web App:

    deployment center 5

    If your project was already checked in, like in my case, this also triggers a first build + deployment in Azure DevOps:

    devops ci pipeline created 1

    And you should eventually get an email from Azure DevOps with a success or failure message. In my case I get a ‘partial success’ because of an error in the pipeline:

    build warning 1

    To view the deails of this message, just look through the detailed steps in the last run in Azure DevOps. You can easily get to these details by clicking the ‘View results’ link/button in the email, and drill into the job details:

    build warning 2

    For some reason the ‘Publish symbols path’ is missing a required task variable – ‘Build.SourceVersion’, but the build succeded and published/uploaded the artifact to a ‘drop container’ and the application is deployed to the Azure Web App. I’m not concerned about this warning right now, just happy it runs through.

    To see the deployed files in the Azure portal, you can go look at the console development tool for the Web App in Azure portal, which is neat:

    azure portal console after first pipeline run

    And you should also be able to view your website at <your web app name>.azurewebsites.net, to see that it works as expected:

    website 1

    To view and edit the pipelines steps created for you by the Azure portal wizard, visit the pipelines menu in Azure DevOps, and select to ‘Edit’ the pipeline:

    devops ci pipeline edit 1

    In edit mode, you see all the steps, and you may opt to disable the ‘Test Assemblies’ and ‘Publish symbols path’, until they are needed:

    devops ci pipeline edit 2

    Remember to save the changes, and try them out again. It’s useful to follow the pipeline job by clicking on the ‘Agent’ that runs the job. the screen updates for every step:

    devops ci pipeline agent working 1

    There are loads of different pipeline steps you can add and customize, which is very helpful if you want to do pre- or post-build steps with your code – like adding build information to your website - which build is deployed and what source code version is actually running.

    That’s enough screenshots for this article. Hope it helps.

    In a follow-up to this blog post, I’ll add build information to the website, and finally add authentication.

  • New features in Dapper.Contrib

    I’ve given the official Dapper.Contrip package some love lately. So now all methods include support for lists! So instead of doing lots of insert calls in a loop, just call connection.Insert(myList); and Dapper/Contrib will interate and insert your entities effectively and fast!

    Dapper.Contrib now contains these methods:

    T Get<T>(id);
    IEnumerable<T> GetAll<T>();
    int Insert<T>(T obj);
    int Insert<T>(IEnumerable<T> list);
    bool Update<T>(T obj);
    bool Update<T>(IEnumerable<T> list);
    bool Delete<T>(T obj);
    bool Delete<T>(IEnumerable<T> list);
    bool DeleteAll<T>();

    For .NET 4.5 users there are also async methods available. For a complete and (almost) up-to-date help page on how Dapper.Contrib works, please visit https://github.com/StackExchange/dapper-dot-net/tree/master/Dapper.Contrib

    Dapper.Contrib can be installed from Nuget, read more at https://www.nuget.org/packages/Dapper.Contrib/

  • Effectively insert list of objects with Dapper

    If you are using Dapper as your sql/object mapper for .Net, you often find yourself inserting lists of objects. There are several ways of doing it, but maybe you're not doing it the fastest way possible (apart from hand-coding)?

    What most people do is iterating over the list add execute the insert for each item like this:

    foreach (var item in myList
    {
        connection.Execute("INSERT INTO MYTABLE VALUES (@A, @B)", item);
    }

    but this is not the fastest way becuse the Dapper Execute() extension takes a list as parameter and iterates for you:

    connection.Execute("INSERT INTO MYTABLE VALUES (@A, @B)", myList);

    I tested by inserting 10.000 simple objects into an SqlCe database and clocked the resuts. The first option took 1.88 seconds, and the second took 1.19 seconds! So, letting Dapper iterate and insert is not twice as fast, but almost!

    To install Dapper, run the following command in the Package Manager Console

    PM> Install-Package Dapper

  • jQuery validate and the comma decimal separator

    Oh this is such a simple and good solution that I must put it on my blog at least for my own future reference. Big THANKS to Lenard Gunda for writing this blog post

    http://blog.rebuildall.net/2011/03/02/jQuery_validate_and_the_comma_decimal_separator

    If you live outside the US and have problems with getting client side validation accepting comma decimal separator in input fields - just overwrite jQuery validation range and number methods with these javascript lines in the end of all your javascript loading.

    $.validator.methods.range = function (value, element, param) {
        var globalizedValue = value.replace(",", ".");
        return this.optional(element) || (globalizedValue >= param[0] && globalizedValue <= param[1]);
    }
     
    $.validator.methods.number = function (value, element) {
        return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:[\s\.,]\d{3})+)(?:[\.,]\d+)?$/.test(value);
    }

  • Bootstrap Image Carousel Fade Transition

    The built in image carousel animation for Bootstrap is a slide, which is nice, but I found this fade transition while Googling, and it seems to work well. I found it here on http://codepen.io/Rowno/pen/Afykb and it’s penned by Roland Warmerdam.

    Html:

    <div class="carousel slide carousel-fade" data-ride="carousel">
        <div class="carousel-inner">
            <div class="item active">
                <img class="img-rounded" src="..." alt="...">
            </div>
            <div class="item">
                <img class="img-rounded" src="..." alt="...">
            </div>
            <div class="item">
                <img class="img-rounded" src="..." alt="...">
            </div>
        </div>
    </div>
    

    Css (less):

    .carousel-fade {
        .carousel-inner {
            .item {
                opacity: 0;
                -moz-transition-property: opacity;
                -o-transition-property: opacity;
                -webkit-transition-property: opacity;
                transition-property: opacity;
            }
    
            .active {
                opacity: 1;
            }
    
            .active.left,
            .active.right {
                left: 0;
                opacity: 0;
                z-index: 1;
            }
    
            .next.left,
            .prev.right {
                opacity: 1;
            }
        }
    
        .carousel-control {
            z-index: 2;
        }
    }
  • Formatting File Upload Input with Bootstrap

    If you’re using file upload forms in your Bootstrap themed website and would like to format the button and the field nicely, take a peek at this article by Cory LaViska. He nails it.

     

    A small example which produces an input-group like this (“Fil” means file in Swedish):

    image

    <div class="editor-label">
        <label>Fil</label>
        <div class="input-group">
            <span class="input-group-btn">
                <span class=" btn btn-default btn-file">
                    välj fil... <input type="file" name="data" id="data">
                </span>
            </span>
            <input type="text" id="valdfil" class="form-control" readonly />
        </div>
    </div>
    
    <script type="text/javascript">
    
        $(document).ready(function () {
            $(document).on('change', '.btn-file :file', function () {
                var input = $(this),
                    numFiles = input.get(0).files ? input.get(0).files.length : 1,
                    label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
                input.trigger('fileselect', [numFiles, label]);
            });
    
            $('.btn-file :file').on('fileselect', function (event, numFiles, label) {
                console.log(numFiles);
                console.log(label);
                $("#valdfil").val(label);
            });
        });
    
    </script>

    You must also add these CSS lines:

    .btn-file {
        position: relative;
        overflow: hidden;
    }
    .btn-file input[type=file] {
        position: absolute;
        top: 0;
        right: 0;
        min-width: 100%;
        min-height: 100%;
        font-size: 100px;
        text-align: right;
        filter: alpha(opacity=0);
        opacity: 0;
        outline: none;
        background: white;
        cursor: inherit;
        display: block;
    }
  • Using FontAwesome in Universal Apps

    image_thumb2Want to use FontAwesome in Universal Apps (both Windows Phone & Windows 8.1). The procedure is similar to how you do it for WPF:

    1) Install-Package FontAwesome

    2) Mark the file /fonts/fontawesome-webfont.ttf with “Build Action” set to “Content” (not “Resource”)

    3) Try out the font like this in a sample Windows Phone main page:

    <Viewbox>
        <TextBlock Text="&#xf09b;"                 FontFamily="fonts/fontawesome-webfont.ttf#FontAwesome" />
    </Viewbox>
    

    And you should see:

    image

    Note that the steps and syntax is a bit different from how you do it in WPF.

  • Using FontAwesome in WPF

    imageWant to use FontAwesome (http://fontawesome.io/) in your WPF application? With a few simple steps you can do it.

    1) Use Nuget and Install-Package FontAwesome

    2) Mark the file /fonts/fontawesome-webfont.ttf and set it’s “Build Action” to “Resource”

    3) Test the font in a simple TextBlock like this:

    <Window x:Class="FontAwesomeWPFBlogTest.MainWindow"         
    xmlns
    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"       
    xmlns
    :x="http://schemas.microsoft.com/winfx/2006/xaml"       
    Title
    ="MainWindow"       
    Height
    ="350"       
    Width
    ="525">     <Grid>         <Viewbox>             <TextBlock Text="&#xf09b;"
                           FontFamily="pack://application:,,,/fonts/#FontAwesome" />         </Viewbox>     </Grid> </Window>

    Run it and you should see this:

    image

    The “hardest” thing is to make sure you enter the right icon-hexcode for the Text property. You can look at the different icons available in the icon-gallery page on http://fontawesome.io/icons/ then check the name of the icon you like. After that, go to the /Contents/font-awesome.css file in your project and look it up there, say for example the paint-brush icon:

    .fa-paint-brush:before {   content: "\f1fc";
    }
    

    The content-value says “\f1fc” which is the hex value of the paint-brush symbol in the font and that is the value you have to enter in the Text-property in your XAML:

    Text=”&#f1fc;”