Tuesday, December 5, 2017

AutoMapper : Handling Profile Dependencies using Custom Value Resolvers

If you are using or if you have used (I am sure you have) AutoMapper, Profiles lets you organize your mapping configurations in an easy manner.

In this post, let’s see how we can handle AutoMapper Profile dependencies using Custom Value Resolvers. As it’s always good to go with an example, let’s go with an example ASP.NET Core Web Application.

For an ASP.NET Core Web Application, AutoMapper can be configured with following easy steps.
You can add a class deriving from Profile class, and in the constructor you can setup your mapping configurations.
public class SomeProfile : Profile
{
    public SomeProfile()
    {
        CreateMap<MyClass, MyClassDTO>();
        // likewise
    }
}
Next in the Startup.ConfigureServices method, you just need to add the following line. (note: you will need to installer required AutoMapper nuget package)
public void ConfigureServices(IServiceCollection services)
{
    // some code
    services.AddAutoMapper();
}
Now you can use IMapper in your required classes as follows.
public class MyController : Controller
{
    private IMapper _mapper;
 
    public MyController(IMapper mapper)
    {
        _mapper = mapper;
    }
}
Now consider we have following two classes.
public class MyClass
{
    public int Id { get; set; }
}
 
public class MyClassDTO
{
    public int Id { get; set; }

    public string SomeProperty { get; set; }
}
And here on MyClassDTO, SomeProperty can't be mapped directly, we will need to get the value by calling ISomeService.GetSomeProperty(int id). Imagine ISomeService is registered for dependency injection.
public interface ISomeService
{
    string GetSomeProperty(int id);
}
So what we would expect is we can get the MyProperty value as follows.
public class SomeProfile : Profile
{
    private ISomeService _someService;
 
    public SomeProfile(ISomeService someService)
    {
        _someService = someService;
 
        CreateMap<MyClass, MyClassDTO>()
            .ForMember(obj => obj.SomeProperty,
                exp => exp.MapFrom(prop => _someService.GetSomeProperty(prop.Id)));
    }
}
But unfortunately, if we run this, we will get an error “No parameterless constructor defined for this object” on services.AddAutoMapper().

In these kinds of scenarios, we can use AutoMapper Custom Value Resolvers. Here I can do the DI without any issues.
public class MyPropertyResolver : IValueResolver<MyClass, MyClassDTO, string>
{
    private ISomeService _someService;
 
    public MyPropertyResolver(ISomeService someService)
    {
        _someService = someService;
    }
 
    public string Resolve(MyClass source, MyClassDTO destination, string destMember, ResolutionContext context)
    {
        return _someService.GetSomeProperty(source.Id);
    }
}
And the usage would be as follows.
public class SomeProfile : Profile
{
    public SomeProfile()
    {
        CreateMap<MyClass, MyClassDTO>()
            .ForMember(obj => obj.SomeProperty,
                exp => exp.ResolveUsing<MyPropertyResolver>());
    }
}
Now SomeProperty value should get resolved without any errors.

Hope this helps.

Happy Coding.

Regards,
Jaliya

Tuesday, November 28, 2017

Wrote a post on Wiki Life at Official Blog of TechNet Wiki

Wrote a post in Wiki Ninjas - Official Blog of TechNet Wiki. The title of the post is TNWiki Article Spotlight – Implementing Server Side validations in AngularJS.
image
TNWiki Article Spotlight – Implementing Server Side validations in AngularJS
Read the rest on,
TNWiki Article Spotlight – Implementing Server Side validations in AngularJS

Happy Coding.

Regards,
Jaliya

Sunday, November 26, 2017

Fiddler Doesn’t Capture All RavenDB REST API Calls

I was trying to figure out an issue in a Web Application that I am currently working on and it has a RavenDB backend.

The code was doing some operations on the RavenDB database (behind the scene those method calls gets translated into API calls to RavenDB REST API), and I was using Fiddler to trace the API calls to RavenDB. But apparently, only some of the API calls were listed on Fiddler and most of the calls were not present. But RavenDB logs showed that it is receiving calls, so I was bit confused why Fiddler isn’t capturing the calls.

Spent couple of hours changing Fiddler settings, RavenDB IIS Web Application settings, but output was still the same.

I had RavenDB IIS Web Application running on 8080 and I was using Url=http://localhost:8080;Database={MyDatabaseName} as the connection string. I just replaced localhost with my machine name and that was it. I am seeing all the API calls to RavenDB in fiddler.

