.NET on Linux: Not Only a Advertising and marketing Ploy

[ad_1]

Creating .NET options on Linux has all the time been difficult as a result of Microsoft’s Visible Studio requires Home windows so as to work. After engaged on a number of .NET tasks, I made a decision to check the boundaries of improvement of .NET on Linux. This straightforward tutorial focuses on an ASP.NET MVC utility with SQL Server to indicate how elegant and efficient .NET improvement may be on my most popular OS.

Growth Setting

First, we should make sure the .NET instruments and SDK related to our explicit taste of Linux are put in utilizing Microsoft’s commonplace information.

My most popular improvement setting consists of a windowed built-in improvement setting (IDE), a strong database administration and question software, the database itself, and instruments for constructing and deployment. I exploit the next instruments to realize stable performance and allow a gorgeous coding expertise:

Ensure that these instruments are correctly put in earlier than you proceed with our pattern utility.

Undertaking Scaffolding

On this pattern utility, we’ll spotlight ASP.NET improvement and performance via a sequence of use instances for a hypothetical shoe retailer stock administration system. As with all new .NET utility, we’ll have to create an answer after which add a undertaking to it. We will leverage the .NET SDK CLI instruments to scaffold our new resolution:

mkdir Shoestore && cd Shoestore
dotnet new sln

Subsequent, create an ASP.NET undertaking containing an specific important class for simplicity’s sake, as this undertaking construction is most acquainted to ASP.NET builders. Let’s create our undertaking utilizing the MVC sample:

mkdir Shoestore.mvc && cd Shoestore.mvc
dotnet new mvc --use-program-main=true

Subsequent, add the undertaking into the answer:

# Go to the foundation of the answer
cd ..
dotnet sln add Shoestore.mvc/

We now have a default resolution and its contained ASP.NET undertaking. Earlier than continuing, be sure that all the pieces builds:

cd Shoestore.mvc/
dotnet restore
dotnet construct

Good improvement follow encourages placing key providers and the applying runtime into Docker containers for improved deployment and portability. Subsequently, let’s create a easy Docker container to help our utility.

Utility Portability

Docker photos usually reference one other mother or father Docker picture as an accepted start line for important necessities like OS and fundamental options, together with databases. Following this Docker greatest follow, create each a Dockerfile and a Docker Compose file for correct service configuration whereas referencing Microsoft-published mother or father photos. We’ll use Docker levels to maintain our picture small. Phases enable us to make use of the .NET SDK whereas constructing our utility in order that the ASP.NET runtime is required solely whereas our utility runs.

Create the Shoestore.mvc Dockerfile with the next contents:

