Setting Up Multi-Region YugabyteDB on Kubernetes

In this article, we will explore setting up a synchronously replicated multi-region YugabyteDB cluster on Kubernetes. To explore other multi-region deployment topologies supported by YugabyteDB, refer to the Multi-Region Deployments section of YugabyteDB docs.

#kubernetes 

What is GEEK

Buddha Community

Setting Up Multi-Region YugabyteDB  on Kubernetes
Hermann  Frami

Hermann Frami

1651383480

A Simple Wrapper Around Amplify AppSync Simulator

This serverless plugin is a wrapper for amplify-appsync-simulator made for testing AppSync APIs built with serverless-appsync-plugin.

Install

npm install serverless-appsync-simulator
# or
yarn add serverless-appsync-simulator

Usage

This plugin relies on your serverless yml file and on the serverless-offline plugin.

plugins:
  - serverless-dynamodb-local # only if you need dynamodb resolvers and you don't have an external dynamodb
  - serverless-appsync-simulator
  - serverless-offline

Note: Order is important serverless-appsync-simulator must go before serverless-offline

To start the simulator, run the following command:

sls offline start

You should see in the logs something like:

...
Serverless: AppSync endpoint: http://localhost:20002/graphql
Serverless: GraphiQl: http://localhost:20002
...

Configuration

Put options under custom.appsync-simulator in your serverless.yml file

| option | default | description | | ------------------------ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | | apiKey | 0123456789 | When using API_KEY as authentication type, the key to authenticate to the endpoint. | | port | 20002 | AppSync operations port; if using multiple APIs, the value of this option will be used as a starting point, and each other API will have a port of lastPort + 10 (e.g. 20002, 20012, 20022, etc.) | | wsPort | 20003 | AppSync subscriptions port; if using multiple APIs, the value of this option will be used as a starting point, and each other API will have a port of lastPort + 10 (e.g. 20003, 20013, 20023, etc.) | | location | . (base directory) | Location of the lambda functions handlers. | | refMap | {} | A mapping of resource resolutions for the Ref function | | getAttMap | {} | A mapping of resource resolutions for the GetAtt function | | importValueMap | {} | A mapping of resource resolutions for the ImportValue function | | functions | {} | A mapping of external functions for providing invoke url for external fucntions | | dynamoDb.endpoint | http://localhost:8000 | Dynamodb endpoint. Specify it if you're not using serverless-dynamodb-local. Otherwise, port is taken from dynamodb-local conf | | dynamoDb.region | localhost | Dynamodb region. Specify it if you're connecting to a remote Dynamodb intance. | | dynamoDb.accessKeyId | DEFAULT_ACCESS_KEY | AWS Access Key ID to access DynamoDB | | dynamoDb.secretAccessKey | DEFAULT_SECRET | AWS Secret Key to access DynamoDB | | dynamoDb.sessionToken | DEFAULT_ACCESS_TOKEEN | AWS Session Token to access DynamoDB, only if you have temporary security credentials configured on AWS | | dynamoDb.* | | You can add every configuration accepted by DynamoDB SDK | | rds.dbName | | Name of the database | | rds.dbHost | | Database host | | rds.dbDialect | | Database dialect. Possible values (mysql | postgres) | | rds.dbUsername | | Database username | | rds.dbPassword | | Database password | | rds.dbPort | | Database port | | watch | - *.graphql
- *.vtl | Array of glob patterns to watch for hot-reloading. |

Example:

custom:
  appsync-simulator:
    location: '.webpack/service' # use webpack build directory
    dynamoDb:
      endpoint: 'http://my-custom-dynamo:8000'

Hot-reloading

By default, the simulator will hot-relad when changes to *.graphql or *.vtl files are detected. Changes to *.yml files are not supported (yet? - this is a Serverless Framework limitation). You will need to restart the simulator each time you change yml files.

Hot-reloading relies on watchman. Make sure it is installed on your system.

You can change the files being watched with the watch option, which is then passed to watchman as the match expression.

e.g.

custom:
  appsync-simulator:
    watch:
      - ["match", "handlers/**/*.vtl", "wholename"] # => array is interpreted as the literal match expression
      - "*.graphql"                                 # => string like this is equivalent to `["match", "*.graphql"]`

Or you can opt-out by leaving an empty array or set the option to false

Note: Functions should not require hot-reloading, unless you are using a transpiler or a bundler (such as webpack, babel or typescript), un which case you should delegate hot-reloading to that instead.

Resource CloudFormation functions resolution

This plugin supports some resources resolution from the Ref, Fn::GetAtt and Fn::ImportValue functions in your yaml file. It also supports some other Cfn functions such as Fn::Join, Fb::Sub, etc.

Note: Under the hood, this features relies on the cfn-resolver-lib package. For more info on supported cfn functions, refer to the documentation

Basic usage

You can reference resources in your functions' environment variables (that will be accessible from your lambda functions) or datasource definitions. The plugin will automatically resolve them for you.

provider:
  environment:
    BUCKET_NAME:
      Ref: MyBucket # resolves to `my-bucket-name`

resources:
  Resources:
    MyDbTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: myTable
      ...
    MyBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: my-bucket-name
    ...

# in your appsync config
dataSources:
  - type: AMAZON_DYNAMODB
    name: dynamosource
    config:
      tableName:
        Ref: MyDbTable # resolves to `myTable`

Override (or mock) values

Sometimes, some references cannot be resolved, as they come from an Output from Cloudformation; or you might want to use mocked values in your local environment.

In those cases, you can define (or override) those values using the refMap, getAttMap and importValueMap options.

  • refMap takes a mapping of resource name to value pairs
  • getAttMap takes a mapping of resource name to attribute/values pairs
  • importValueMap takes a mapping of import name to values pairs

Example:

custom:
  appsync-simulator:
    refMap:
      # Override `MyDbTable` resolution from the previous example.
      MyDbTable: 'mock-myTable'
    getAttMap:
      # define ElasticSearchInstance DomainName
      ElasticSearchInstance:
        DomainEndpoint: 'localhost:9200'
    importValueMap:
      other-service-api-url: 'https://other.api.url.com/graphql'

# in your appsync config
dataSources:
  - type: AMAZON_ELASTICSEARCH
    name: elasticsource
    config:
      # endpoint resolves as 'http://localhost:9200'
      endpoint:
        Fn::Join:
          - ''
          - - https://
            - Fn::GetAtt:
                - ElasticSearchInstance
                - DomainEndpoint

