ASP.NET Core, DevOps, DevTools, MVC

MSBuild… what? I just right-click on Publish

What is MSBuild? I had no idea. It has the word “build” in it, it must build something. Oh, I also remember that in the early stages of .NET Core there was a lot of discussion about project.json and the all DNX thing…. Then they decided to keep this MSBuild thingy. In the end we are all using Visual Studio and the only thing I needed to know is how to set up a Publish definition, right-click on publish and voila! My app was ready to ship. Untill…

While doing some DevOps work, I wanted to build the app only once but transform the config file multiple times based on the environment. So I started digging into this MSBuild. What is it? Here is Microsoft definition: MSBuild is the Microsoft Build Engine, a platform for building applications.
It really does a lot for our apps but all its work is hidden behind the “greatest GUI” of all time: Visual Studio.

I was going into this discovery with the idea that MSBuild would work like some of the other build process. Run a command with some flags and the build is done. Instead, the story is slightly different. It is a bit like the Angular CLI with schematics. You use schematics to define custom actions or re-define existing actions. In MSBuild you use a build file (xml format) to define the sequence of actions you need to do. That is what the .csproj are. Just build definitions. When you run MSBuild and point to a .sln file, it knows how to go through each .csproj and run the build processes as needed. Let’s see how it works and play with it.

Where is MSbuild in our machines?

The MSBuild command comes with Windows installation here: C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe based on the .NET Framework. But this version is kind of bare bone, it lucks a bunch of extensions you might need for application specific builds (like we.config transformation).

Visual Studio installation brings in a more complete version of it here: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe (actual location may vary based on your VS version and installation settings). This version includes a bunch of extensions saved in these folders:

First a bit of configuration:

Let’s start by making sure MSBuild work. Open PowerShell (or your command line of choice) and just run the MSBuild that comes with Windows with the -version flag:

As you can see all is good, MSBuild responded with its version. Now let’s see the version available with Visual Studio install:

Much newer version (obviously).

We will be using this version for the exercises below.

Hello World

This example comes from here here.

Go to your working directory of choice and create a new file named HelloWorld.build. I use VS Code but you can use your editor of choice. The content of this new file is:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0"  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Target Name="HelloWorld">
        <Message Text="Hello"></Message>
        <Message Text="World"></Message>
    </Target>
</Project>

MSBuild has 2 main concepts in executing instructions:

  • Target
  • Task

The first is a set of instructions/command to complete a larger unit of work. A task is the smallest unit of work, usually just one instruction. All instructions are wrapped in a Project tag. A target is called via a flag on the MSBuild invocation /t:TargetName (see below). In this case we just print on the console “Hello” and “World”. Let’s do it.

In PowerShell run this command:

& "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe" HelloWorld.build /t:HelloWorld

And:

How about flow control and variables?

But of course they are possible. A new variable is just a custom xml tag and condition can be build in a PropertyGroup tag. Create another build definition file and call it example2.build with this content:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0"  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup Condition="'$(Name)' == ''">
        <OutMsg>Please let us know your name!</OutMsg>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Name)' != ''">
        <OutMsg>Welcome $(Name)!</OutMsg>
    </PropertyGroup>
    <Target Name="Condition">
            <Message Text="$(OutMsg)"></Message>
    </Target>
</Project>

Then run it with:

& "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe" example2.build /t:Condition /p:Name=""

And then assign your first name to Name:

& "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe" example2.build /t:Condition /p:Name="Emanuele"

You know already the result:

How about that web.config transformation?

In this case, we will use a task (small unit of work) and it is a preexisting task that comes with the Visual Studio installation. So we must import such task. Here is the build definition:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0"  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Staging|AnyCPU'">
        <BuildConfig>Staging</BuildConfig>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
        <BuildConfig>Release</BuildConfig>
    </PropertyGroup>
    <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v15.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
    <Target Name="TransformWebConfig">
        <TransformXml Source="Configuration/Web.config"
                      Transform="Configuration/Web.$(BuildConfig).config"
                      Destination="Web.config"
                      StackTrace="true"/>
    </Target>
</Project>

I called this definition web_configs.build.

We then need the we.config files to be transformed. I created 3 files inside a folder called Configuration:

  • web.config
  • web.Staging.config
  • web.Release.config

