As you have noticed, you need Visual Studio Enterprise for live unit testing, or Jetbrains Rider, or some Visual Studio Code “hacks”. Here is a method to have coverage of .Net core with a global tool:

Daniel Palme has a global tool version of Report Generator. You should install it once with:

dotnet tool install -g dotnet-reportgenerator-globaltool

dotnet tool install dotnet-reportgenerator-globaltool --tool-path tools

You can then run it with `reportgenerator` so after building I run:

dotnet test --filter FullyQualifiedName~UnitTests /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[*Test*]" /p:ExcludeByAttribute="GeneratedCodeAttribute"
reportgenerator "-reports:**\coverage.opencover.xml" "-targetdir:C:\Temp\Reports\" "-reporttypes:HTML"
Start-Process -FilePath "C:\Temp\Reports\index.htm"

Of course you can go to the project properties and add the three lines of powershell to a file in the root of your solution and add to the build events tab as post-build:

Powershell -File "$(SolutionDir)nameOfPowershellscript.ps1"

Good luck!

Pin on pinterest Plus on Googleplus Post on LinkedIn
0 Comments

I have just enabled the MariaDB 10.x package and installed the famous Heidi SQL from the Microsoft Store (because of the auto update and roaming settings etc.)

So I tried to connect to it. The MariaDB 5.x uses port 3306, but the 10.x uses 3307 (minor detail) However, I could not connect, because by default only localhost connections are enabled.

So I had to SSH into the nas and fix it. But using SSH did not work how it used to. I used Ubuntu (also from the Microsoft store) to `ssh myadminname@localipofnas` but got a cypher not accepted/available message. It turns out that the Synology has disabled several old insecure ciphers. So I had to provide a –c and an algorithm to use in order to get it to work.

“no matching cipher found. Their offer: aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc”

I used `-c aes128-cbc` because it was the first option in the list

Once logged in, I had to launch MariaDB mysql and give the user access within the lan and create a database:

  • Search mysql (/usr/local/mariadb10/bin/mysql)
  • Enter to mariadb with command line: ./mysql -u root –p
    • Use the password
  • Check user's:
    • SELECT User, Host FROM mysql.user WHERE Host <> 'localhost';
  • Granting User Connections From Remote Hosts:
    • GRANT ALL PRIVILEGES ON . TO 'root'@'192.168.1.%' IDENTIFIED BY 'my-new-password' WITH GRANT OPTION;

Found it on: https://stackoverflow.com/a/51277323/169714

You can also use localhost or % instead of the ip. It depends on what you are trying to do Smile

MariaDB is now ready for some .Net Core

(Only my Synology NAS does not support Docker to run .Net Core…)

I am having doubts if I should try to work around it or just use a Raspberry Pi for my .Net core code.


Good luck, hope it saved someone some time!

Pin on pinterest Plus on Googleplus Post on LinkedIn

I have blogged before about this Excel Nuget package where you don’t need to use interop and have Excel installed on the server. And my journey to start this Azure Function. This is because the most recent Excel format uses xml under the cover in a zipped file stored as a file with an xlsx extension. Since you do not have hard disk access in a serverless environment like Azure Functions you need to generate the Excel in memory (or store stuff in blob storage). I chose the in memory to leave no footprints or take up space in the cloud.

I wanted to use an Azure function to have it run in the cloud. Not being dependent on a Server which needs updates, reboots etc. Since the database already is in the Azure Cloud (Azure SQL) this seems a good/perfect fit.

I got the option to go for Azure function v1 or v2 which is in preview. So this was a nice opportunity to use the v2 and .Net Core/Standard. https://docs.microsoft.com/en-us/azure/azure-functions/functions-versions

The v2 also has support for the Office365 Graph. But that was out of (my) scope.

I took a timer based project because I wanted it to send an overview of invoices on a monthly basis. The Timer based project has a timer as data annotation based on CRON scheduling. There is however a small difference. Instead of 5 “fields” the Azure function has 6. It also let’s you schedule the seconds.

https://en.wikipedia.org/wiki/Cron#CRON_expression

So not just: minutes, hours, day of month, month, day of week, year but seconds, minutes, hours, day of month, month, day of week, year. Of course the order is really important. https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer#cron-expressions

I used this Nuget for the Excel export https://www.nuget.org/packages/EPPlus/

it has .Net Core support and will work perfectly.

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Net;
using System.Net.Mail;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using OfficeOpenXml;