Key-value mock notation

In some special cases you will need to use key-value mock nottation. Good example can be case when you need to include serverless stage value (${self:provider.stage}) in the import name.

This notation can be used with all mocks - refMap, getAttMap and importValueMap

provider:
  environment:
    FINISH_ACTIVITY_FUNCTION_ARN:
      Fn::ImportValue: other-service-api-${self:provider.stage}-url

custom:
  serverless-appsync-simulator:
    importValueMap:
      - key: other-service-api-${self:provider.stage}-url
        value: 'https://other.api.url.com/graphql'

Limitations

This plugin only tries to resolve the following parts of the yml tree:

  • provider.environment
  • functions[*].environment
  • custom.appSync

If you have the need of resolving others, feel free to open an issue and explain your use case.

For now, the supported resources to be automatically resovled by Ref: are:

  • DynamoDb tables
  • S3 Buckets

Feel free to open a PR or an issue to extend them as well.

External functions

When a function is not defined withing the current serverless file you can still call it by providing an invoke url which should point to a REST method. Make sure you specify "get" or "post" for the method. Default is "get", but you probably want "post".

custom:
  appsync-simulator:
    functions:
      addUser:
        url: http://localhost:3016/2015-03-31/functions/addUser/invocations
        method: post
      addPost:
        url: https://jsonplaceholder.typicode.com/posts
        method: post

Supported Resolver types

This plugin supports resolvers implemented by amplify-appsync-simulator, as well as custom resolvers.

From Aws Amplify:

  • NONE
  • AWS_LAMBDA
  • AMAZON_DYNAMODB
  • PIPELINE

Implemented by this plugin

  • AMAZON_ELASTIC_SEARCH
  • HTTP
  • RELATIONAL_DATABASE

Relational Database

Sample VTL for a create mutation

#set( $cols = [] )
#set( $vals = [] )
#foreach( $entry in $ctx.args.input.keySet() )
  #set( $regex = "([a-z])([A-Z]+)")
  #set( $replacement = "$1_$2")
  #set( $toSnake = $entry.replaceAll($regex, $replacement).toLowerCase() )
  #set( $discard = $cols.add("$toSnake") )
  #if( $util.isBoolean($ctx.args.input[$entry]) )
      #if( $ctx.args.input[$entry] )
        #set( $discard = $vals.add("1") )
      #else
        #set( $discard = $vals.add("0") )
      #end
  #else
      #set( $discard = $vals.add("'$ctx.args.input[$entry]'") )
  #end
#end
#set( $valStr = $vals.toString().replace("[","(").replace("]",")") )
#set( $colStr = $cols.toString().replace("[","(").replace("]",")") )
#if ( $valStr.substring(0, 1) != '(' )
  #set( $valStr = "($valStr)" )
#end
#if ( $colStr.substring(0, 1) != '(' )
  #set( $colStr = "($colStr)" )
#end
{
  "version": "2018-05-29",
  "statements":   ["INSERT INTO <name-of-table> $colStr VALUES $valStr", "SELECT * FROM    <name-of-table> ORDER BY id DESC LIMIT 1"]
}

Sample VTL for an update mutation

#set( $update = "" )
#set( $equals = "=" )
#foreach( $entry in $ctx.args.input.keySet() )
  #set( $cur = $ctx.args.input[$entry] )
  #set( $regex = "([a-z])([A-Z]+)")
  #set( $replacement = "$1_$2")
  #set( $toSnake = $entry.replaceAll($regex, $replacement).toLowerCase() )
  #if( $util.isBoolean($cur) )
      #if( $cur )
        #set ( $cur = "1" )
      #else
        #set ( $cur = "0" )
      #end
  #end
  #if ( $util.isNullOrEmpty($update) )
      #set($update = "$toSnake$equals'$cur'" )
  #else
      #set($update = "$update,$toSnake$equals'$cur'" )
  #end
#end
{
  "version": "2018-05-29",
  "statements":   ["UPDATE <name-of-table> SET $update WHERE id=$ctx.args.input.id", "SELECT * FROM <name-of-table> WHERE id=$ctx.args.input.id"]
}

Sample resolver for delete mutation

{
  "version": "2018-05-29",
  "statements":   ["UPDATE <name-of-table> set deleted_at=NOW() WHERE id=$ctx.args.id", "SELECT * FROM <name-of-table> WHERE id=$ctx.args.id"]
}

Sample mutation response VTL with support for handling AWSDateTime

#set ( $index = -1)
#set ( $result = $util.parseJson($ctx.result) )
#set ( $meta = $result.sqlStatementResults[1].columnMetadata)
#foreach ($column in $meta)
    #set ($index = $index + 1)
    #if ( $column["typeName"] == "timestamptz" )
        #set ($time = $result["sqlStatementResults"][1]["records"][0][$index]["stringValue"] )
        #set ( $nowEpochMillis = $util.time.parseFormattedToEpochMilliSeconds("$time.substring(0,19)+0000", "yyyy-MM-dd HH:mm:ssZ") )
        #set ( $isoDateTime = $util.time.epochMilliSecondsToISO8601($nowEpochMillis) )
        $util.qr( $result["sqlStatementResults"][1]["records"][0][$index].put("stringValue", "$isoDateTime") )
    #end
#end
#set ( $res = $util.parseJson($util.rds.toJsonString($util.toJson($result)))[1][0] )
#set ( $response = {} )
#foreach($mapKey in $res.keySet())
    #set ( $s = $mapKey.split("_") )
    #set ( $camelCase="" )
    #set ( $isFirst=true )
    #foreach($entry in $s)
        #if ( $isFirst )
          #set ( $first = $entry.substring(0,1) )
        #else
          #set ( $first = $entry.substring(0,1).toUpperCase() )
        #end
        #set ( $isFirst=false )
        #set ( $stringLength = $entry.length() )
        #set ( $remaining = $entry.substring(1, $stringLength) )
        #set ( $camelCase = "$camelCase$first$remaining" )
    #end
    $util.qr( $response.put("$camelCase", $res[$mapKey]) )
#end
$utils.toJson($response)

Using Variable Map

Variable map support is limited and does not differentiate numbers and strings data types, please inject them directly if needed.

Will be escaped properly: null, true, and false values.

