Wednesday, 1 March 2023

Model Validation In ASP.NET MVC Core 3.1

 In this article we will understand the concept of model validation in ASP.NET MVC core 3.1. It is valid for any version of MVC core. These validations are available in System.ComponentModel.DataAnnotations namespace. Validation attributes let us specify validation rules for model properties. Model state represents errors that come from two sub systems' model binding and model validation.

 
There are in-built attributes in ASP.NET MVC core,
 
Attribute
Description
CreditCard
This validates that the property has a credit card format.
Compare
This attribute validates that two property in model class match like password and compare password.
EmailAddress
This validates the property has email address format.
Phone
This validates that the property has a telephone number format.
Range
This validates that the property value within a specified range.
RegularExpression
This validates that the property value matches a specified regular expression.
Required
This validates that the field is not null
StringLength
This validates that a string property value doesn't exceed a specified length limit.
Url
This validates that the property has a URL format.
Remote
This validates input on the client by calling an action method on the server
 
Step 1
 
Start-up Visual Studio 2019. Now click on create new project and Choose ASP.NET Core Web Application and click on “Next”
 
Model Validation In ASP.NET MVC Core 3.1
 
After clicking next, another wizard will open. Under the project name, give a meaningful name to your project and click on create.
 
Model Validation In ASP.NET MVC Core 3.1
 
That will open up another new wizard. Select ASP.Net Core 3.0 from the dropdown. If not, select default. Choose Web Application (Model-View-Controller) template and click on create which will create ASP.Net Core Application.
 
Model Validation In ASP.NET MVC Core 3.1
 
Step 2
 
Now right click on Models folder and “Add” class and name it Student.
  1. using System;    
  2. using System.ComponentModel.DataAnnotations;    
  3.     
  4. namespace MvcCoreModelValidation_Demo.Models    
  5. {    
  6.     public class Student    
  7.     {    
  8.         [Key]    
  9.         public int Id { getset; }    
  10.     
  11.         [Required(ErrorMessage = "Please enter name")]    
  12.         [StringLength(100)]    
  13.         public string Name { getset; }    
  14.     
  15.         [Required(ErrorMessage = "Please choose gender")]    
  16.         public string Gender { getset; }    
  17.     
  18.         [Required(ErrorMessage = "Please enter date of birth")]    
  19.         [Display(Name = "Date of Birth")]    
  20.         [DataType(DataType.Date)]    
  21.         public DateTime DateofBirth { getset; }    
  22.     
  23.         [Required(ErrorMessage = "Choose batch time")]  
  24.         [Display(Name = "Batch Time")]  
  25.         [DataType(DataType.Time)]   
  26.         public DateTime BatchTime { getset; }   
  27.     
  28.         [Required(ErrorMessage = "Please enter phone number")]    
  29.         [Display(Name = "Phone Number")]    
  30.         [Phone]    
  31.         public string PhoneNumber { getset; }    
  32.     
  33.         [Required(ErrorMessage = "Please enter email address")]  
  34.         [Display(Name = "Email Address")]   
  35.         [EmailAddress]   
  36.         public string Email { getset; }  
  37.     
  38.         [Required(ErrorMessage = "Please enter website url")]    
  39.         [Display(Name = "Website Url")]    
  40.         [Url]    
  41.         public string WebSite { getset; }    
  42.     
  43.         [Required(ErrorMessage = "Please enter password")]    
  44.         [DataType(DataType.Password)]    
  45.         public string Password { getset; }    
  46.     
  47.         [Required(ErrorMessage = "Please enter confirm password")]    
  48.         [Display(Name = "Confirm Password")]    
  49.         [Compare("Password", ErrorMessage = "Password and confirm password does not match")]    
  50.         public string ConfirmPassword { getset; }    
  51.     }    
  52. }    
Step 3
 
Now open HomeController which is added when we created new project. Write the following code for Index and New IActionResult methods.
  1. using Microsoft.AspNetCore.Mvc;  
  2. using MvcCoreModelValidation_Demo.Models;  
  3.   
  4. namespace MvcCoreModelValidation_Demo.Controllers  
  5. {  
  6.     public class HomeController : Controller  
  7.     {  
  8.         public IActionResult Index()  
  9.         {  
  10.             return View();  
  11.         }  
  12.   
  13.         [HttpPost]  
  14.         [ValidateAntiForgeryToken]  
  15.         public IActionResult Index(Student student)  
  16.         {  
  17.             if (ModelState.IsValid)  
  18.             {  
  19.   
  20.             }  
  21.             return View();  
  22.         }  
  23.   
  24.     }  
  25. }  
