.NET on Linux: Not Only a Advertising Ploy

[ad_1]

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

Growth Surroundings

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

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

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

Challenge Scaffolding

On this pattern utility, we’ll spotlight ASP.NET growth and performance via a collection of use instances for a hypothetical shoe retailer stock administration system. As with all new .NET utility, we’ll must create an answer after which add a mission to it. We are able to leverage the .NET SDK CLI instruments to scaffold our new answer:

mkdir Shoestore && cd Shoestore
dotnet new sln

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

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

Subsequent, add the mission into the answer:

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

We now have a default answer and its contained ASP.NET mission. Earlier than continuing, be certain that the whole lot builds:

cd Shoestore.mvc/
dotnet restore
dotnet construct

Good growth follow encourages placing key companies and the appliance runtime into Docker containers for improved deployment and portability. Due to this fact, let’s create a easy Docker container to help our utility.

Utility Portability

Docker pictures usually reference one other dad or mum Docker picture as an accepted place to begin for important necessities like OS and primary options, together with databases. Following this Docker finest follow, create each a Dockerfile and a Docker Compose file for correct service configuration whereas referencing Microsoft-published dad or mum pictures. We’ll use Docker levels to maintain our picture small. Levels permit 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 mission packages
RUN dotnet restore
COPY Shoestore.mvc/* ./
# Create a launch construct
RUN dotnet construct -c Launch -o /app/construct

# Run the appliance 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 answer’s root listing. Initially, it’s going to solely include a reference to our utility service’s .Dockerfile:

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

Let’s additionally configure our surroundings 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 simple, 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 contains each our utility service and database.

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

# From the basis 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 deal with http://localhost:8080.

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

Earlier than we are able to specify the instruments we’d like, we should create a tool-manifest file:

# From the basis 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 accurately. Subsequent, run dotnet aspnet-codegenerator to check the ASP.NET instruments; the output must be a basic CLI utilization block.

Now we are able to use these instruments to create our utility.

MVC: Mannequin

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

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 knowledge from the database.

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

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

namespace Shoestore.mvc.Information;

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 Most important operate. We’ll embody 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. This may explicitly set the file paths to our view location in our Docker picture:

utilizing Microsoft.EntityFrameworkCore;
utilizing Shoestore.mvc.Information;

namespace Shoestore.mvc;

// ...

    public static void Most important(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 companies to the container.
        // ASP.NET has a recognized problem the place the ultimate constructed app does not know the place the view
        // recordsdata 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 right 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 growth mode. Add an else assertion with the next code:

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

Subsequent, run a fast check to make sure the brand new packages and the supply code edits compile accurately:

// 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? Identify { 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 the right way to translate between MS SQL Server and our utility. Let’s do that within the database context file, Shoestore/Shoestore.mvc/Information/ApplicationDBContext.cs:

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

namespace Shoestore.mvc.Information;

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 operating our migration till now we have a controller and look at in place.

MVC: Controller and View

We’ll create our controller utilizing the ASP.NET code era software. This software may be very highly effective however requires particular helper courses. Use the Design model packages for the essential 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 the whole lot operating.

Migration and Utility Check

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

All configuration and migration recordsdata are included in our repository. Let’s clone the total mission 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 operating answer, go to http://localhost:8080/Footwear.

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

.NET on Linux Simply Works

See the full repository for an outline of our answer. The subsequent article will cowl our migration intimately, in addition to ideas and tips to make our Docker pictures 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 might 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 introduced on this article.



[ad_2]

Leave a Reply