So  if you want Fiddler to capture all RavenDB calls being made from your application, instead of having localhost or 127.0.0.1, use the machine name.

So now everything is in-place to find out the real issue, I am back to it.

Hope someone will find this helpful.

Happy Coding.

Regards,
Jaliya

Tuesday, November 21, 2017

Visual C# Technical Guru - October 2017

Another month as a judge in Microsoft TechNet Guru Awards under Visual C# category. The TechNet Guru Awards celebrate the technical articles on Microsoft TechNet.

Post in WikiNinjas Official Blog,
image
Visual C# Technical Guru - October 2017
Happy Coding.

Regards,
Jaliya

Saturday, November 4, 2017

Azure PowerShell - Cloning App Service Slots

This is some set of scripts I keep using for cloning Azure App Service Slots. Hope someone will find it useful.
# Login
Login-AzureRmAccount
 
# List all subscriptions (this step is only useful if you have multiple subscriptions)
Get-AzureRmSubscription
 
# Select azure subscription (this step is only useful if you have multiple subscriptions)
Get-AzureRmSubscription –SubscriptionName "<SubscriptionName>" | Select-AzureRmSubscription
 
# Listing all slots for a app service
Get-AzureRmWebAppSlot -ResourceGroupName "<ResourceGroupName>" -Name "<AppServiceName>"
 
# Cloning web app to a new slot
$srcWebApp = Get-AzureRmWebApp -ResourceGroupName "<ResourceGroupName>" -Name "<AppServiceName>"
New-AzureRmWebAppSlot -ResourceGroupName "<ResourceGroupName>" -Name "<AppServiceName>" -AppServicePlan "<AppServicePlan>" -Slot "<NewSlotName>" -SourceWebApp $srcWebApp
 
# Cloning web app slot to a new slot
$srcWebAppSlot = Get-AzureRmWebAppSlot -ResourceGroupName "<ResourceGroupName>" -Name "<AppServiceName>" -Slot "<SourceSlotName>"
New-AzureRmWebAppSlot -ResourceGroupName "<ResourceGroupName>" -Name "<AppServiceName>" -AppServicePlan "<AppServicePlan>" -Slot "<NewSlotName>" -SourceWebApp $srcWebAppSlot
Happy Coding.

Regards,
Jaliya

Wednesday, November 1, 2017

ASP.NET Core 2.0: Why it’s important to have Program.BuildWebHost method?

I was doing some refactoring on an ASP.NET Core 2.0 Web Application which was migrated from ASP.NET Core 1.1.

In ASP.NET Core 1.1 Web Applications, program.cs was like this.
public class Program
{
    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup&lt;Startup>()
            .UseApplicationInsights()
            .Build();
 
        host.Run();
    }
}
But with ASP.NET Core 2.0, it has to be something like this.
public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }
 
    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup&lt;Startup>()
            .Build();
}
I felt like I can eliminate BuildWebHost method, so I did like follows.
public class Program
{
    public static void Main(string[] args)
    {
        WebHost.CreateDefaultBuilder(args)
            .UseStartup&lt;Startup>()
            .Build()
            .Run();
    }
}
All seem be good, the application was running well. After sometime, I wanted to add a database migration, and when I tried to do Add-Migration, I was getting this weird error.
Unable to create an object of type 'T'. Add an implementation of 'IDesignTimeDbContextFactory&lt;T>' to the project, or see https://go.microsoft.com/fwlink/?linkid=851728 for additional patterns supported at design time.
Apparently the error turned out to be program.cs not having BuildWebHost method.

In ASP.NET Core 1.x to ASP.NET Core 2.0 Migration Guide, it specifically says, “The adoption of this new 2.0 pattern is highly recommended and is required for product features like Entity Framework (EF) Core Migrations to work.”

Once I added it back, I was able to add database migrations back again.

Lesson learnt: When doing refactoring, somethings are better left alone!

Happy Coding.

Regards,
Jaliya

Thursday, October 12, 2017

ASP.NET Core 2.0 – Applying CORS Policies

In this post let’s see how we can apply CORS policies for different scenarios (based on the route/path etc.) in an ASP.NET Core 2.0 Web Application.