# ShoestoreShoestore.mvcDockerfile
# Construct stage
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS construct
WORKDIR /shoestore
COPY Shoestore.mvc/*.csproj ./
# Restore undertaking packages
RUN dotnet restore
COPY Shoestore.mvc/* ./
# Create a launch construct
RUN dotnet construct -c Launch -o /app/construct

# Run the applying and make it out there on port 80
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
EXPOSE 80
# Property and views
COPY Shoestore.mvc/Views ./Views
COPY Shoestore.mvc/wwwroot ./wwwroot
COPY --from=construct /app/construct ./
ENTRYPOINT [ "dotnet", "Shoestore.mvc.dll" ]

Subsequent, we’ll create the docker-compose.yml file in our resolution’s root listing. Initially, it’ll solely comprise a reference to our utility service’s .Dockerfile:

# Shoestore/docker-compose.yml
model: "3.9"
providers:
  internet:
    construct:
      context: .
      dockerfile: Shoestore.mvc/Dockerfile
    ports:
      - "8080:80"

Let’s additionally configure the environment with a .dockerignore file to make sure that solely the construct artifacts are copied to our picture.

With our utility service now stubbed in and its execution setting able to run, we have to create our database service and join it to our Docker configuration.

The Database Service

Including the Microsoft SQL Server to our Docker configuration is easy, particularly since we’re utilizing a Microsoft-provided Docker picture with out altering it. Add the next configuration block to the underside of the docker-compose.yml file to configure the database:

  db:
    picture: "mcr.microsoft.com/mssql/server"
    setting:
      SA_PASSWORD: "custom_password_123"
      ACCEPT_EULA: "Y"
    ports:
      - "1433:1433"

Right here, ACCEPT_EULA prevents the set up from halting, and our ports setting lets the default SQL Server port go via with out translation. With that, our Compose file consists of each our utility service and database.

Earlier than customizing the applying code, let’s confirm that our Docker setting works:

# From the foundation of the answer
docker compose up --build

Assuming no errors seem throughout startup, our incomplete pattern utility must be out there via an online browser on the native handle http://localhost:8080.

Now we get to concentrate on the enjoyable half: customizing the applying code and making certain that the applying information persists within the Microsoft SQL Server database. We’ll use each the Entity Framework (EF) and .NET SDK instruments to attach the applying to the database and scaffold the applying’s mannequin, view, controller, and EF-required configuration.

Earlier than we will specify the instruments we want, we should create a tool-manifest file:

# From the foundation of the answer

dotnet new tool-manifest

Add the EF and SDK instruments to this file with these easy instructions:

dotnet software set up dotnet-ef
dotnet software set up dotnet-aspnet-codegenerator

To confirm the correct set up of those instruments, run dotnet ef. If a unicorn seems, they’re put in appropriately. Subsequent, run dotnet aspnet-codegenerator to check the ASP.NET instruments; the output must be a common CLI utilization block.

Now we will use these instruments to create our utility.

MVC: Mannequin

The primary activity in constructing our utility is creating the mannequin. Since this mannequin will probably be added to the database later, we’ll embrace the MS SQL Server and EF packages in our undertaking:

cd Shoestore.mvc/
dotnet add bundle Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
dotnet add bundle Microsoft.EntityFrameworkCore.SqlServer
dotnet add bundle Microsoft.EntityFrameworkCore.Instruments
dotnet restore

Subsequent, create an EF database context object that determines which fashions are added to the database, and permits our code to simply entry and question that information from the database.

Create a Knowledge listing to deal with the EF-specific code and create the ApplicationDBContext.cs file with the next contents:

// Shoestore/Shoestore.mvc/Knowledge/ApplicationDBContext.cs
utilizing Microsoft.EntityFrameworkCore;

namespace Shoestore.mvc.Knowledge;

public class ApplicationDBContext : DbContext
{
  public ApplicationDBContext(DbContextOptions<ApplicationDBContext> choices):base(choices){}
}

Subsequent, configure the database connection string, which should match the credentials we configured in our Dockerfile. Set the contents of Shoestore/Shoestore.mvc/appsettings.json to the next:

{
  "Logging": {
    "LogLevel": {
      "Default": "Data",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "Shoestore": "Server=db;Database=grasp;Person=sa;Password=custom_password_123;"
  }
}

With the database connection string configured and database context coded, we’re able to code our utility’s Foremost operate. We’ll embrace database exception dealing with to simplify system debugging. Moreover, as a result of a .NET bug within the generated code causes the Docker container to serve our views incorrectly, we’ll want so as to add particular code to our view service configuration. It will explicitly set the file paths to our view location in our Docker picture:

utilizing Microsoft.EntityFrameworkCore;
utilizing Shoestore.mvc.Knowledge;

namespace Shoestore.mvc;

// ...

    public static void Foremost(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        // Affiliate our EF database context and configure it with our connection string
        var connectionString = builder.Configuration.GetConnectionString("Shoestore");
        builder.Companies.AddDbContext<ApplicationDBContext>(
            choices => choices.UseSqlServer(connectionString));
        // Middleware to catch unhandled exceptions and show a stack hint
        builder.Companies.AddDatabaseDeveloperPageExceptionFilter();

        // Add providers to the container.
        // ASP.NET has a recognized concern the place the ultimate constructed app would not know the place the view
        // information are (within the Docker container). 
        // The repair is to particularly add view places.
        builder.Companies
            .AddControllersWithViews()
            .AddRazorOptions(choices => {
                choices.ViewLocationFormats.Add("/{1}/{0}.cshtml");
                choices.ViewLocationFormats.Add("/Shared/{0}.cshtml");
            });

Skip all the way down to the IsDevelopment if assertion throughout the identical file so as to add a database migration endpoint to our system when it’s in improvement mode. Add an else assertion with the next code:

        // Configure the HTTP request pipeline.
        if (!app.Setting.IsDevelopment())
        {
            // Depart the contents of the if block alone. These are hidden for readability.
        } else {
            app.UseMigrationsEndPoint();
        }

Subsequent, run a fast take a look at to make sure the brand new packages and the supply code edits compile appropriately:

// Go to mvc listing
cd Shoestore.mvc
dotnet restore
dotnet construct

Now, let’s populate the mannequin with our required fields by creating the Shoestore.mvcModelsShoe.cs file:

namespace Shoestore.mvc.Fashions;

public class Shoe {
    public int ID { get; set; }
    public string? Title { get; set; }
    public int? Worth { get; set; }
    public DateTime CreatedDate { get; set; }
}

EF generates SQL based mostly on the related mannequin, its context file, and any EF code in our utility. SQL outcomes are then translated and returned to our code, as wanted. If we add our Shoe mannequin to our database context, EF will know how one can translate between MS SQL Server and our utility. Let’s do that within the database context file, Shoestore/Shoestore.mvc/Knowledge/ApplicationDBContext.cs:

utilizing Microsoft.EntityFrameworkCore;
utilizing Shoestore.mvc.Fashions;

namespace Shoestore.mvc.Knowledge;

public class ApplicationDBContext : DbContext
{
  public ApplicationDBContext(DbContextOptions<ApplicationDBContext> choices) : base(choices) { }

    personal DbSet<Shoe>? _shoe { get; set; }
    public DbSet<Shoe> Shoe {
        set => _shoe = worth;
        get => _shoe ?? throw new InvalidOperationException("Uninitialized property" + nameof(Shoe));
    }
}

Lastly, we’ll use a database migration file to get our mannequin into the database. The EF software creates a migration file particular to MS SQL Server based mostly on the database context and its related mannequin (i.e., Shoe):

cd Shoestore.mvc/
dotnet ef migrations add InitialCreate

Let’s maintain off on working our migration till now we have a controller and examine in place.

MVC: Controller and View

We’ll create our controller utilizing the ASP.NET code technology software. This software could be very highly effective however requires particular helper lessons. Use the Design type packages for the fundamental controller construction and its EF integration. Let’s add these packages:

cd Shoestore.mvc
dotnet add bundle Microsoft.VisualStudio.Net.CodeGeneration.Design && 
dotnet add bundle Microsoft.EntityFrameworkCore.Design && 
dotnet restore

Now, creating our default controller is so simple as invoking the next command:

cd Shoestore.mvc
dotnet dotnet-aspnet-codegenerator controller 
        -name ShoesController 
        -m Shoe 
        -dc ApplicationDBContext 
        --relativeFolderPath Controllers 
        --useDefaultLayout 
        --referenceScriptLibraries

When the code generator creates our controller, it additionally creates a easy view for that controller. With our MVC foundations full, we’re able to get all the pieces working.

Migration and Utility Take a look at

EF migrations are often a easy affair, however when Docker is concerned, the method turns into extra advanced. Within the subsequent article in our sequence, we’ll discover the splendidly twisty path to creating these migrations work in our Docker resolution, however for now, we simply need our migration to run.

All configuration and migration information are included in our repository. Let’s clone the complete undertaking to our native machine and carry out the migration:

git clone https://github.com/theZetrax/dot-net-on-linux.git
cd ./dot-net-on-linux
docker composer up

The docker composer operation builds our utility, runs the migration, and launches our ASP.NET utility with the .NET runtime. To entry the working resolution, go to http://localhost:8080/Footwear.

Though our utility interface is straightforward, it demonstrates performance via all tiers, from the view all the way down to the database.

.NET on Linux Simply Works

See the full repository for an outline of our resolution. The following article will cowl our migration intimately, in addition to suggestions and tips to make our Docker photos lean.

.NET on Linux is greater than only a pipe dream: It’s a viable language, runtime, and OS mixture. Many builders raised on Visible Studio could not have expertise utilizing .NET CLI to its fullest, however these instruments are efficient and highly effective.

Additional Studying on the Toptal Engineering Weblog:

The Toptal Engineering Weblog extends its gratitude to Henok Tsegaye for reviewing the code samples offered on this article.



[ad_2]

Leave a Reply