Here is the xml in each file. Nothing new just regular web.config with environment transformations.

<!-- web.config -->
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <connectionStrings>
        <add name="entities" connectionString="Debug" />
    </connectionStrings>
</configuration>

<!-- web.Staging.config -->
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <connectionStrings>
        <add name="entities" connectionString="Staging" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />
    </connectionStrings>
</configuration>

<!-- web.Release.config -->
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <connectionStrings>
        <add name="entities" connectionString="Release" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />
    </connectionStrings>
</configuration>

Let’s now run this build definition with this command:

& "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe" web_configs.build /t:TransformWebConfig /p:Platform=AnyCPU /p:Configuration=Staging

As expected a new transformed web.config file is created in the working directory:

With this expected content:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <connectionStrings>
        <add name="entities" connectionString="Staging" />
    </connectionStrings>
</configuration>

You can run the Release version of the above command, just change the Configuration property value.

Well, I started this little journey a bit worry about the complexity of MSBuild, but once I understood a couple of the basic concepts, it wasn’t that hard to use. Keep in mind that you can do a lot with MSBuild, from copying files around, to run node, npm or other command line scripts.

I would love to hear some interesting use of MSBuild you have done. Feel free to leave a comment below.

ASP.NET Core, MVC

From WCF to Secure ASP.NET Core

Here is the challenge: securing a system of WCF services with modern OAuth and OpenIDConnect.

The entire business logic of this solution is handled and served by WCFs.  Nothing wrong with it, but the security practices were a bit outdated and not up to standard.

Considering that years of features and logic were coded in those WCFs, the budget was limited and the need to upgrade to a secure and modern system became quickly very urgent, a rewrite of the entire solution was definitely not an option.  Therefore, I decided to place all the WCFs end-point behind a ASP.NET Core proxy that leverages the Identity Server 4 framework for authentication.

Another challenge I faced was that the entire solution was in VB and I am mainly a C# developer; additionally this is a VB shop that was a little reluctant in moving to C#.  But after long pondering and knowing that in the end VB and C# compile down to the same Microsoft Intermediate Lanaguage (MSIL) we decided to code this proxy in C# and eventually start porting some of these WCF functionality into a VB .NET Standard Class Library that plays well with C# projects anyway.

After doing some research I found several sources of information that I am sharing below. Definitely the most important and inspiring one was this video and blog of Shayne Boyer called ASP.NET Core: Getting clean with SOAPThese other sources might be helpful as well:

– Here is a way to securing existing WCFs and keep open the door for more modern WebApi systems. The problem is that is done with Identity Server 3 (older version): https://leastprivilege.com/2015/07/02/give-your-wcf-security-architecture-a-makeover-with-identityserver3/ Check also the link to Github samples.

– Here is an article on CORS for WCF:

https://blogs.msdn.microsoft.com/carlosfigueira/2012/05/14/implementing-cors-support-in-wcf/

The solution in question has a few different clients:  Javascript client (browser dashboard apps), mobile apps and server client.  IdentityServer 4 has a configuration for each of these case scenarios (or flows) and their Quickstart samples give you a very good idea on how to implement them.

The key here is the creation of the WCF client that from the ASP.NET Core WebApi calls the WCF services.  Shayne uses the “svcutil” (ServiceModel Metadata Utility Tool) to automatically generate the WCF client code.  But instead I decided to use this great Visual Studio extension that does just that but makes it easier to instantiate and use a WCF client. The extension is called  Microsoft WCF Web Service Reference Provider , once installed you just go to “Connected Services” in your solution explorer, input the endpoint url and the tool creates all the code you need.  Also, just recently this tool has been included in Visual Studio 2017 (version 15.5 and above), thus no need to install this extension anymore. One thing I must mention about this tool is that it work only with a SOAP endpoints, if the WCF has other type of endpoints (like REST) the tool will not be able to read the service metadata end will return an error. You can always add a SOAP endpoint to your WCF (hopefully you have access to it).

The extension creates a client that you can instantiate by passing the “EndpointConfiguration” type and use it to call each method exposed by the WCF (by default async). Here is how:

WCFclient client = new WCFclient(EndpointConfiguration.soap);
var result = await client.MyMethodAsync(args);