As you already know, in ASP.NET Core projects, on the Startup.cs, we have 2 methods ConfigureServices and Configure, and these two will get called by the runtime. ConfigureServices is used to add services to the container, so we can use them through out the application. Configure method is used to configure the HTTP Request pipeline.

So moving to the topic, first thing we need to do is AddCors to IoC container, (again so we can consume this through out the application). (Note: these is an alternate way, and I will be describing that later in the post, keep reading forward)
public void ConfigureServices(IServiceCollection services)
{
    // Add policies, so we can consume them when configuring HTTP request pipeline
    services.AddCors(options =>
    {
        string[] origins = new string[] { "http://localhost:2000", "http://localhost:2001" };
 
        options.AddPolicy("MyCorsPolicy", policyBuilder =>
        {
            policyBuilder
                .AllowAnyHeader()
                .AllowAnyMethod()
                .WithOrigins(origins);
        });
    });
 
    services.AddMvc();
}
Once we have defined the CORS policy (you can define many policies), we can configure the HTTP Requests for CORS policies in following ways.
  1. Application Level (Applies to all the HTTP Requests)
  2. Controller Level
  3. Custom

Application Level


This is kind of the basic approach among above three.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
 
    app.UseCors("MyCorsPolicy");
            
    app.UseMvc();
}
Something to note here is, if you prefer not to go with named policies, you can just skip Adding CORS (AddCors) and do as following in Configure method.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
 
    app.UseCors(policyBuilder =>
    {
        string[] origins = new string[] { "http://localhost:2000", "http://localhost:2001" };
 
        policyBuilder
            .AllowAnyHeader()
            .AllowAnyMethod()
            .WithOrigins(origins);
    });
 
    app.UseMvc();
}

Controller Level


If you don’t want to go with Application level and you want to go with Controller level, this is how you can do it.
[EnableCors("MyCorsPolicy")]
[Route("api/[controller]")]
public class ValuesController : Controller
{
    // actions
}
But to do this, so need to have named CORS policies defined.

Note: The precedence order is: Action, controller, global. Action-level policies take precedence over controller-level policies, and controller-level policies take precedence over global policies.

Custom


Imagine, you want to apply CORS policy based on HTTP Request route/path etc. You can use the power of Middleware for that kind of a scenario.

One approach would would be, you can use app.Map and app.MapWhen to branch off the HTTP Request pipeline and use app.UseCors as shown in above, but the downside is your HTTP Request pipeline is getting short-circuited. That of course you can merge back, but personally I don’t find it a good approach.

The other approach (which I personally find best) is, you can easily create a separate Middleware class for handling CORS in following way.
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
 
namespace WebApplication178.Middleware
{
    public class CustomCorsMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ICorsService _corsService;
        private readonly ICorsPolicyProvider _corsPolicyProvider;
        private readonly CorsPolicy _policy;
        private readonly string _corsPolicyName;
 
        public CustomCorsMiddleware(
            RequestDelegate next,
            ICorsService corsService,
            ICorsPolicyProvider policyProvider)
            : this(next, corsService, policyProvider, policyName: null) { }
 
        public CustomCorsMiddleware(
            RequestDelegate next,
            ICorsService corsService,
            ICorsPolicyProvider policyProvider,
            string policyName)
        {
            _next = next ?? throw new ArgumentNullException(nameof(next));
            _corsService = corsService ?? throw new ArgumentNullException(nameof(corsService));
            _corsPolicyProvider = policyProvider ?? throw new ArgumentNullException(nameof(policyProvider));
            _corsPolicyName = policyName;
        }
 
        public CustomCorsMiddleware(
           RequestDelegate next,
           ICorsService corsService,
           CorsPolicy policy)
        {
            _next = next ?? throw new ArgumentNullException(nameof(next));
            _corsService = corsService ?? throw new ArgumentNullException(nameof(corsService));
            _policy = policy ?? throw new ArgumentNullException(nameof(policy));
        }
 