{
  "version": "2018-05-29",
  "statements":   [
    "UPDATE <name-of-table> set deleted_at=NOW() WHERE id=:ID",
    "SELECT * FROM <name-of-table> WHERE id=:ID and unix_timestamp > $ctx.args.newerThan"
  ],
  variableMap: {
    ":ID": $ctx.args.id,
##    ":TIMESTAMP": $ctx.args.newerThan -- This will be handled as a string!!!
  }
}

Requires

Author: Serverless-appsync
Source Code: https://github.com/serverless-appsync/serverless-appsync-simulator 
License: MIT License

#serverless #sync #graphql 

Christa  Stehr

Christa Stehr

1602964260

50+ Useful Kubernetes Tools for 2020 - Part 2

Introduction

Last year, we provided a list of Kubernetes tools that proved so popular we have decided to curate another list of some useful additions for working with the platform—among which are many tools that we personally use here at Caylent. Check out the original tools list here in case you missed it.

According to a recent survey done by Stackrox, the dominance Kubernetes enjoys in the market continues to be reinforced, with 86% of respondents using it for container orchestration.

(State of Kubernetes and Container Security, 2020)

And as you can see below, more and more companies are jumping into containerization for their apps. If you’re among them, here are some tools to aid you going forward as Kubernetes continues its rapid growth.

(State of Kubernetes and Container Security, 2020)

#blog #tools #amazon elastic kubernetes service #application security #aws kms #botkube #caylent #cli #container monitoring #container orchestration tools #container security #containers #continuous delivery #continuous deployment #continuous integration #contour #developers #development #developments #draft #eksctl #firewall #gcp #github #harbor #helm #helm charts #helm-2to3 #helm-aws-secret-plugin #helm-docs #helm-operator-get-started #helm-secrets #iam #json #k-rail #k3s #k3sup #k8s #keel.sh #keycloak #kiali #kiam #klum #knative #krew #ksniff #kube #kube-prod-runtime #kube-ps1 #kube-scan #kube-state-metrics #kube2iam #kubeapps #kubebuilder #kubeconfig #kubectl #kubectl-aws-secrets #kubefwd #kubernetes #kubernetes command line tool #kubernetes configuration #kubernetes deployment #kubernetes in development #kubernetes in production #kubernetes ingress #kubernetes interfaces #kubernetes monitoring #kubernetes networking #kubernetes observability #kubernetes plugins #kubernetes secrets #kubernetes security #kubernetes security best practices #kubernetes security vendors #kubernetes service discovery #kubernetic #kubesec #kubeterminal #kubeval #kudo #kuma #microsoft azure key vault #mozilla sops #octant #octarine #open source #palo alto kubernetes security #permission-manager #pgp #rafay #rakess #rancher #rook #secrets operations #serverless function #service mesh #shell-operator #snyk #snyk container #sonobuoy #strongdm #tcpdump #tenkai #testing #tigera #tilt #vert.x #wireshark #yaml

Sean Robertson

Sean Robertson

1574307124

How to add CRUD Operations to Angular using ASP.NET Web API and MongoDB

MongoDB is a NoSQL, free, open source, high-performance, and cross-platform document-oriented database. MongoDB was developed by the 10gen company that is now called MongoDB Inc. MongoDB is written in C++ and stores data in a flexible, JSON-like format with a dynamic schema.

Prerequisites

  • We should have the basic knowledge of Angular, MongoDB, and Web API.
  • The Visual Studio Code IDE should be installed.
  • Robo 3T or Studio 3T should be installed.

Create a Database and Collection in MongoDB

MongoDB Environment Setup

Check how to set up the MongoDB environment and Robo 3T, from here.

Step 1

Now, open Robo 3T and connect to the local server.
Connecting to localhost

Step 2

Create a database with the name “employee” using Robo 3T (Check Link).

Create a Web API Project

Step 1

Open Visual Studio and create a new project.
Creating a project

Change the name to CrudWithMongoDB.

Changing project name

Choose the WEB API template.

Step 2

Now, add the MongoDB Driver for C# using NuGet Package Manager.

Go to Tools>>NuGet Package Manager >> Manage NuGet package for Solution.

Managing NuGet package

Step 3

Right-click the Models folder and add two classes, Employee and Status. Now, paste the following codes in these classes.

Add the required namespaces in the Employee class.

using MongoDB.Bson;  
using MongoDB.Bson.Serialization.Attributes;  

Employee class

 public class Employee  
       {  
           [BsonRepresentation(BsonType.ObjectId)]  
           public String Id { get; set; }  
           public string Name { get; set; }  
           public string  { get; set; }  
           public string Address { get; set; }  
           public string City { get; set; }  
           public string Country { get; set; }  
       }  

Status class

  public class Status  
       {  
           public string Result { set; get; }  
           public string Message { set; get; }  
       }  

Step 4

Now, add a connection string in the web.config file and add the following line in the App Settings section of that file.

<add key="connectionString" value="mongodb://localhost"/>    

Step 5

Right-click on the Controllers folder and add a new controller. Name it “Emp controller.”

Add the following namespaces in the Emp controller.

using MongoDB.Driver;  
using MongoDB.Bson;  
using CrudWithMongoDB.Models;  

Now, add a method to insert data into the database for inserting employee details.

    [Route("InsertEmployee")]  
           [HttpPost]  
           public object Addemployee(Employee objVM)  
           {  
               try  
               {   ///Insert Emoloyeee  
                   #region InsertDetails  
                   if (objVM.Id == null)  
                   {  
                       string constr = ConfigurationManager.AppSettings["connectionString"];  
                       var Client = new MongoClient(constr);  
                       var DB = Client.GetDatabase("Employee");  
                       var collection = DB.GetCollection<Employee>("EmployeeDetails");  
                       collection.InsertOne(objVM);  
                       return new Status  
                       { Result = "Success", Message = "Employee Details Insert Successfully" };  
                   }  
                   #endregion  
                   ///Update Emoloyeee  
                   #region updateDetails  
                   else  
                   {  
                       string constr = ConfigurationManager.AppSettings["connectionString"];  
                       var Client = new MongoClient(constr);  
                       var Db = Client.GetDatabase("Employee");  
                       var collection = Db.GetCollection<Employee>("EmployeeDetails");  

                       var update = collection.FindOneAndUpdateAsync(Builders<Employee>.Filter.Eq("Id", objVM.Id), Builders<Employee>.Update.Set("Name", objVM.Name).Set("Department", objVM.Department).Set("Address", objVM.Address).Set("City", objVM.City).Set("Country", objVM.Country));  

                       return new Status  
                       { Result = "Success", Message = "Employee Details Update Successfully" };  
                   }  
                   #endregion  
               }  

               catch (Exception ex)  
               {  
                   return new Status  
                   { Result = "Error", Message = ex.Message.ToString() };  
               }  

           }  