Now, one of the things that we need to make sure to do is to close and dispose of the WCF Client at the end of each request.  And here the ASP.NET Core Dependency Injection comes in handy.

The ASP.NET Core DI call the Dispose() method of the injected service if it implements the  IDisposable interface.  Our WCF client created with either the VS extension or the svcutil.exe utility does not implement IDisposable.  So we will wrap the client in a class and implement the interface ourselves. The WCF Client do expose the Close() and Abort() methods needed to dispose the service client (see below).

Be careful as the ASP.NET docs note the followings:

// container will create the instance(s) of these types and will dispose them
services.AddScoped<Service1>();
services.AddSingleton<Service2>();

// container did not create instance so it will NOT dispose it
services.AddSingleton<Service3>(new Service3());
services.AddSingleton(new Service3());

So if the DI creates the instance it will dispose of it (if it implements IDisposable) but if it doesn’t it will not dispose of it even if it implements IDisposable. So do not pass in an instantiated object as an argument, just let DI do the magic.

In wrapping the WCF client we want to maintain the possibility of changing the EndpointConfiguration as well as other configurations we might want to pass in in the future (like a different URL to point to if necessary).  Thus we inherit from the IWCFClient (the WCF interface implemented by the WCF and its client which is brought in by the VS extension above) and IDisposable and we pass in the configuration directly into “base” by way of the contructor:

public class WCFClientBySoap : IWCFClient, IDisposable
{
    public WCFClientBySoap() : base(EndpointConfiguration.soap)
    {
    }

    private bool disposedValue = false; 

    protected async virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                try
                {
                    if (State != System.ServiceModel.CommunicationState.Faulted)
                    {
                        await CloseAsync();
                    }
                }
                finally
                {
                    if (State != System.ServiceModel.CommunicationState.Closed)
                    {
                        Abort();
                    }
                }
            }

            disposedValue = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
    }
}

Here is a blog that talk about disposing of a WCF Client WCF Client Closal and Disposal

Now we just need to register this wrapper with the ASP.NET Core DI container.  Because we want to be able to change the wrapper in case of different configurations, we register the wrapper as a concrete class of the WCF interface.  In Startup.cs we add this line in the ConfigurationServices method:

services.AddScoped<IWCFClient, WCFClientBySoap>();

Finally we create a controller/action endpoint for each WCF endpoint leveraging the injected client:

[Produces("application/json")]
[Route("mycontroller")]
public class MyControllerController : Controller
{
    private IWCFClient _wcfclient;

    public MyControllerController(IWCFClient wcfclient)
    {
        _wcfclient = wcfclient;

    }

    [HttpGet("getMyData")]
    public async Task<IActionResult> GetMyData()
    {
        try
        {
            var result = await _wcfclient.getMyDataAsync();
            if (result == null)
            {
                return BadRequest("Couldn't get Data");
            }
            return new ObjectResult(result);
         }
         catch (Exception x)
         {
             return BadRequest(x.Message);
         }
     }
}

And this is all. It just works.

 

MVC

Return URL with fragment in ASP.NET Core MVC

I am working on a web project based on Asp.Net MVC and Aurelia and I decided to structure it with part MVC and part Spa (Aurelia). The project also implements a basic authentication system (Asp.Net Core Identity) where if a non-authenticated user is trying to access a secure page it is redirected to the login page, which is standard procedure in these cases.

As you can see the return URL sent in with the query string includes a fragment, used by the Aurelia routing (or any spa framework routing you are using):

http://localhost:14500/Auth/Login?ReturnUrl=%2Fcamp%2F7#sessions

The problem is that the fragment  portion of the URL is never sent to the server and it is therefore ignored. So here is what happens:

The fragment of the URL is not being added to the action url of the form, so when you post the login form the server redirects to a URL without fragment and you are not able to get to the correct page handled by the spa router.

So, I included a little Javascript functions that picks up the return URL from the browser’s location.href and updates the form action with the correct return URL:

$(document).ready(function () {
        var form = $("form")[0];
        var hash = document.location.hash;
        if (hash) {
            if (form) {
                if (form.action) {
                    form.action = document.location.href;
                }
            }
        }
    });

Here is how the form action looks like after this code runs:

Now, when the user logs in and the server redirect to the originally requested URL, Aurelia router picks it up and renders the correct page.