namespace MonthlyMailInvoices
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static void Run([TimerTrigger("10 0 0 1 * *")]TimerInfo myTimer, TraceWriter log)
        {
            log.Info($"C# Timer trigger function executed at: {DateTime.Now}");

            var com = new SqlCommand("SELECT * FROM [dbo].[INVOICES] where invoicedate > @startdt and invoicedate < @enddt");

            com.Parameters.AddWithValue("startdt", DateTime.Now.AddMonths(-1));
            com.Parameters.AddWithValue("enddt", DateTime.Now.AddDays(-1));

            var dt = new DataTable();

            using (var con = new SqlConnection("connectionstring goes here"))
            {
                con.Open();
                com.Connection = con;
                var da = new SqlDataAdapter(com);
                da.Fill(dt);

                log.Info($"start: {DateTime.Now.AddMonths(-1)} and end { DateTime.Now.AddDays(-1) } gave {dt.Rows.Count}");
            }

            using (var wb = new ExcelPackage())
            {
                wb.Workbook.Worksheets.Add("Our company");
                var ws = wb.Workbook.Worksheets[0];

                FillData(ws, dt, "Our company B.V.");

                var msg = new MailMessage();
                msg.To.Add("mymail@companydomain.com");
                msg.Subject = "Montly invoices";
                msg.From = new MailAddress("the@cloud.com");
                msg.Body = $"Invoices from {DateTime.Now.AddMonths(-1)} to { DateTime.Now.AddDays(-1) } in the Excel attachment.";
                var ms = new MemoryStream(wb.GetAsByteArray());
                ms.Position = 0;

                //msg.Attachments.Add(new Attachment(ms, "Invoices.xlsx", "application/vnd.ms-excel"));
                msg.Attachments.Add(new Attachment(ms, "Invoices.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
                var smtp = new SmtpClient
                {
                    Host = "smtp.gmail.com",
                    Port = 587,
                    EnableSsl = true,
                    Credentials = new NetworkCredential("my@gmailaccount.com", "incorrectpassword")
                };
                smtp.Send(msg);
            }
        }

        private static void FillData(ExcelWorksheet ws, DataTable dt, string title)
        {
            ws.Cells[1, 1].Value = title;

            ws.Cells[2, 1].Value = "Invoice nr";
            ws.Cells[2, 2].Value = "Invoice date";
            ws.Cells[2, 3].Value = "Amount inc. VAT";
            ws.Cells[2, 4].Value = "VAT";
            ws.Cells[2, 5].Value = "Amount exc. VAT";

            int row = 3;

            foreach (DataRow dr in dt.Rows)
            {
                ws.Cells[row, 1].Value = dr[0].ToString();
                ws.Cells[row, 2].Value = dr[1].ToString();
                ws.Cells[row, 3].Value = dr[2].ToString();
                ws.Cells[row, 4].Value = dr[3].ToString();
                ws.Cells[row++, 5].Value = dr[4].ToString();
            }
        }
    }
}

I could not test it locally because I had some issues with logins for my localdb. So I hit publish to deploy it on Azure. However republishing failed. I found the answer (as always) on StackOverflow. I had to add “MSDEPLOY_RENAME_LOCKED_FILES” and set it to 1 (true).

app-settings

Tony gave the correct solution.

I also had issues with the Excel generating in memory and having the Memorystream to a byte array and providing the right Mime type. Found that too on SO.

The last bit was to automate deployment. I had my code in VSTS (git) and configured a CI/CD pipeline (build + release) But had issues to grant myself (personal account) global admin rights from our company account in order to be able to access Azure resources to deploy. It was a matter of time before the Azure rights/roles changes are active. It’s a nice small serverless function which you can (should) add to source control and ci/cd to automate the latest builds to a test or production environment in the cloud.


Good luck!

Pin on pinterest Plus on Googleplus Post on LinkedIn
0 Comments

Yeah! I am exited! Passed the MVC 70-486 this morning.

You can see it instantly on my Acclaim page or just view the screenshot below:

image

I want to earn an MCSD cert. So I am following the app builder path:

image

According to my learning dashboard I have just passed 1 of 2 requirements for the app builder cert. But when I click details, it shows I have both… that’s strange, but I have asked @MSLearning so I will have an answer soon.

I am already looking forward to the next exam and next cert.

If I would pass 70-532 Developing Microsoft Azure Solutions and after that, will study for 70-535 Architecting Microsoft Azure Solutions, then I’d get the:

MCSA: Cloud Platform Microsoft Certified Solutions Associate

What is your certification path for 2018?

Good luck!

Pin on pinterest Plus on Googleplus Post on LinkedIn
0 Comments

Perhaps it’s because I was still in holiday-mode, but I kept getting a 403 error. Even when I added a `helloworld.html` in the `.well-known` dir. Which was driving me crazy. I even thought it was .net Core 2.x related because all full framework sites were renewing just fine, both MVC and Webform applications.

The answer for my situation was in this comment:

Do you have both http/https binding? http binding is required for it to work.

I did, but I remembered something about forcing to SSL for this website.

I searched my code, but all I could find was commented out:

image

image

So how did I manage to force visitors to the SSL version? I could not remember it. There was also no URL rewriting in the web.config. It was a checkbox in IIS which I forgot that I ever changed that setting! (sorry for the Dutch screenshot of IIS 8.5)

 image

It would be nice if the new version of Let’s Encrypt Win Simple would temporary disable it and afterwards restored it.

Here is the link to the latest version 1.9.6.2


Good luck and best wishes for 2018!

Pin on pinterest Plus on Googleplus Post on LinkedIn