        public async Task Invoke(HttpContext context)
        {
            if (context.Request.Headers.ContainsKey(CorsConstants.Origin))
            {
                CorsPolicy corsPolicy = null;
 
                // If the following condition matches only apply CORS Policy
                if (context.Request.Path.ToString().ToLower().Contains("something"))
                {
                    corsPolicy = _policy ?? await _corsPolicyProvider?.GetPolicyAsync(context, "MyCustomPolicy");
                }
 
                if (corsPolicy != null)
                {
                    var corsResult = _corsService.EvaluatePolicy(context, corsPolicy);
                    _corsService.ApplyResult(corsResult, context.Response);
 
                    var accessControlRequestMethod = context.Request.Headers[CorsConstants.AccessControlRequestMethod];
                    if (string.Equals(
                            context.Request.Method,
                            CorsConstants.PreflightHttpMethod,
                            StringComparison.OrdinalIgnoreCase) &&
                            !StringValues.IsNullOrEmpty(accessControlRequestMethod))
                    {
                        // Since there is a policy which was identified,
                        // always respond to preflight requests.
                        context.Response.StatusCode = StatusCodes.Status204NoContent;
                        return;
                    }
                }
            }
 
            await _next(context);
        }
    }
}
The whole piece of code is taken from CorsMiddleware.cs (cheers to Microsoft for going open source), and we can just modify it to match our need. Here I have modified it to apply CORS policy based on the request route/path. Now you can simply do following.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
 
    app.UseMiddleware<CustomCorsMiddleware>();
            
    app.UseMvc();
}
The usual behavior of CorsMiddleware would be as follows. For this, you need to have Microsoft.AspNetCore.Cors package installed.
app.UseMiddleware<CorsMiddleware>();
 
// Passing in the policy name
app.UseMiddleware<CorsMiddleware>("MyCorsPolicy");
Hope this helps.

Happy Coding.

Regards,
Jaliya

Tuesday, October 10, 2017

EF Core Automatic Migrations

As you might know and as of today, for Entity Framework Core, Microsoft does not support Automatic Database Migrations as in Entity Framework Full. The reasons are described in this Issue. But it doesn't stop you from configuring automatic migrations by your own. You can just write something like below and call this inside Startup -> Configure method passing the IApplicationBuilder.
private static void InitializeMigrations(IApplicationBuilder app)
{
    using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
    {
        MyDbContext dbContext = serviceScope.ServiceProvider.GetRequiredService<MyDbContext>();
        dbContext.Database.Migrate();
 
        // TODO: Use dbContext if you want to do seeding etc.
    }
}
Happy Coding.

Regards,
Jaliya

Thursday, September 28, 2017

Visual C# Technical Guru - August 2017

Another month as a judge in Microsoft TechNet Guru Awards under Visual C# category. The TechNet Guru Awards celebrate the technical articles on Microsoft TechNet.

Post in WikiNinjas Official Blog,
image
Visual C# Technical Guru - August 2017
Happy Coding.

Regards,
Jaliya

Thursday, September 14, 2017

Wrote a post on Wiki Life at Official Blog of TechNet Wiki

Wrote a post in Wiki Ninjas - Official Blog of TechNet Wiki. The title of the post is TNWiki Article Spotlight – Getting started with Cognitive Services – Vision.
image
TNWiki Article Spotlight – Getting started with Cognitive Services – Vision

Happy Coding.

Regards,
Jaliya

Wednesday, August 30, 2017

Visual C# Technical Guru - July 2017

Another month as a judge in Microsoft TechNet Guru Awards under Visual C# category. The TechNet Guru Awards celebrate the technical articles on Microsoft TechNet.

Post in WikiNinjas Official Blog,
image
Visual C# Technical Guru - July 2017
Happy Coding.

Regards,
Jaliya

Friday, August 18, 2017

Getting Started with ASP.NET Core 2.0 Razor Pages

With the release of ASP.NET Core 2.0, one of the new features that got introduced was Razor Pages. The easiest way to get yourself started on ASP.NET Core Razor Pages is with Visual Studio 2017 Update 15.3.

Once you have installed Visual Studio 2017 Update 15.3 and if you try to create a new ASP.NET Core Web Application,
image
New Project
You are presented with an improved dialog window. 
image
New ASP.NET Core Web Application
When you selected ASP.NET Core 2.0 from the ASP.NET Core version selection dropdown, you are presented with multiple application templates. From there, when you select your template as Web Application, you can see that it uses Razor Pages.

Let’s go ahead and create a Web Application. Once the project is created, if you have a look at Solution Explorer, you should be able to see something like below.
image
Pages Folder
When I first had a look at this, for me it was familiar MVC file names and Web Forms like file structure (HTML file and a code behind file).