Step 4
 
Right click on Index IActionResult method. “Add” view with default name “Index” if you don’t have it. Write the following code.
  1. @model MvcCoreModelValidation_Demo.Models.Student  
  2.   
  3. @{  
  4.     ViewData["Title"] = "Home Page";  
  5. }  
  6.   
  7. <div class="card">  
  8.     <div class="card-header bg-primary text-white text-uppercase">  
  9.         <h4>Student Information</h4>  
  10.     </div>  
  11.     <div class="card-body">  
  12.         <form asp-action="Index">  
  13.             <div class="row">  
  14.                 <div class="col-md-6">  
  15.                     <div class="form-group">  
  16.                         <label asp-for="Name" class="lable-control"></label>  
  17.                         <input asp-for="Name" class="form-control" />  
  18.                         <span asp-validation-for="Name" class="text-danger"></span>  
  19.                     </div>  
  20.                 </div>  
  21.                 <div class="col-md-6">  
  22.                     <div class="form-group">  
  23.                         <label asp-for="Gender" class="lable-control"></label>  
  24.                         <select class="custom-select">  
  25.                             <option value="">Choose Gender</option>  
  26.                             <option value="Male">Male</option>  
  27.                             <option value="Female">Female</option>  
  28.                         </select>  
  29.                         <span asp-validation-for="Gender" class="text-danger"></span>  
  30.                     </div>  
  31.                 </div>  
  32.             </div>  
  33.             <div class="row">  
  34.                 <div class="col-md-6">  
  35.                     <div class="form-group">  
  36.                         <label asp-for="DateofBirth" class="lable-control"></label>  
  37.                         <input asp-for="DateofBirth" class="form-control" />  
  38.                         <span asp-validation-for="DateofBirth" class="text-danger"></span>  
  39.                     </div>  
  40.                 </div>  
  41.                 <div class="col-md-6">  
  42.                     <div class="form-group">  
  43.                         <label asp-for="BatchTime" class="lable-control"></label>  
  44.                         <input asp-for="BatchTime" class="form-control" />  
  45.                         <span asp-validation-for="BatchTime" class="text-danger"></span>  
  46.                     </div>  
  47.                 </div>  
  48.             </div>  
  49.             <div class="row">  
  50.                 <div class="col-md-4">  
  51.                     <div class="form-group">  
  52.                         <label asp-for="PhoneNumber" class="lable-control"></label>  
  53.                         <input asp-for="PhoneNumber" class="form-control" />  
  54.                         <span asp-validation-for="PhoneNumber" class="text-danger"></span>  
  55.                     </div>  
  56.                 </div>  
  57.                 <div class="col-md-4">  
  58.                     <div class="form-group">  
  59.                         <label asp-for="Email" class="lable-control"></label>  
  60.                         <input asp-for="Email" class="form-control" />  
  61.                         <span asp-validation-for="Email" class="text-danger"></span>  
  62.                     </div>  
  63.                 </div>  
  64.                 <div class="col-md-4">  
  65.                     <div class="form-group">  
  66.                         <label asp-for="WebSite" class="lable-control"></label>  
  67.                         <input asp-for="WebSite" class="form-control" />  
  68.                         <span asp-validation-for="WebSite" class="text-danger"></span>  
  69.                     </div>  
  70.                 </div>  
  71.             </div>  
  72.             <div class="row">  
  73.                 <div class="col-md-6">  
  74.                     <div class="form-group">  
  75.                         <label asp-for="Password" class="lable-control"></label>  
  76.                         <input asp-for="Password" class="form-control" />  
  77.                         <span asp-validation-for="Password" class="text-danger"></span>  
  78.                     </div>  
  79.                 </div>  
  80.                 <div class="col-md-6">  
  81.                     <div class="form-group">  
  82.                         <label asp-for="ConfirmPassword" class="lable-control"></label>  
  83.                         <input asp-for="ConfirmPassword" class="form-control" />  
  84.                         <span asp-validation-for="ConfirmPassword" class="text-danger"></span>  
  85.                     </div>  
  86.                 </div>  
  87.             </div>  
  88.             <div class="form-group">  
  89.                 <button type="submit" class="btn btn-primary rounded-0">Submit</button>  
  90.             </div>  
  91.         </form>  
  92.     </div>  
  93. </div>  
Step 5 
 
Build and run your application by pressing ctrl+F5
 