Add a new method to delete employee details.

#region DeleteEmployee  
     [Route("Delete")]  
     [HttpGet]  
     public object Delete(string id)  
     {  
         try  
         {  
             string constr = ConfigurationManager.AppSettings["connectionString"];  
             var Client = new MongoClient(constr);  
             var DB = Client.GetDatabase("Employee");  
             var collection = DB.GetCollection<Employee>("EmployeeDetails");  
             var DeleteRecored = collection.DeleteOneAsync(  
                            Builders<Employee>.Filter.Eq("Id", id));  
             return new Status  
             { Result = "Success", Message = "Employee Details Delete  Successfully" };  

         }  
         catch (Exception ex)  
         {  
             return new Status  
             { Result = "Error", Message = ex.Message.ToString() };  
         }  

     }  
     #endregion  

Add a method to get Employee details.

  #region Getemployeedetails  
           [Route("GetAllEmployee")]  
           [HttpGet]  
           public object GetAllEmployee()  
           {  
               string constr = ConfigurationManager.AppSettings["connectionString"];  
               var Client = new MongoClient(constr);  
               var db = Client.GetDatabase("Employee");  
               var collection = db.GetCollection<Employee>("EmployeeDetails").Find(new BsonDocument()).ToList();  
               return Json(collection);  

           }  
           #endregion  

Add a method to get Employee details by Id.

#region EmpdetaisById  
     [Route("GetEmployeeById")]  
     [HttpGet]  
     public object GetEmployeeById(string id)  
     {  
         string constr = ConfigurationManager.AppSettings["connectionString"];  
         var Client = new MongoClient(constr);  
         var DB = Client.GetDatabase("Employee");  
         var collection = DB.GetCollection<Employee>("EmployeeDetails");  
         var plant = collection.Find(Builders<Employee>.Filter.Where(s => s.Id == id)).FirstOrDefault();  
         return Json(plant);  

     }  
     #endregion 

Here is the complete Emp controller code.

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Net;  
using System.Net.Http;  
using System.Web.Http;  
using MongoDB.Driver;  
using MongoDB.Bson;  
using CrudWithMongoDB.Models;  
using System.Configuration;  

namespace CrudWithMongoDB.Controllers  
{  
    [RoutePrefix("Api/Employee")]  
    public class EmpController : ApiController  
    {  
        [Route("InsertEmployee")]  
        [HttpPost]  
        public object Addemployee(Employee objVM)  
        {  
            try  
            {   ///Insert Emoloyeee  
                #region InsertDetails  
                if (objVM.Id == null)  
                {  
                    string constr = ConfigurationManager.AppSettings["connectionString"];  
                    var Client = new MongoClient(constr);  
                    var DB = Client.GetDatabase("Employee");  
                    var collection = DB.GetCollection<Employee>("EmployeeDetails");  
                    collection.InsertOne(objVM);  
                    return new Status  
                    { Result = "Success", Message = "Employee Details Insert Successfully" };  
                }  
                #endregion  
                ///Update Emoloyeee  
                #region updateDetails  
                else  
                {  
                    string constr = ConfigurationManager.AppSettings["connectionString"];  
                    var Client = new MongoClient(constr);  
                    var Db = Client.GetDatabase("Employee");  
                    var collection = Db.GetCollection<Employee>("EmployeeDetails");  

                    var update = collection.FindOneAndUpdateAsync(Builders<Employee>.Filter.Eq("Id", objVM.Id), Builders<Employee>.Update.Set("Name", objVM.Name).Set("Department", objVM.Department).Set("Address", objVM.Address).Set("City", objVM.City).Set("Country", objVM.Country));  

                    return new Status  
                    { Result = "Success", Message = "Employee Details Update Successfully" };  
                }  
                #endregion  
            }  

            catch (Exception ex)  
            {  
                return new Status  
                { Result = "Error", Message = ex.Message.ToString() };  
            }  

        }  

        #region Getemployeedetails  
        [Route("GetAllEmployee")]  
        [HttpGet]  
        public object GetAllEmployee()  
        {  
            string constr = ConfigurationManager.AppSettings["connectionString"];  
            var Client = new MongoClient(constr);  
            var db = Client.GetDatabase("Employee");  
            var collection = db.GetCollection<Employee>("EmployeeDetails").Find(new BsonDocument()).ToList();  
            return Json(collection);  

        }  
        #endregion  
        #region EmpdetaisById  
        [Route("GetEmployeeById")]  
        [HttpGet]  
        public object GetEmployeeById(string id)  
        {  
            string constr = ConfigurationManager.AppSettings["connectionString"];  
            var Client = new MongoClient(constr);  
            var DB = Client.GetDatabase("Employee");  
            var collection = DB.GetCollection<Employee>("EmployeeDetails");  
            var plant = collection.Find(Builders<Employee>.Filter.Where(s => s.Id == id)).FirstOrDefault();  
            return Json(plant);  

        }  
        #endregion  
        #region DeleteEmployee  
        [Route("Delete")]  
        [HttpGet]  
        public object Delete(string id)  
        {  
            try  
            {  
                string constr = ConfigurationManager.AppSettings["connectionString"];  
                var Client = new MongoClient(constr);  
                var DB = Client.GetDatabase("Employee");  
                var collection = DB.GetCollection<Employee>("EmployeeDetails");  
                var DeleteRecored = collection.DeleteOneAsync(  
                               Builders<Employee>.Filter.Eq("Id", id));  
                return new Status  
                { Result = "Success", Message = "Employee Details Delete  Successfully" };  

            }  
            catch (Exception ex)  
            {  
                return new Status  
                { Result = "Error", Message = ex.Message.ToString() };  
            }  

        }  
        #endregion  
    }  
}  

Step 6

Now, let’s enable CORS. Go to Tools, open NuGet Package Manager, search for Cors, and install the Microsoft.Asp.Net.WebApi.Cors package.

Installing Microsoft.Asp.Net.Web.Cors package

Open Webapiconfig.cs and add the following lines.

EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");    
config.EnableCors(cors);   

Create an Project

Step 1

Create an Angular 7 project with the name “CrudwithMongoDB” by using the following command.

 ng new CrudwithMongoDB

Step 2

Open Visual Studio Code, open the newly created project, and add bootstrap to this project.

