Archives

Archives / 2021
  • 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.