Model Validation In ASP.NET MVC Core 3.1

    Sunday, 26 February 2023

    How to Transfer/Move a Docker Image to Another System?

     In an ideal scenario, transferring docker images is done through the Docker Registry or though a fully-managed provider such as AWS’s ECR or Google’s GCR. You can easily upload an image through the docker push command, and others can pull the image using the docker pull command.

    Although, if you need to move an image from one host to another to test the image before sending it to the production environment, or you want to share the image with someone in the office, then it can be achieved by exporting the image as a .tar file.

    Docker supports two different types of methods for saving the container images to a single tarball.

    1. docker save - Save is used to persist an image (not a container)
    2. docker export - Export is used to persist a container (not an image)

    Using Docker Save Command:

    Saving Docker Image:

    First, we will stick to the plan, that is saving the image only. Now, let's walk through the docker save command. Assume that you need a Python image with Alpine, which can be pulled from Docker Hub:

    $ docker pull python:2.7.17-alpine3.9
    2.7.17-alpine3.9: Pulling from library/python
    e7c96db7181b: Already exists
    1819f4b92bc2: Already exists
    8061b3761cb3: Pull complete
    73aebae115de: Pull complete
    Digest: sha256:5f6059d78f530c3c59c4842e104ddcfc772a27fb8fac0d900f4d77bcb4621d9b
    Status: Downloaded newer image for python:2.7.17-alpine3.9
    docker.io/library/python:2.7.17-alpine3.9
    

    After adding a few files or making changes in the container, you decide to create a tarball of the image to provide it to your colleague. You can achieve this by running the below-mentioned command:

    $ docker save python:2.7.17-alpine3.9 > /path/to/save/my-python-container.tar
    

    Just make sure that you use the exact image name and the tag during tar creation. In our case, it was python:2.7.17-alpine3.9. You can verify if the above command worked:

    $ du -h my-python-container.tar 
    75M my-python-container.tar
    

    Now, you can send the .tar file to another person via rsync, scp or a similar file transfer protocol as per your preference.

    Loading Docker Image:

    Once the target machine has the .tar file, you can load the image into the local registry using command docker load :

    $ docker load < my-python-container.tar
    

    Now, cross-check if you have that image on the target machine by using docker images or docker image list. The end result will be something like below :

    $ docker image list
    REPOSITORY   TAG               IMAGE ID       CREATED              SIZE
    python       2.7.17-alpine3.9  3f0e580ded94   2 hours ago          74.9MB
    

    Using Docker Export Command:

    Exporting Docker Container:

    Note: The docker export command will not export the content of the volume, which is attached to the container. In this case, you need to run an additional command to backup, restore or migrate the existing volume. You can read more about this here.

    Looking at the docker export method, first we will pull an Alpine image:

    $ docker pull alpine
    Using default tag: latest
    latest: Pulling from library/alpine
    e6b0cf9c0882: Pull complete
    Digest: sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
    Status: Downloaded newer image for alpine:latest
    docker.io/library/alpine:latest
    
    

    Now, you can run the instance in detach mode so that the container doesn’t get destroyed when we exit it.

    $ docker run -it --detach --name alpine-t alpine
    

    To get the container ID and name which we created, we can use the docker ps command. Just in case, if in your machine the container has/was stopped for some reason, you can still get the ID and name by using docker ps -a:

    $ docker ps
    CONTAINER ID  IMAGE  COMMAND   CREATED         STATUS        PORTS    NAMES
    35f34fabfa84  alpine "/bin/sh" 14 seconds ago  8 seconds ago           alpine-t
    

    As we can see, our container id is 35f34fabfa84 (it will be different for you), or you can use the container name as well; in our case, it is alpine-t. Now, we can run the docker export command to export the instance’s image:

    $ docker export 35f34fabfa84 > alpine-t.tar
    

    Alternatively, you can also use OPTIONS to do the same, and your .tar file will be ready for transfer.

    $ docker export --output="alpine-t.tar" 35f34fabfa84
    

    Importing Docker Container:

    Now, you can import the .tar file to the target machine by using docker import:

    $ sudo tar -c alpine-t.tar | docker import - alpine-t
    

    To verify, you can run the container using --rm (it will destroy the container once you execute it):

    $ docker run --rm -it --name alpine-test alpine-t:[TAG]

    5 ways to move Docker container to another host

     

    How to move Docker container to another host

    There is no straightforward way to directly move Docker container from one host to another. We workaround this by using one or more of these methods for the migration.

    1. Export and import containers

    Exporting a container means creating a compressed file from the container’s file system. The exported file is saved as a ‘gzip’ file.

    docker export container-name | gzip > container-name.gz

     

    This compressed file is then copied over to the new host via file transfer tools such as scp or rsync. In the new host, this gzip file is then imported into a new container.

    zcat container-name.gz | docker import - container-name

     

    The new container created in the new host can be accessed using ‘docker run’ command.

    One drawback of export tool is that, it does not copy ports and variables, or the underlying data volume which contains the container data.

    This can lead to errors when trying to load the container in another host. In such cases, we opt for Docker image migration to move containers from one host to another.

     

    2. Container image migration

    The most commonly used method to move Docker container to another host, is by migrating the image linked to that container.

    For the container that has to be moved, first its Docker image is saved into a compressed file using ‘docker commit’ command.

    docker commit container-id image-name

     

    The image that is generated is compressed and moved into the new host machine. In the new host, a new container is created with ‘docker run’.

    Using this method, the data volumes will not be migrated, but it preserves the data of the application created inside the container.

    3. Save and load images

    A docker image is a package of code, libraries, configuration files, etc. for an application. Docker containers are created out of these images.

    The images can be compressed using ‘docker save’ and moved to a new host.

    docker save image-name > image-name.tar

     

    In the new host, this compressed image file can be used to create new image using ‘docker load’.

    cat image-name.tar | docker load

     

    4. Migrate data volumes

    Data volumes in Docker machines are shared directories that contains the data specific to containers. The data in volumes are persistent and will not be lost during container recreation.

    When Docker containers or images are moved from one host to another using export or commit tools, the underlying data volume is not migrated.

    In such situations, the directory containing data is manually moved to the new host. Then containers are created there with reference to that directory as its data volume.

    Another fool proof method is to backup and restore the data volume by passing ‘–volumes-from’ parameter in the ‘docker run’ command.

    docker run --rm --volumes-from datavolume-name -v $(pwd):/backup image-name tar cvf  backup.tar /path-to-datavolume

    Here, datavolume-name is the /path/to/volume. This command provides a backup of the data volume. To specify the working directory, we can specify the -w /backup as well. The backup generated in /backup folder can be moved to new host via scp or ftp tools.

    Copied backup is then extracted and restored to the data volume in the new container there.

     docker run --rm --volumes-from datavolume-name -v $(pwd):/backup image-name bash -c "cd /path-to-datavolume && tar xvf /backup/backup.tar --strip 1"
    
    

    5. Move entire Docker containers

    The methods we saw here are applicable for individual containers. But in cases where all the containers are to be moved from one host to another, we adopt another method.

    This method includes copying the entire “/var/lib/docker” directory to new host. To make this method successful, a few critical points are ensured.

    • The permissions and ownership of the folders are preserved.
    • Docker service is stopped before the move.
    • Docker versions in two hosts are verified to be compatible.
    • Container list and functionality is verified before and after the move.
    • Paths to the entry points and other configuration files are maintained.

    In cases when this method does not work due to any hiccups, we configure custom scripts to migrate the containers and images from one host to another.

    Monday, 13 February 2023

    ASP.Net Core MVC: Get JSON data from URL

     In this article I will explain with an example, how to get JSON data from URL inside Controller’s Action method in ASP.Net Core MVC.

    The JSON data will be read from the remote URL using WebClient class in ASP.Net Core MVC.
    The JSON string returned from the API
    The following JSON string is returned from the ASPSnippets Test API.
    [
       {
          "CustomerId":1,
          "Name":"John Hammond",
          "Country":"United States"
       },
       {
          "CustomerId":2,
          "Name":"Mudassar Khan",
          "Country":"India"
       },
       {
          "CustomerId":3,
          "Name":"Suzanne Mathews",
          "Country":"France"
       },
       {
          "CustomerId":4,
          "Name":"Robert Schidner",
          "Country":"Russia"
       }
    ]
     
     
    Namespaces
    You will need to import the following namespace.
    using System.Net;
     
     
    Controller
    The Controller consists of the following Action method.
    Action method for handling GET operation
    Inside this Action method, first the JSON string is downloaded from an API using DownloadString method of the WebClient class.
    Note: SecurityProtocol needs to be set to TLS 1.2 (3072) in order to call an API.
     
    Finally, the JSON string is returned using the Content function.
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            //Fetch the JSON string from URL.
            ServicePointManager.Expect100Continue = true;
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            string json = (new WebClient()).DownloadString("https://raw.githubusercontent.com/aspsnippets/test/master/Customers.json");
     
            //Return the JSON string.
            return Content(json);
        }
    }