npm install bootstrap --save

Step 3

Now, create two components for displaying the employee list page and adding a new employee page. To create the components, open terminal and use the following commands.

ng g c employee
ng g c addemployee

Step 4

Create a class named “employee” by using the following command.

ng g class employee

Add the required properties in the class.

export class Employee {  
    Id: string;  
    Name: string;  
    Department: string;  
    Address: string;  
    City: string;  
    Country: string;  
} 

Step 5

Create a service to call the Web API.

ng g s emprecord

Step 6

Open the emprecord service and import the required packages and classes. Add the following lines of code in the emprecord.service.ts file.

    import { Injectable } from '@angular/core';  
    import { Observable } from "rxjs";  
    import {HttpHeaders, HttpClient } from "@angular/common/http";  
    import { Employee } from "../app/employee";  
    @Injectable({  
      providedIn: 'root'  
    })  
    export class EmprecordService {  
       Url="http://localhost:14026/Api/Employee/";  
      constructor(private http:HttpClient) { }  
       InsertEmployee(employee:Employee)  
       {  
         debugger;  
        const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) };  
         return this.http.post<Employee[]>(this.Url+'/InsertEmployee/', employee,httpOptions)  
       }  
       GetEmployeeRecord():Observable<Employee[]>  
       {  
         debugger;  
        return this.http.get<Employee[]>(this.Url+"/GetAllEmployee")  
       }  
       DeleteEmployee(id:string):Observable<number>  
       {  
         debugger;  
        return this.http.get<number>(this.Url + '/Delete/?id='+id);  
       }  
       GetEmployeeById(id:string)  
       {  
        return this.http.get<Employee>(this.Url + '/GetEmployeeById/?id=' + id);  
       }  
       UpdatEmplouee(employee:Employee)  
       {  
        debugger;  
        const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) };  
         return this.http.post<Employee[]>(this.Url+'/UpdateEmployee/', employee,httpOptions)  
       }  

    }  

Step 7 - Add Paging and Searching

To add paging and searching, install the following library in the project. For pagination:

npm install --save ngx-pagination  

For searching:

npm i ng2-search-filter --save  

Export and import both these directives in the app.module.ts file.

import {NgxPaginationModule} from 'ngx-pagination';  
import { Ng2SearchPipeModule } from 'ng2-search-filter';  

Step 8

Now, open addemployee.component.html and add the following HTML.


    <div class="container" style="padding-top:40px;">    
      <div class="row">    
        <div class="col-md-10 mx-auto">    
          <div class="card mx-4">   
            <div class="card-head p-4">  
                <div class="col-sm-12 btn btn-success">  
                    Employee's Information  
                  </div>  
            </div>   
            <div class="card-body p-4">    
         <form [formGroup]="Addemployee" (ngSubmit)="onFormSubmit(Addemployee.value)">  
        <div class="col-sm-12">  
          <div class="card-body">  
            <!-- <div class="row"> -->  
            <div class="form-group ">  

              <label class="col-sm-2 control-label" for="Name">Name</label>  
              <div class="col-sm-10">  
                <input type="text" class="form-control" placeholder="Enter name" formControlName="Name">  
              </div>  
            </div>  
            <div class="form-group ">  
              <label class="col-sm-2 control-label" for="Department">Department</label>  
              <div class="col-sm-10">  
                <input type="text" class="form-control" placeholder="Enter Department" formControlName="Department">  
              </div>  
            </div>  
            <div class="form-group ">  
              <label class="col-sm-2 control-label" for="Address">Address</label>  
              <div class="col-sm-10">  
                <input type="text" class="form-control" placeholder="Enter Address" formControlName="Address">  
              </div>  
            </div>  
            <div class="form-group ">  
              <label class="col-sm-2 control-label" for="City">City</label>  
              <div class="col-sm-10">  
                <input type="text" class="form-control" placeholder="Enter City" formControlName="City">  
              </div>  
            </div>  
            <div class="form-group ">  
              <label class="col-sm-2 control-label" for="Country">Country</label>  
              <div class="col-sm-10">  
                <input type="text" class="form-control" placeholder="Enter Country" formControlName="Country">  
              </div>  
            </div>  

          </div>  
        </div>  
        <div class="col-6 text-right">    
            <button class="btn btn-primary px-10" type="submit">Add </button>  
          </div>  
      </form>  
          </div>    
        </div>    
      </div>    
      </div>   
    </div>   

Step 9

Open the addemployee.componet.ts file and add the following lines.

	import { Component, OnInit } from '@angular/core';  
    import { HttpClient } from "@angular/common/http";  
    import { FormGroup, FormControl } from '@angular/forms';  
    import { EmprecordService } from "../../emprecord.service";  
    import { Employee } from "../../employee";  
    import { Observable } from "rxjs";  
    import { identifierModuleUrl } from '@angular/compiler';  
    import { Router } from '@angular/router';  
    @Component({  
      selector: 'app-addemployee',  
      templateUrl: './addemployee.component.html',  
      styleUrls: ['./addemployee.component.css']  
    })  
    export class AddemployeeComponent implements OnInit {  
      massage: string;  
      dataSaved = false;  
      Addemployee:FormGroup;  
      EmployeeIdUpdate = "0";  
      constructor(private router: Router,private emprecordService:EmprecordService) { }  

      InsertEmployee(employee:Employee)  
      {  
    debugger;  
        if (this.EmployeeIdUpdate != "0") employee.Id=this.EmployeeIdUpdate;  
          this.emprecordService.InsertEmployee(employee).subscribe(  
            ()=>  
            {  
              if (this.EmployeeIdUpdate == "0") {  
                this.massage = 'Saved Successfully';  

              }  
              else  
              {  
                this.massage = 'Update Successfully';  
              }  
              this.dataSaved = true;  
              this.router.navigate(['/employee']);  
            })  
      }  
      onFormSubmit() {  
        const Emp = this.Addemployee.value;  
        this.InsertEmployee(Emp);  
      }  

      EmployeeEdit(id: string) {  
        debugger;  
        this.emprecordService.GetEmployeeById(id).subscribe(emp => {  
          this.massage = null;  
          this.dataSaved = false;  
          debugger;  
          this.EmployeeIdUpdate=id;  
          this.Addemployee.controls['Name'].setValue(emp.Name);  
          this.Addemployee.controls['Department'].setValue(emp.Department);  
          this.Addemployee.controls['City'].setValue(emp.City);  
          this.Addemployee.controls['Country'].setValue(emp.Country);  
          this.Addemployee.controls['Address'].setValue(emp.Address);  
        });  
        debugger;  
      }  
      clearform() {  
        debugger;  
        this.Addemployee.controls['Name'].setValue("");  
        this.Addemployee.controls['Department'].setValue("");  
        this.Addemployee.controls['Address'].setValue("");  
        this.Addemployee.controls['City'].setValue("");  
        this.Addemployee.controls['Country'].setValue("");  

      }  
      ngOnInit() {  
        this.Addemployee = new FormGroup({  

          Name: new FormControl(),  
          Department:new FormControl(),  
          Address:new FormControl(),  
          City:new FormControl(),  
          Country:new FormControl(),  
      });  
      let Id = localStorage.getItem("id");  
    if(Id!=null)  
    {  
      this.EmployeeEdit(Id) ;  
     }}  
    }  