Now if you run the application, you should be seeing the familiar template.
image
Running
Now to explore what ASP.NET Core Razor Pages really is, let’s open up About.cshtml and About.cshtml.cs (I am going ahead with About files as there are less static content there).

About.cshtml
image
About.cshtml
Here the highlighted @page directive is one of the most important things. It enables, razor file to link with it’s related PageModel.

About.cshtml.cs
image
About.cshtml.cs
If you prefer, to improve productivity in development, you can have the content in code behind in the razor file itself.

About.cshtml
@page
@model AboutModel
@using Microsoft.AspNetCore.Mvc.RazorPages
@{
    ViewData["Title"] = "About";
}
 
@functions{
    public class AboutModel : PageModel
    {
        public string Message { get; set; }
 
        public void OnGet()
        {
            Message = "Your application description page.";
        }
    }
}
 
<h2>@ViewData["Title"]</h2>
<h3>@Model.Message</h3>
 
<p>Use this area to provide additional information.</p>
While above will work fine, there is a advantage, above supports run-time compilation. That is pretty handy in development, you don't need to stop the debugger to do some change in PageModel class.

When the page is requested by http://localhost:xxxx/About, OnGet method will get called and when you want to post something, you can introduce OnPost method and it will get trigged upon POST requests. For async requests, you can name  the methods as OnGetAsync, OnPostAsync etc.

About.cshtml
@page
@model AboutModel
@using Microsoft.AspNetCore.Mvc.RazorPages
@{
    ViewData["Title"] = "About";
}
 
@functions{
    public class AboutModel : PageModel
    {
        public string Message { get; set; }
 
        public void OnGet()
        {
            Message = "Your application description page.";
        }
 
        public void OnPost()
        {
            Message = $"You just made a post on {DateTime.Now}.";
        }
    }
}
 
<h2>@ViewData["Title"]</h2>
<h3>@Model.Message</h3>
 
<p>Use this area to provide additional information.</p>
 
<form method="post">
    <input type="submit" value="Submit"/>
</form>
Hopefully, this will help you get started on ASP.NET Core Razor Pages.

More reads,

Happy Coding.

Regards,
Jaliya

Friday, August 11, 2017

Session : Docker for .NET Developers at Sri Lanka .NET Forum

Delivered an hour long session at Sri Lanka .NET Forum today.

There was no session slides, I was totally focusing on showing the participants Docker in action. I have demoed how we can run a containerized ASP.NET Core application in a Linux container using only docker command. Then I have showed what Visual Studio 2017 has introduced to improve the productivity in building containerized applications and the use of docker-compose command.

For more information,
   Meetup Event

Happy Coding.

Regards,
Jaliya

Wednesday, July 26, 2017

Visual C# Technical Guru - June 2017

Another month as a judge in Microsoft TechNet Guru Awards under Visual C# category. The TechNet Guru Awards celebrate the technical articles on Microsoft TechNet.

Post in WikiNinjas Official Blog,
image
Visual C# Technical Guru - June 2017
Happy Coding.

Regards,
Jaliya

Wednesday, July 5, 2017

Session : ASP.NET MVC 5 and SignalR 2

Delivered a 2-hour long session today about ASP.NET MVC 5 and SignalR 2 for a Microsoft partnered company in Sri Lanka.