Step 10

Open employee.componet.html and add this HTML.


    <div class="container" style="margin-bottom:20px;padding-top:20px;">  
      <div class="row">  
        <div class="col-sm-12 btn btn-success">  
          Employee's Information  
        </div>  
      </div>  
      <div class="col-sm-12" style="margin-bottom:20px;padding-top:20px;">  
        <div class="row">  
          <div class="col-sm-6">  
            <button type="button" class="btn btn-primary" data-toggle="modal" routerLink="/addemployee">  
              Add New Employee  
            </button>  
          </div>  
          <div class="col-sm-6">  
            <input class="form-control" type="text" name="search" [(ngModel)]="filter" placeholder="Search">  
          </div>  
        </div>  
      </div>  
    </div>  
    <div class="container" style="padding-top:20px;">  
      <table class="table table-striped">  
        <thead class="thead-dark">  
          <th>Name</th>  
          <th>Department</th>  
          <th>Address</th>  
          <th>City</th>  
          <th>Country</th>  
          <th>Action</th>  
        </thead>  
        <tbody>  
          <tr *ngFor="let e of emp | async|filter:filter| paginate: { itemsPerPage: 5, currentPage: p } ; let i=index">  
            <td>{{e.Name}}</td>  
            <td>{{e.Department}}</td>  
            <td>{{e.Address}}</td>  
            <td>{{e.City}}</td>  
            <td>{{e.Country}}</td>  
            <td>  
              <div class="btn-group">  
                <button type="button" class="btn btn-primary mr-1" (click)="EmployeeEdit(e.Id)">Edit</button>  
                <button type="button" class="btn btn-danger mr-1" (click)="Deleteemployee(e.Id)">Delete</button>  
              </div>  
            </td>  
          </tr>  
        </tbody>  
      </table>  
      <ul class="pagination">  
        <pagination-controls (pageChange)="p = $event"></pagination-controls>  
      </ul>  
    </div>  

Step 11

Open employee.componet.ts file and add the following lines.

	import { Component, OnInit } from '@angular/core';  
    import { Employee } from "../employee";  
    import { EmprecordService } from "../emprecord.service";  
    import { Observable } from "rxjs";  
    import { Router } from '@angular/router';  
    @Component({  
      selector: 'app-employee',  
      templateUrl: './employee.component.html',  
      styleUrls: ['./employee.component.css']  
    })  
    export class EmployeeComponent implements OnInit {  
      private emp: Observable<Employee[]>;  
      massage:String;  
      dataSaved=false;  
      constructor(private router: Router,private emprecordService:EmprecordService) { }  
       Loademployee()  
       {  
          debugger;  
          this.emp = this.emprecordService.GetEmployeeRecord();  
          console.log(this.emp);  

          debugger;  

       }  
       EmployeeEdit(id: string) {  
        debugger;  
       localStorage.removeItem("id");  
       localStorage.setItem("id",id.toString());  
        this.router.navigate(['/addemployee'], { queryParams: { Id: id } });  
        debugger;  
      }  
       Deleteemployee(id: string) {  
        if (confirm("Are You Sure To Delete this Informations")) {  

          this.emprecordService.DeleteEmployee(id).subscribe(  
            () => {  
              this.dataSaved = true;  
              this.massage = "Deleted Successfully";  
            }  
          );  
        }  
      }  
      ngOnInit() {  
        localStorage.clear();
        this.Loademployee();  

      }  

    }  

Step 12

Now, open app-routing.module.ts file and add the following lines to create routing.

	import { NgModule } from '@angular/core';  
    import { Routes, RouterModule } from '@angular/router';  
    import { EmployeeComponent } from "./employee/employee.component";  
    import { AddemployeeComponent } from "./employee/addemployee/addemployee.component";  

    const routes: Routes = [  
     {path:"employee",component:EmployeeComponent},  
     {path:"addemployee",component:AddemployeeComponent},  
    ];  

    @NgModule({  
      imports: [RouterModule.forRoot(routes)],  
      exports: [RouterModule]  
    })  
    export class AppRoutingModule { }  

Step 13

Now, open app.module.ts file and add the following lines.

import { BrowserModule } from '@angular/platform-browser';  
import { NgModule } from '@angular/core';  
import { FormsModule } from '@angular/forms';  
import { AppRoutingModule } from './app-routing.module';  
import { AppComponent } from './app.component';  
import { HttpClientModule,HttpClient} from '@angular/common/http';   
import { EmployeeComponent } from './employee/employee.component';  
import { ReactiveFormsModule } from "@angular/forms";  
import { EmprecordService } from "../app/emprecord.service";  
import { AddemployeeComponent } from './employee/addemployee/addemployee.component';   
import {NgxPaginationModule} from 'ngx-pagination';   
import { Ng2SearchPipeModule } from 'ng2-search-filter';  

@NgModule({  
  declarations: [  
    AppComponent,  
    EmployeeComponent,  
    AddemployeeComponent,  
  ],  
  imports: [  
    BrowserModule,FormsModule,  
    AppRoutingModule,HttpClientModule,ReactiveFormsModule,Ng2SearchPipeModule,NgxPaginationModule  
  ],  
  providers: [EmprecordService],  
  bootstrap: [AppComponent]  
})  
export class AppModule { }

Step 14

Now, let us run the project and redirect the URL to the Addemployee page.

Employee Information form

Step 15

Enter the details and click on the Add button.

Adding employees

Summary

In this article, we discussed how to perform CRUD operations using MongoDB, Angular 8, and Asp.net Web API.

#Angular #MongoDB #dotnet #webdev #api

藤本  結衣

藤本 結衣

1633367280

単純な挿入MYSQLデータベースを使用したASP.NETでの更新と削除の選択

この記事では、ASP.NET WebアプリケーションからMySQLデータベースにデータの選択、更新、および削除を挿入する方法について説明します。

それでは、次の手順に進みましょう。

  • ASP.NETWebページ
  • グリッドビューデータコントロールとMySQLデータベース

次に、MySQLAdminページを開き、[Create A New Table]-> [View]-> [Table Structure for Table`student`]を選択します。

CREATE TABLE IF NOT EXISTS `student` (  
 `SID` int(100) NOT NULL AUTO_INCREMENT,  
 `Name` varchar(100) NOT NULL,  
 `Address` varchar(500) NOT NULL,  
 `Email` varchar(100) NOT NULL,  
 `Mobile` varchar(25) NOT NULL,  
 PRIMARY KEY (`SID`)  
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=31 ; 



Visual Studio 2012のインスタンスを開き、新しいASP.NETWebアプリケーションを作成します。次の図に示すように、プロジェクトに「MYSQLCRUDApplication」という名前を付け



ます。コードビハインドファイル(Student.aspx.cs)に、次のようにコードを記述します

Student.aspx 

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true"  
CodeBehind="Student.aspx.cs" Inherits="MYSQLCRUDApplication.Student" %>  
  
<asp:Content ID="Content1" ContentPlaceHolderID="titleContent" runat="server">  
    Simple Insert Select Update and Delete in ASP.NET using MySQL Database   
</asp:Content>  
<asp:Content ID="Content2" ContentPlaceHolderID="head" runat="server">  
</asp:Content>  
<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">  
    <table>  
        <tr>  
            <td class="td">Name:</td>  
            <td>  
                <asp:TextBox ID="txtName" runat="server"></asp:TextBox></td>  
            <td>  
                <asp:Label ID="lblSID" runat="server" Visible="false"></asp:Label> </td>  
        </tr>  
        <tr>  
            <td class="td">Address:</td>  
            <td>  
                <asp:TextBox ID="txtAddress" runat="server"></asp:TextBox></td>  
            <td> </td>  
        </tr>  
        <tr>  
            <td class="td">Mobile:</td>  
            <td>  
                <asp:TextBox ID="txtMobile" runat="server"></asp:TextBox></td>  
            <td> </td>  
        </tr>  
        <tr>  
            <td class="td">Email ID:</td>  
            <td>  
                <asp:TextBox ID="txtEmail" runat="server"></asp:TextBox></td>  
            <td> </td>  
        </tr>  
        <tr>  
            <td></td>  
            <td>  
                <asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="btnSubmit_Click" />  
                <asp:Button ID="btnUpdate" runat="server" Text="Update" Visible="false"  
OnClick="btnUpdate_Click" />  
                <asp:Button ID="btnCancel" runat="server" Text="Cancel" OnClick="btnCancel_Click" /></td>  
            <td></td>  
        </tr>  
    </table>  
  
    <div style="padding: 10px; margin: 0px; width: 100%;">  
        <p>  
            Total Student:<asp:Label ID="lbltotalcount" runat="server" Font-Bold="true"></asp:Label>  
        </p>  
        <asp:GridView ID="GridViewStudent" runat="server" DataKeyNames="SID"   
            OnSelectedIndexChanged="GridViewStudent_SelectedIndexChanged"  
OnRowDeleting="GridViewStudent_RowDeleting">  
            <Columns>  
                <asp:CommandField HeaderText="Update" ShowSelectButton="True" />  
                <asp:CommandField HeaderText="Delete" ShowDeleteButton="True" />  
            </Columns>  
        </asp:GridView>  
    </div>  
</asp:Content>  

Web.configファイルで、次のように接続文字列を作成します。

Web.config 

<connectionStrings>  
    <add name="ConnectionString"  
connectionString="Server=localhost;userid=root;password=;Database=Testdb"  
providerName="MySql.Data.MySqlClient"/>  
 </connectionStrings>  

ここで、コードビハインドファイル「Student.aspx.cs」で次のコードを使用します。

Student.aspx.cs 

using System;  
using System.Collections.Generic;  
using System.Configuration;  
using System.Data;  
using System.Linq;  
using System.Web;  
using System.Web.UI;  
using System.Web.UI.WebControls;  
using MySql.Data.MySqlClient;  
  
  
namespace MYSQLCRUDApplication  
{  
    public partial class Student : System.Web.UI.Page  
    {  
        #region MySqlConnection Connection and Page Lode  
        MySqlConnection conn = new  
MySqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);          
        protected void Page_Load(object sender, EventArgs e)  
        {  
            Try  
            {  
                if (!Page.IsPostBack)  
                {  
                    BindGridView();  
                      
                }  
            }  
            catch (Exception ex)  
            {  
                ShowMessage(ex.Message);  
            }  
        }  
        #endregion  
        #region show message  
        /// <summary>  
        /// This function is used for show message.  
        /// </summary>  
        /// <param name="msg"></param>  
        void ShowMessage(string msg)  
        {  
            ClientScript.RegisterStartupScript(Page.GetType(), "validation", "<script  
language='javascript'>alert('" + msg + "');</script>");  
        }  
        /// <summary>  
        /// This Function is used TextBox Empty.  
        /// </summary>  
        void clear()  
        {  
            txtName.Text = string.Empty; txtAddress.Text = string.Empty; txtMobile.Text = string.Empty;  
txtEmail.Text = string.Empty;  
            txtName.Focus();  
        }  
        #endregion  
        #region bind data to GridViewStudent  
        private void BindGridView()  
        {   
            Try  
            {  
                if (conn.State == ConnectionState.Closed)  
                {  
                    conn.Open();  
                }  
                MySqlCommand cmd = new MySqlCommand("Select * from Student ORDER BY SID DESC;",  
conn);  
                MySqlDataAdapter adp = new MySqlDataAdapter(cmd);  
                DataSet ds = new DataSet();  
                adp.Fill(ds);  
                GridViewStudent.DataSource = ds;  
                GridViewStudent.DataBind();  
                lbltotalcount.Text = GridViewStudent.Rows.Count.ToString();  
            }  
            catch (MySqlException ex)  
            {  
                ShowMessage(ex.Message);  
            }  
            Finally  
            {  
                if (conn.State == ConnectionState.Open)  
                {  
                   conn.Close();  
                }  
            }  
        }  
        #endregion  
        #region Insert Data  
        /// <summary>  
        /// this code used to Student Data insert in MYSQL Database  
        /// </summary>  
        /// <param name="sender"></param>  
        /// <param name="e"></param>  
        protected void btnSubmit_Click(object sender, EventArgs e)  
        {  
            Try  
            {  
                conn.Open();  
                MySqlCommand cmd = new MySqlCommand("Insert into student (Name,Address,Mobile,Email )  
values (@Name,@Address,@Mobile,@Email)", conn);  
                cmd.Parameters.AddWithValue("@Name",txtName.Text);  
                cmd.Parameters.AddWithValue("@Address", txtAddress.Text);  
                cmd.Parameters.AddWithValue("@Mobile",txtMobile.Text);  
                cmd.Parameters.AddWithValue("@Email",txtEmail.Text);  
                cmd.ExecuteNonQuery();                 
                cmd.Dispose();   
                ShowMessage("Registered successfully......!");               
                clear();  
                BindGridView();  
            }  
            catch (MySqlException ex)  
            {  
                ShowMessage(ex.Message);  
            }  
            Finally  
            {  
                conn.Close();  
            }  
        }  
          
        #endregion   
        #region SelectedIndexChanged  
        /// <summary>  
        /// this code used to GridViewRow SelectedIndexChanged value show textbox  
        /// </summary>  
        /// <param name="sender"></param>  
        /// <param name="e"></param>  
        protected void GridViewStudent_SelectedIndexChanged(object sender, EventArgs e)  
        {  
            GridViewRow row = GridViewStudent.SelectedRow;  
            lblSID.Text = row.Cells[2].Text;  
            txtName.Text = row.Cells[3].Text;  
            txtAddress.Text = row.Cells[4].Text;  
            txtEmail.Text = row.Cells[5].Text;  
            txtMobile.Text = row.Cells[6].Text;  
            btnSubmit.Visible = false;  
            btnUpdate.Visible = true;  
        }  
        #endregion  
        #region Delete Student Data  
        /// <summary>  
        /// This code used to GridViewStudent_RowDeleting Student Data Delete  
        /// </summary>  
        /// <param name="sender"></param>  
        /// <param name="e"></param>  
        protected void GridViewStudent_RowDeleting(object sender, GridViewDeleteEventArgs e)  
        {  
            Try  
            {  
                conn.Open();  
                int SID = Convert.ToInt32(GridViewStudent.DataKeys[e.RowIndex].Value);  
                MySqlCommand cmd = new MySqlCommand("Delete From student where SID='" + SID + "'",  
conn);  
                cmd.ExecuteNonQuery();  
                cmd.Dispose();  
                ShowMessage("Student Data Delete Successfully......!");  
                GridViewStudent.EditIndex = -1;  
                BindGridView();  
            }  
            catch (MySqlException ex)  
            {  
                ShowMessage(ex.Message);  
            }  
            Finally  
            {  
                conn.Close();  
            }  
        }  
        #endregion  
        #region student data update  
        /// <summary>  
        /// This code used to student data update  
        /// </summary>  
        /// <param name="sender"></param>  
       /// <param name="e"></param>  
        protected void btnUpdate_Click(object sender, EventArgs e)  
        {  
            Try  
            {  
                conn.Open();  
                string SID = lblSID.Text;                
                MySqlCommand cmd = new MySqlCommand("update student Set  
Name=@Name,Address=@Address,Mobile=@Mobile,Email=@Email where SID=@SID", conn);  
                cmd.Parameters.AddWithValue("@Name", txtName.Text);  
                cmd.Parameters.AddWithValue("@Address", txtAddress.Text);  
                cmd.Parameters.AddWithValue("@Mobile", txtMobile.Text);  
                cmd.Parameters.AddWithValue("@Email", txtEmail.Text);  
                cmd.Parameters.AddWithValue("SID",SID);  
                cmd.ExecuteNonQuery();  
                cmd.Dispose();  
                ShowMessage("Student Data update Successfully......!");  
                GridViewStudent.EditIndex = -1;  
                BindGridView(); btnUpdate.Visible = false;  
            }  
            catch (MySqlException ex)  
            {  
                ShowMessage(ex.Message);  
            }  
            Finally  
            {  
                conn.Close();  
            }  
        }  
        #endregion  
        #region textbox clear  
        protected void btnCancel_Click(object sender, EventArgs e)  
        {  
            clear();  
        }  
        #endregion  
    }  
}   

ページを実行すると、次のようになります。



次に、学生データの挿入とグリッドビューのデータの表示を入力します。メッセージボックス「正常に登録されました」。



次に、Studentを選択し、データTextBoxを表示して、メッセージボックス「StudentDataupdatesuccessfully」に表示されているデータを更新します。



ここで、メッセージボックス「StudentDataDeleteSuccessfully」に表示されているStudentデータを削除します。



この記事がお役に立てば幸いです。他にご不明な点がございましたら、以下にコメントをお寄せください。

リンク: https://www.c-sharpcorner.com/

#aspdotnet #sql 

Ruth  Nabimanya

Ruth Nabimanya

1623169620

Multi-Region Database Deployments

Modern applications and services demand an always-on, low-latency experience for users no matter where they are on the planet. To meet these requirements, many deploy multiple instances of their applications and services across multiple cloud regions. This legacy approach leaves room for downtime and, even worse, inconsistencies in data. In this Refcard, we explore patterns and anti-patterns to multi-region database deployments — allowing your applications to survive a region failure without downtime while also ensuring consistent and low latency access to data no matter where you do business.

Table of Contents

► Introduction

► What Is a Multi-Region Application?

► Common Patterns and Anti-Patterns

► Final Thoughts

Section 1

Introduction

Deployed in the cloud, our modern applications and services demand an always-on, low latency experience for users no matter where they are on the planet. Whether you’re building a startup from the ground up or you are a member of a massive Fortune 500 development organization, these demands are typically the same.

To meet these requirements, many deploy multiple instances of their applications and services across multiple cloud regions. Some will deploy a database and synchronize it across multiple regions so that they can survive a regional outage as well. It’s not enough. This legacy approach leaves room for downtime and even worse, inconsistencies in data.

Deployment of an active-active database with multi-region capabilities that can be applied down to the table and row level of your data will allow you to not only survive a region failure without downtime, but also ensure consistent and low latency access to data no matter where you do business.

#database deployments #multi-region #multi-region application #multi-region database #multi-region database deployments #cross-​region