There I went through the following set of topics in the context of ASP.NET MVC 5 and SignalR 2.
  • What is SignalR
  • Transports
  • Supported Platforms
  • Connections and Hubs
  • Hubs API Guide
    • Server (C#)
    • Client (JavaScript)
  • Understanding Lifetime Events
  • Security
  • Performance
  • What’s Next: ASP.NET Core SignalR


And a demo application was created during the session from scratch for a better understanding of the concepts.
Happy Coding.

Regards,
Jaliya

Friday, June 23, 2017

Visual C# Technical Guru - May 2017

Another month as a judge in Microsoft TechNet Guru Awards under Visual C# category. The TechNet Guru Awards celebrate the technical articles on Microsoft TechNet.

Post in WikiNinjas Official Blog,
image
Visual C# Technical Guru - May 2017
Happy Coding.

Regards,
Jaliya

Wednesday, June 21, 2017

Wrote a post on Wiki Life at Official Blog of TechNet Wiki

Wrote a post in Wiki Ninjas - Official Blog of TechNet Wiki. The title of the post is Wiki Life: TechNet Guru Competition – How far we have come.
image
Wiki Life: TechNet Guru Competition – How far we have come

Happy Coding.

Regards,
Jaliya

Creating a Docker Container Running ASP.NET Core Web Application Powered by React and Redux

This is likely going to be a quick post. I wanted to have a Docker Container running ASP.NET Core Web Application powered by React and Redux. Luckily there are nice SPA templates introduced by Microsoft, and there we have React, Redux template.
SNAGHTML3757723
MVC ASP.NET Core with React.js and Redux
I created the application and did a publish. Then I have added a Dockerfile with following configs.

Dockerfile
FROM microsoft/aspnetcore:1.1.2
LABEL Name=ReactReduxApp Version=0.0.0
ARG source
WORKDIR /app
EXPOSE 30000
COPY ${source:-bin/Release/netcoreapp1.1/publish} .
RUN apt-get update
# Installing npm
RUN apt-get install -y npm
# Installing Node.js
RUN npm install -g n; n stable
ENTRYPOINT dotnet ReactReduxApp.dll    
Next I have build the image. This will install all npm and Node.js to my base Image. Once that is done, I have started the Container and all is good.
image
docker run
image
MVC ASP.NET Core with React.js and Redux Running in Docker
If you want to learn how to create a ASP.NET Core MVC Application running inside a Docker Linux Container this post should help.

Complete source code is available on GitHub.
https://github.com/jaliyaudagedara/Blog-Post-Samples/tree/master/ReactReduxApp

Happy Coding.

Regards,
Jaliya

Thursday, June 1, 2017

Creating a Release Build of an ASP.NET Core Project using Docker ASP.NET Core Build Image

In one of my previous posts I wrote about Creating and Debugging Docker Enabled .NET Core Project in Visual Studio 2017 and in this post let’s see how we can create a release build of an ASP.NET Core Project using official Docker ASP.NET Core Build Image.

Right now I have a Docker support enabled ASP.NET Core MVC Application created (If you don't know how, you can read my above mentioned previous post).

Note: I have created the solution using Visual Studio 2017, but you don't need to have Visual Studio 2017 to create this solution. dotnet SDK and Visual Studio Code should be more than enough. For the next steps, we only need dotnet SDK and cmd/PowerShell.

Let's proceed. I have a clean solution, no obj/bin folders present yet.
SNAGHTML9e60569
No obj/bin folders
I have a PowerShell window opened on the root folder level.
PS C:\Users\Jaliya\Desktop\DockerComposeWebApp>
Next to do a Release build what I would do is do a dotnet restore and a publish like below.
# Restore packages
dotnet restore .\DockerComposeWebApp\DockerComposeWebApp.csproj
 
# Publish on Release mode
dotnet publish -c Release .\DockerComposeWebApp\DockerComposeWebApp.csproj
But in that case the build would be done on my local machine, instead here I want to use a Docker Container to do the building.

Now let’s open up the docker-compose.ci.build.yml in my local folder. Remember I did not write this file myself, Visual Studio 2017 created this for me when I have enabled Docker Support for my project (if you want to know how to get these docker-compose.xxxxx.yml files created when using Visual Studio Code, you can read this previous post of mine Running ASP.NET Core MVC Application inside a Docker Linux Container from Windows).

docker-compose.ci.build.yml
version: '2'
services:
  ci-build:
    image: microsoft/aspnetcore-build:1.0-1.1
    volumes:
      - .:/src
    working_dir: /src    
    command: /bin/bash -c "dotnet restore ./DockerComposeWebApp.sln && dotnet publish ./DockerComposeWebApp.sln -c Release -o ./obj/Docker/publish"
Here you can see that we have a service named ci-build which uses microsoft/aspnetcore-build Image and that is the official Image for building ASP.NET Core applications (version will be changed time to time). Then my current folder is getting mapped to src folder in the ci-build Container (which is not yet created). After Container is created and running, it’s working directory will get changed to src and the given command will get executed. And basically what the command does is a dotnet restore and a dotnet publish (here output path is set to .\obj\Docker\publish).

Now from PowerShell let’s run the following command.
# docker-compose up: Builds, (re)creates, starts, and attaches to containers for a service.
PS C:\Users\Jaliya\Desktop\DockerComposeWebApp> docker-compose -f .\docker-compose.ci.build.yml up
image
docker-compose up
(Note: since I already had microsoft/aspnetcore-build Image locally, it didn't get downloaded again. If not, downloading status of the image will be displayed here.)

Now if we examine the \DockerComposeWebApp project folder, we can see obj/bin folders has been created and if we go to .\obj\Docker\publish folder, build contents are there.
image
Published Folder
Now we have a Release build created using a Docker Container (remember we didn’t do the build on our local machine).

For a further step, to make sure all is good, let’s package this content into a another Docker Container and see whether it works.

docker-compose.yml
version: '2'
services:
  dockercomposewebapp:
    image: dockercomposewebapp    
    build:
      context: ./DockerComposeWebApp      
      dockerfile: Dockerfile
Dockerfile
FROM microsoft/aspnetcore:1.1
ARG source
WORKDIR /app
EXPOSE 80
COPY ${source:-obj/Docker/publish} .
ENTRYPOINT ["dotnet", "DockerComposeWebApp.dll"]
docker-compose.override.yml
version: '2'
services:
  dockercomposewebapp:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development    
    ports:
      - "80"
PS C:\Users\Jaliya\Desktop\DockerComposeWebApp> docker-compose -f .\docker-compose.yml -f .\docker-compose.override.yml up
image
docker-compose up
SNAGHTMLa547c48
docker images & docker ps
:latest Image of a build has been created and a Container is running which got instantiated from that Image.

Now let’s just browse the running port. And yes, it is working.
image
Site Running inside a Docker Container
Happy Coding.

Regards,
Jaliya

Creating and Debugging Docker Enabled .NET Core Project in Visual Studio 2017

In this post let’s see how you can use Visual Studio 2017 to develop .NET Core application with Docker support enabled and see what happens when you build/debug.

Let’s start off by creating a ASP.NET Core Web Application (.NET Core) and I am naming it as DockerComposeWebApp.
image
ASP.NET Core Web Application (.NET Core)
Once you clicked on OK from above, you are prompted to select application type (of course, I am sure you have done this hundred times, if not thousands).
image
Enable Docker Support
And there is a new check box presented in the dialog window, that is Enable Docker Support. You can either enable Docker support from there, or as mentioned, you can enable it later.

And I am not enabling it right now, I am clicking on OK and the solution gets created. And to enable Docker support now, you can right click on the Project, select Add and then click on Docker Support (well, you should be able to right click on any root item, and do Add –> Docker Support, but not on Solution level nor file level).
image
Enable Docker Support
Once you enabled Docker support, a Dockerfile has been added to DockerComposeWebApp project and you can see a new project that is added to the solution named docker-compose with some files.

Dockerfile
FROM microsoft/aspnetcore:1.1
ARG source
WORKDIR /app
EXPOSE 80
COPY ${source:-obj/Docker/publish} .
ENTRYPOINT ["dotnet", "DockerComposeWebApp.dll"]

image
Files View - Visual Studio
If you examine the files in the File Explorer, it looks like this.
image
Files View - File Explorer
Let’s just open up the docker-compose.dcproj file.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" Sdk="Microsoft.Docker.Sdk">
  <PropertyGroup Label="Globals">
    <ProjectGuid>00832628-12a5-4b9b-b434-fcabd17c57b8</ProjectGuid>
    <DockerLaunchBrowser>True</DockerLaunchBrowser>
    <DockerServiceUrl>http://localhost:{ServicePort}</DockerServiceUrl>
    <DockerServiceName>dockercomposewebapp</DockerServiceName>
  </PropertyGroup>
  <ItemGroup>
    <None Include="docker-compose.ci.build.yml" />
    <None Include="docker-compose.override.yml">
      <DependentUpon>docker-compose.yml</DependentUpon>
    </None>
    <None Include="docker-compose.vs.debug.yml">
      <DependentUpon>docker-compose.yml</DependentUpon>
    </None>
    <None Include="docker-compose.vs.release.yml">
      <DependentUpon>docker-compose.yml</DependentUpon>
    </None>
    <None Include="docker-compose.yml" />
  </ItemGroup>
</Project>
And if you have a look at the ItemGroup, that is what it gives Visual Studio the nested view in docker-compose project items. So basically there is two main docker-compose files, one is docker-compose.ci.build.yml and the other is docker-compose.yml.

Now let’s see what happens when you debug the application. Since our main interest here is in Docker side of things, let’s set the docker-compose project as the startup project. Same time you can see that the Debug target is changed to Docker (if you debug the solution having the Web App project as the startup project it will not be debugging on Docker).

Before hitting F5, let’s see is there any Docker Containers running.
image
docker images & docker ps -a
Nothing specific to our current project (DockerComposeWebApp).

Now let’s debug. After couple of seconds, the site is working (well, it should) and what we need to focus is the Build output in Visual Studio.
------ Build started: Project: docker-compose, Configuration: Debug Any CPU ------
docker-compose -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.override.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.vs.debug.yml" 
               -p dockercompose1628124139 
               config
First VS is issuing docker-compose config command to validate and view the compose file and it shows the output as below.
networks: {}
services:
  dockercomposewebapp:
    build:
      args:
        source: obj/Docker/empty/
      context: C:\Users\Jaliya\Desktop\DockerComposeWebApp\DockerComposeWebApp
      dockerfile: Dockerfile
    entrypoint: tail -f /dev/null
    environment:
      ASPNETCORE_ENVIRONMENT: Development
      DOTNET_USE_POLLING_FILE_WATCHER: '1'
    image: dockercomposewebapp:dev
    labels:
      com.microsoft.visualstudio.targetoperatingsystem: linux
    ports:
    - '80'
    volumes:
    - C:\Users\Jaliya\Desktop\DockerComposeWebApp\DockerComposeWebApp:/app:rw
    - C:\Users\Jaliya\clrdbg:/clrdbg:ro
    - C:\Users\Jaliya\.nuget\packages:/root/.nuget/packages:ro
version: '2.0'
volumes: {}
Basically this is a consolidation of docker-compose.yml, docker-compose.override.yml and docker-compose.vs.debug.yml files.

Next Visual Studio is executing docker ps command setting up some filter options to see if there is already a Container related to our project.
docker  ps --filter "status=running" --filter "name=dockercompose1628124139_dockercomposewebapp_" --format {{.ID}} -n 1
And there is no output. But still above command follows couple of docker-compose kill and docker-compose down commands using docker-compose release and debug yml files.
docker-compose -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.override.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.vs.release.yml" 
               -p dockercompose1628124139 
                kill
 
docker-compose -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.override.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.vs.release.yml" 
               -p dockercompose1628124139 
               down 
               --rmi local 
               --remove-orphans
 
Removing network dockercompose1628124139_default
Network dockercompose1628124139_default not found.
 
docker-compose -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.override.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.vs.debug.yml" 
               -p dockercompose1628124139 
               kill
 
docker-compose -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.override.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.vs.debug.yml" 
               -p dockercompose1628124139 
               down 
               --rmi local 
               --remove-orphans
 
Removing network dockercompose1628124139_default
Network dockercompose1628124139_default not found.
And finally docker-compose up command with build argument is being executed.
docker-compose -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.override.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.vs.debug.yml" 
               -p dockercompose1628124139 
               up 
               -d 
               --build
 
Creating network "dockercompose1628124139_default" with the default driver
Building dockercomposewebapp
Step 1/6 : FROM microsoft/aspnetcore:1.1
 ---> e57f6d3fac0a
Step 2/6 : ARG source
 ---> Running in 1d44520ba0ff
 ---> 3b1eab823df1
Removing intermediate container 1d44520ba0ff
Step 3/6 : WORKDIR /app
 ---> 2f8078c67f8b
Removing intermediate container 8e3775dc753a
Step 4/6 : EXPOSE 80
 ---> Running in ee30aa3b3287
 ---> 38ea46a28cd0
Removing intermediate container ee30aa3b3287
Step 5/6 : COPY ${source:-obj/Docker/publish} .
 ---> 441f4a61d8ee
Removing intermediate container 7426260a8476
Step 6/6 : ENTRYPOINT dotnet DockerComposeWebApp.dll
 ---> Running in 471fb962159c
 ---> e756ed44b5f7
Removing intermediate container 471fb962159c
Successfully built e756ed44b5f7
Creating dockercompose1628124139_dockercomposewebapp_1
========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
And now if I examine Images and currently running Containers, I can see an Image is created and a Container is running related to our project.
image
docker images & docker ps
And that’s it for this post. You definitely will like to see what happens/what commands gets executed if we stop the Debugger and start back. And I will leave it with you to find it out.

Note: I have not gone through all the theoretical things related to Docker Compose as Docker maintains a rich documentation over those.

Happy Coding.

Regards,
Jaliya