Showing posts with label .NET Core. Show all posts
Showing posts with label .NET Core. Show all posts

.NET 5+: the Future of .NET

Microsoft doesn't want to restrict the growth of their highly popular .NET development framework by requiring that it only run on Windows OS and that its components rely on Windows-based components like ASP.NET which relies on IIS.

Enter .NET Core 1, 1.1, 2, 5 (6)+: the Future of .NET.


One .NET Framework to rule them all? No. But a new, unified, cross-platform .NET Runtime? Yes.


With .NET 5 (and coming in hot down the pike, .NET 6), developers can use the languages (C#, F#, VB and C++/CLI) and framework (.NET) they are familiar with, to build applications that can run on a Windows, Linux or Mac OS. While .NET Core 1 and 2 lacked several expected features and felt fairly unsupportable, .NET 5 feels more familiar and addresses most issues (this is just the networking improvements made).

Formerly known as .NET Core 1, .NET Core 1.1 and then .NET Core 2, the future for the .NET Framework and associated runtime libraries will fall under the umbrella of what is simply called ".NET" (5 (current release), 6 (preview), with intermediate minor versions one would expect) as of the time of this writing. ASP.NET Core will continue to be labeled with the "Core" designation for now with the .NET version tagging the runtime (ASP.NET Core Runtime 5, ASP.NET Core Runtime 6, etc.).

There do exist more-than-slightly-subtle differences. For instance ASP.NET Core Runtime 5 projects are structured differently and Global.asax.cs has been replaced with Program.cs and the accompanying Startup.cs which contain the Main entry point and provide spaces for application configuration methods that execute only when your program is initially run (this includes functions to respond to certain events like a unhandled/last chance exception handling, etc.).

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
            services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true).AddEntityFrameworkStores<ApplicationDbContext>();
            services.AddControllersWithViews();
            services.AddRazorPages();
            services.AddMvc().AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
            services.AddLocalization(options => options.ResourcesPath = "Resources");
            services.Configure<RequestLocalizationOptions>(options =>
            {
                options.SetDefaultCulture("en-US");
                options.AddSupportedCultures("en-US", "es-CO", "fr-FR");........

An example of .NET 5 ASP.NET Startup.cs which replaces most Global.asax.cs functionality; Program.cs handles all else

 

In sum total, .NET 5 is basically a framework with the same functionalities that the .NET Framework had, with new namespaces and methods and a few slightly different design paradigms for ASP.NET and other project templates that use .NET 5 code. But it compiles to binary code that can run crossplatform- to a Linux distro or OSX27 or regular old Windows 10, 11, 12, etc.).

.NET 5 seems to favor better encapsulation/information hiding (less extensibility but fewer things to keep track of that can go wrong!) but ASP.NET Core still tends to have the magic string architecture that is its double-edged sword. Everything is a balance; never can be 100% fast, cheap and customizable.

Expect lots more to come now that .NET has it's versioning, cross-platform integration and road map in order



Virtually everything is customizable if you want to use your own implementation of a SqlClient RDBMS provider or Authentication provider. Setting up social media authentication is relatively simple. For relational database access, Dapper is a nice balance between ADO.NET with pure SQL statements and an ORM for object population/deserialization, etc. and compiles to .NET Standard which can be referenced and compiled by a .NET 5 project.

With SQL Server moving to Linux world I imagine many other useful services that used to rely solely on Windows-OS will follow: native MS Office, MS Dynamics and related dependencies, IIS, etc.

Where .NET really shines is in its ability to compile/integrate .NET code libraries (with the notable exception of server-side WCF)  built with .NET Framework 4.5-4.8 as well as Xamarin, Mono, Unity and other previous .NET-related runtime libraries. It uses what is called .NET Standard (a collection of commonly used and .NET 5-compatible .NET Framework  members) to achieve this bridging between .NET and all .NET Framework versions preceding it.

Perhaps not all of that old .NET 4.5-4.8 legacy code will need to go to waste.


All SDKs under one roof; what is not to like? Almost as great as "Write Once.. Run Anywhere" 


Long-term support for .NET 5's predecessor, .NET Framework will continue for versions 4.6.2 and above for the foreseeable future while prior versions have either already ended LTS or will be ending LTS soon, per Microsoft:

Support for .NET Framework 4, 4.5, and 4.5.1 ended on January 12, 2016.

Support for .NET Framework 4.5.2, 4.6, and 4.6.1 will end on April 26, 2022. Customers and developers must have completed the in-place update to .NET Framework 4.6.2 or later by April 26, 2022 to continue receiving technical support and security updates.

Getting Familiar with Microsoft Azure

I'd like to summarize what I've learned in the past couple years of using MS Azure for personal and professional software development. Keep in mind this is coming from the perspective of a developer; Azure can be used for many interesting things outside the scope of just deploying, hosting, and scaling software in the cloud.


The Azure Portal UI is intuitive, constantly being updated (for the better), and contains tools to create and configure nearly anything you can imagine  


First, it's a bit of a maze.

Then it's amazing.


Starting out

The idea of any cloud provider is to enable IaaS, SaaS and PaaS among other XaaS's. Instead of having to provision physical machines, network equipment and associated hardware, and go out to dozens of different vendors to manage service agreements for the various services a company uses- nowadays a company can move most of that distributed mess into their own private cloud and just manage everything in one place.

And that one place is highly secure, geo-redundant and hosted on some of the best and newest hardware available.





Azure resources

In Azure you have the concept of resources which consume resource units. Anything can be a resource: a network card, a virtual machine, a firewall security policy- they are all resources in the world of Azure. You can create, modify and delete resources virtually at will- or on a schedule through automation scripts that operate on what are known as ARM (Azure Resource Manager) templates which are basically representations of Azure resources in the form of JSON.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "adminUsername": {
      "type": "string",
      "metadata": {
        "description": "Username for the Virtual Machine."
      }
    },
    "adminPassword": {
      "type": "securestring",
      "minLength": 12,
      "metadata": {
        "description": "Password for the Virtual Machine."
      }
    },
    "dnsLabelPrefix": {
      "type": "string",
      "defaultValue": "[toLower(concat(parameters('vmName'),'-', uniqueString(resourceGroup().id, parameters('vmName'))))]",
      "metadata": {
        "description": "Unique DNS Name for the Public IP used to access the Virtual Machine."
      }
    },
    "publicIpName": {
      "type": "string",
      "defaultValue": "myPublicIP",
      "metadata": {
        "description": "Name for the Public IP used to access the Virtual Machine."
      }
    },
    "publicIPAllocationMethod": {
      "type": "string",
      "defaultValue": "Dynamic",
      "allowedValues": [
        "Dynamic",
        "Static"
      ],
      "metadata": {
        "description": "Allocation method for the Public IP used to access the Virtual Machine."
      }
    },
    "publicIpSku": {
      "type": "string",
      "defaultValue": "Basic",
      "allowedValues": [
        "Basic",
        "Standard"
      ],
      "metadata": {
        "description": "SKU for the Public IP used to access the Virtual Machine."
      }
    },

    "OSVersion": {
      "type": "string",
      "defaultValue": "2019-Datacenter",
      "allowedValues": [
        "2008-R2-SP1",
        "2012-Datacenter",
        "2012-R2-Datacenter",
        "2016-Nano-Server",
        "2016-Datacenter-with-Containers",
        "2016-Datacenter",
        "2019-Datacenter",
        "2019-Datacenter-Core",
        "2019-Datacenter-Core-smalldisk",
        "2019-Datacenter-Core-with-Containers",
        "2019-Datacenter-Core-with-Containers-smalldisk",
        "2019-Datacenter-smalldisk",
        "2019-Datacenter-with-Containers",
        "2019-Datacenter-with-Containers-smalldisk"
      ],
      "metadata": {
        "description": "The Windows version for the VM. This will pick a fully patched image of this given Windows version."
      }
    },
    "vmSize": {
      "type": "string",
      "defaultValue": "Standard_D2_v3",
      "metadata": {
        "description": "Size of the virtual machine."
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for all resources."
      }
    },
    "vmName": {
      "type": "string",
      "defaultValue": "simple-vm",
      "metadata": {
        "description": "Location for all resources."
      }
    }
  },
  "variables": {
    "storageAccountName": "[concat('bootdiags', uniquestring(resourceGroup().id))]",
    "nicName": "myVMNic",
    "addressPrefix": "10.0.0.0/16",
    "subnetName": "Subnet",
    "subnetPrefix": "10.0.0.0/24",
    "virtualNetworkName": "MyVNET",
    "subnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworkName'), variables('subnetName'))]",
    "networkSecurityGroupName": "default-NSG"
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2019-06-01",
      "name": "[variables('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage",
      "properties": {}
    },
    {
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2020-06-01",
      "name": "[parameters('publicIPName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[parameters('publicIpSku')]"
      },
      "properties": {
        "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]",
        "dnsSettings": {
          "domainNameLabel": "[parameters('dnsLabelPrefix')]"
        }
      }
    },
    {
      "type": "Microsoft.Network/networkSecurityGroups",
      "apiVersion": "2020-06-01",
      "name": "[variables('networkSecurityGroupName')]",
      "location": "[parameters('location')]",
      "properties": {
        "securityRules": [
          {
            "name": "default-allow-3389",
            "properties": {
              "priority": 1000,
              "access": "Allow",
              "direction": "Inbound",
              "destinationPortRange": "3389",
              "protocol": "Tcp",
              "sourcePortRange": "*",
              "sourceAddressPrefix": "*",
              "destinationAddressPrefix": "*"
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/virtualNetworks",
      "apiVersion": "2020-06-01",
      "name": "[variables('virtualNetworkName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
      ],
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[variables('addressPrefix')]"
          ]
        },
        "subnets": [
          {
            "name": "[variables('subnetName')]",
            "properties": {
              "addressPrefix": "[variables('subnetPrefix')]",
              "networkSecurityGroup": {
                "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
              }
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/networkInterfaces",
      "apiVersion": "2020-06-01",
      "name": "[variables('nicName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPName'))]",
        "[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPName'))]"
              },
              "subnet": {
                "id": "[variables('subnetRef')]"
              }
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2018-10-01",
      "name": "[parameters('vmName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]",
        "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
      ],
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "computerName": "[parameters('vmName')]",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPassword')]"
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "MicrosoftWindowsServer",
            "offer": "WindowsServer",
            "sku": "[parameters('OSVersion')]",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "FromImage",
            "managedDisk": {
              "storageAccountType": "StandardSSD_LRS"
            }
          },
          "dataDisks": [
            {
              "diskSizeGB": 1023,
              "lun": 0,
              "createOption": "Empty"
            }
          ]
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
            }
          ]
        },
        "diagnosticsProfile": {
          "bootDiagnostics": {
            "enabled": true,
            "storageUri": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))).primaryEndpoints.blob]"
          }
        }
      }
    }
  ],
  "outputs": {
    "hostname": {
      "type": "string",
      "value": "[reference(parameters('publicIPName')).dnsSettings.fqdn]"
    }
  }
}
An example of an ARM template- this one is for deploying/updating a Windows Server VM resource


For a trial period of (currently 12 months) most all of the really useful stuff is free (be careful not to accidentally deploy Azure Co$mos though...😳 ...that is not free, and that is not cheap). After the trial period, the cost was still relatively cheap for the services that I use most in Azure (an App Service hosting a handful of .NET Core apps with SSL, 1 powerful virtual machine, a DNS zone, a vNet)- all for about $30/month.


Development

For development, much like it is with Git, the Visual Studio integration with Azure is pretty seamless and enables deployments directly from the IDE. You can also enable an Azure object explorer to view your Azure cloud instance' resources within VS.

Most all established companies are going to want to- for security reasons- (or will have to for incompatibility reasons)- keep at least some legacy software and/or infrastructure on-prem.


Azure ARC connects your On-Prem to your Cloud



And that is why there is Azure ARC- an incredibly simple way to bridge cloud and on-prem resources to create a hybrid virtual network. ARC is essentially a service that you run on your on-prem machines that connects them to your Azure subscription where the machines can then be configured as if they were an Azure resource and can enable on-prem devices to communicate with cloud resources.

"Arc works by running an agent on your non-azure resources; this is a service on VM's and a Kubernetes pod on Kubernetes cluster. Once you install this service, the machine registers with Azure and is ready for management." -samcogan.com

Additionally, virtual machines (Windows OSs or approved Linux distros) can be accessed via SSH or RDP and are as amazingly fast or as tortuously slow as you configure them to be. You can choose from preconfigured database server or application server templates or build your virtual machines completely à la carte.

The ARM template paradigm is easy to understand and develop with, and there are 2 CLI options- Azure CLI and the new PowerShell "Az" module.


How to see "gains"

To see savings from using the cloud, instead of purchasing a new server or physical license, you can rent the computing power you need to power your apps and services and you can even move your worker machines onto the cloud where they can be more easily managed (we are indeed moving back to a thin client/dumb terminal world).

You can move from the physical Exchange mail server model to Outlook365. You can move all of your physical Office subscriptions to Office365.

If your computing needs are seasonal or time-sensitive, you can scale up when needed and pay a high price for short bursts of computing power, while scaling back down to a much lower-budget level until the next scale-up need arises. The configuration of the usage of resources in Azure is highly granular and lends itself to squeezing out a lot of efficiency for those who can monitor and manage it correctly in accordance with organizational needs.

Azure Hybrid Benefit also provides credits for customers who already have an on-prem SQL Server software license. Want to see that MSSQL2019 Enterprise for Linux instance in the cloud? 🙂


Monitor usage

Monitor your cloud resource usage as you can inadvertently requisition a resource that behaves in ways you did not expect and in turn end up ringing up a lot of expensive RUs (resource units). Azure allows you to configure a budget and alerts when you have reached certain thresholds toward or beyond the budget number so that you can configure an alert which will email you a warning message if you have reached 105% of your monthly budget, for example.


The current Azure offerings are plentiful and powerful enough to outfit even the most complex IT infrastructure

Azure, like any cloud provider, forces you to take a fine-grain look at every single resource you are using. It is amazing how much stuff we don't actually use.

It is only when you begin to pay for usage of each resource and see the numbers rising daily do you really understand how much you are utilizing your various resources.

Powerful computing machines began as a timeshare because of the realization that it is madness to let expensive machines sit idle. And though the resources to share and provision among users has become far more complex, we are returning to that model.


Conclusion

Whether you use Azure to explore different kinds of technology or to implement an IT infrastructure completely in the cloud to connect and supercharge your applications and/or workforce- the tech is now there and the costs are comparable to AWS.

My two criticisms of Azure are that (1) Azure seems to excessively spotlight/push certain features forward and other features (many practical, free and cheap things you would think are "essential"- like setting up DNS zones) remain sort of in the shadows/awaiting help links waiting to be discovered... And (2), sadly other things, little things like logging analytic insights that you would think are free are in fact Azure resources that charge RUs. 😕

These aspects suck but are tolerable in light of all of the awesome functionality Azure provides.

Microsoft continues to improve an industry-leading cloud platform that executives, management, engineers, developers, and system admins alike can all learn to love. 💖

Dapper for .NET Data Access

Jeff Atwood described the phrase coined by Ted Neward that "Object-Relational Mapping is the Vietnam of Computer Science".

I agree with everything except Atwood's (huh? 😨- keep in mind this is 2006) conclusion that we should do one or the other: objects or relational data records. Develop apps as a series of SQL data access statements assigning values to arbitrary pieces of monolith application code.. or exclusively object-oriented with everything saved to blob storage... Or something awkward like that.

That, he says (in the 2006 article*), removes the O (object) - R (relational data) mapping problem entirely. It sure does; but how can we develop apps like that?

(fast-forward 6yrs, and.... Dapper to the rescue!)

Dapper is an awesome (IMO) alternative that allows developers to retain SOLID reuse and extensibility in their .NET data access code while still accessing complex relational data- and fast.


Dapper has the best of both worlds in terms of what you look for in a data access framework - speed and clean, easy SQL-to-typed object mapping facilitation


I highly recommend the brief peruse; it is a very interesting article. It essentially describes the pitfalls that ADO.NET, Hibernate and Entity SQL (EF for MSSQL) and so many of the other approaches to modeling relational data as .NET objects that have, if not failed completely- severely been lacking especially in terms of speed and control over the actual SQL that you instruct the SQL engine to execute.

Dapper aims to bridge the eternal gap between application and relational database code in a pretty elegant way for .NET development. So long as your database records (whether from a complex JOIN'd SP or wherever in your db)- can return data with types and field/alias names that match your "query-return-target-type" class' properties' names and data types, you are set for all the kinds of data access you like and are off and running without all the headaches normally associated with ORMs (magic config strings, mappings in separate files out of sync with class or db changes, etc.).

"there is no good solution to the object/relational mapping problem. There are solutions, sure, but they all involve serious, painful tradeoffs. And the worst part is that you can't usually see the consequences of these tradeoffs until much later in the development cycle." -Jeff Atwood on ORMs

I guess you could say that the SQL itself in the queries you tell Dapper to issue to MSSQL are "magic strings" insofar as VS doesn't compile them.. But if you don't use SSMS to parse and execute tests of your queries before using them in application code then you aren't really doing real data development- you are just shooting in the dark.

You should have unit tests for this very purpose. Unit tests of your Dapper calls will catch any db changes in the tests ("hey why did nobody tell me about this schema change in the Archives table?"); regardless- if your SQL field names don't match the class prop names of the object you are trying to "Dapperize"- you will find out at run-time. The exception messages are very "straight to the point of exactly what is off".

Dapper works the same in all versions of .NET; it is currently based on .NET Standard for that very reason, but you will need to bring in more dependency depending on what type of data source you are trying to access (SQL Server, MySQL, Oracle, DB2, Terradata, etc.).

Consider giving Dapper a try - it is very useful and illuminating, and it really shines in the very areas where EF falls short.



Dapper accessing 'UserReport' records from SQL db and returning the dynamic, typed object:
     SqlConnection db = new SqlConnection(WebConfigurationManager.AppSettings["DefaultSQLConnection"]);  
     public List<UserReport> ReadAllSavedUserReports()  
     {  
       using (db)  
       {  
         return db.Query<Report>("SELECT * FROM CLARO.dbo.UserReport").ToList();  
       }  
     }  
     public UserReport FindSavedUserReport(int id)  
     {  
       using (db)  
       {  
         return db.Query<Report>("SELECT * FROM CLARO.dbo.UserReport WHERE Id = @Id", new { id }).SingleOrDefault();  
       }  
     }  
Forgive the "SELECT *.... this is just a demonstration..



These methods can then easily be called in controller or other code like so:
     public ViewResult Index()  
     {  
       string nowTime = DateTime.Now.ToShortDateString();  
       ReportDAL dal = new ReportDAL();  
       Demo model = BuildModel(BuildSQLStatement(nowTime, ReportDrafts.BaseballDemo), nowTime);  
       model.Reports = dal.ReadAllSavedUserReports();  
       return View(model);  
     }  


Dapper is not a company trying to sell anything- it is just a really useful micro-ORM for those who prefer to work more hands-on with the SQL in data access code (and like to be able to more granularily control optimization for speedier queries).

*Atwood helped contribute (with SO) to the development of Dapper, so... I think he and that team kinda nailed the removal and easing of the very same limitations he bemoaned in the article I reference at the beginning: https://stackoverflow.blog/2012/02/18/stack-exchange-open-source-projects/


References: 

https://elanderson.net/2019/02/asp-net-core-with-dapper/

https://dapper-tutorial.net/



Social Authentication in ASP.NET Core MVC

A common modern convenience for apps is the ability to choose to authenticate and create an account based on credentials from an existing service that most people have (ie. Google, Twitter, LinkedIn, GitHub, etc.). in this post I will walk through the configuration of social authentication for Google and LinkedIn accounts.

Setting up social authentication in ASP.NET Core is a lot easier than you might think...

Before implementing this feature you will need to register for a Google and a LinkedIn developer account which will then give you access to the 2 values that make the magic of this built-in authentication possible: clientKey and clientSecret.

Important(!): you will also want to register the Callback/Redirect URLs for each social authentication as shown below. This redirect URL below is for my project running on localhost:44396 obviously ("/signin-google" is the path you want to append to your app root for Google and "/signin-linkedin" for LinkedIn):


Once you have this setup, you will be able to wire them up in the Startup.cs ConfigureServices() method of an ASP.NET Core 3 MVC Web Application ie:

  public void ConfigureServices(IServiceCollection services)  
     {  
       services.AddDbContext<ApplicationDbContext>(options =>  
         options.UseSqlServer(  
           Configuration.GetConnectionString("DefaultConnection")));  
       services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)  
         .AddEntityFrameworkStores<ApplicationDbContext>();  
       services.AddControllersWithViews();  
       services.AddRazorPages();  
       services.AddAuthentication()  
       .AddGoogle(o =>  
       {  
         o.ClientId = "[YourGoogleClientId]";  
         o.ClientSecret = "[YourGoogleClientSecret]";  
       })  
       .AddLinkedIn(o =>  
       {  
         o.ClientId = "[YourLinkedInClientId]";  
         o.ClientSecret = "[YourLinkedInClientSecret]";  
       });  
       // Add application services.   
       services.AddMvc();  
     }  


Now you just have to:

  • Create your ASP.NET Core 3 MVC Web Application project with Identity options as below
  • Install a couple Nuget packages for Google OAuth2 and Linked OAuth respectively
  • Call "Update-Database" from Nuget Package Manager Console
  • Modify Startup.cs

To implement this feature for your users you only need follow a couple steps when setting up the project (whether ASP.NET MVC or the newer ASP.NET Core MVC) to enable some builtin identify and authentication handling after which you can configure and customize to fit your app's particular custom authentication needs. Follow the images below for proper installation of the required 2 Nuget packages, the db command, etc.

First, make sure you create your ASP.NET Core MVC project with "Individual User Accounts" radio button selection and "Store user accounts in app" dropdown selection as follows:


Change Authentication to use Individual User Accounts- this sets up the required boilerplate template code



You will add this Nuget package for LinkedIn authentication



You will add this Nuget package for Google authentication


Next you will need to create the database objects (ASPNET app auth db and tables) via "Update-Database" Package Manager Console command


Finally, modify Startup.cs ConfigureServices() method as shown in the snippet above. Compile and give it a whirl.

And that is all there is to it. Strangely there is not a lot of documentation on exactly how to do this and what can cause it to not work; I spent over an hour debugging what turned out to be a not-so-obvious issue (in my case I was following instructions that erroneously suggested I inject unneeded services to the services.AddAuthentication() instantiation in the snippet of Startup.cs above).


If your keys and Callback URLs are correct you will be able to authenticate to Google and LinkedIn



Once you have registered your social account, you can then log in with it and you will see the following (notice "Hello!...." and "Logout")


If you are like me and do not want to keep to adding yet more and more credentials to LastPass, your users probably don't either. Implementing Social Authentication is a powerful tool that you can leverage with relative ease in ASP.NET Core 3 MVC Web apps.

If you have questions on implementing this or just need some help and general guidance, feel free to comment or drop me an email at colin@sonrai.io


GitHub: https://github.com/cfitzg/DotNetSocialAuth


References:

http://codereform.com/blog/post/asp-net-core-2-1-authentication-with-social-logins/

https://docs.microsoft.com/en-us/aspnet/mvc/overview/security/create-an-aspnet-mvc-5-app-with-facebook-and-google-oauth2-and-openid-sign-on

https://ankitsharmablogs.com/authentication-using-linkedin-asp-net-core-2-0/  

https://stackoverflow.com/questions/53654020/how-to-implement-google-login-in-net-core-without-an-entityframework-provider


Developer Scratchpad (.NET C#, VB, JavaScript, Powershell, Python, SQL, etc.)

If you memorize infrequently used code, you are wasting mental storage space- reference notes!



--------NETWORK-----------------------------------------------------------
--------------------------------------WINDOWS BUILTIN CMDs-------------------------------------
//converting Windows back slashes to Unix forward slashes
SET string=C:\Users\Admin\Desktop\DeskDEV\
ECHO %string:\=/%
//converting Unix forward slashes to Windows back slashes
SET string=C:/Users/Admin/Desktop/DeskDEV/
ECHO %string:/=\%
netsh interface ip show config
netsh interface ip set address "Local Area Connection" static 192.168.0.10 255.255.255.0 192.168.0.254
netsh interface ip set address "Local Area Connection" dhcp
netsh http show urlacl
netsh int tcp set heuristics disabled
netsh int tcp set global autotuninglevel=disabled
netsh int tcp set global rss=enabled
netsh int tcp show global
netsh winsock reset
netsh int ip reset
ipconfig /release
ipconfig /renew
ipconfig /flushdns
ipconfig /registerdns
msdt.exe -id NetworkDiagnosticsWeb
msdt.exe -id NetworkDiagnosticsInbound
msdt.exe -id NetworkDiagnosticsNetworkAdapter
ipconfig
sfc /scannow
driverquery
ping and pathping
tasklist and taskkill
nslookup
sigverif
doskey /history
netstat
cipher
getmac
net user
arp
nbstat
logman
route
shutdown
assoc
schtasks
attrib
auditpol
bcdboot
bcdedit
bootcofg
bootsect
cacls
call
cd
certreq
certutil
chcp - (active code page)
checknetisolation
chkdsk
chkntfs
choice - ([Y,N]? prompt in .bat)
cipher - (enc status of files)
clip
cls
cmstp - (connectionMgr interesting*)
comp - (basic file diff)
compact - (compress)
convert - (file system type)
copy
cscript - (execute vbs, etc.)
date
debug - (only on DOS && 32bit Windows)
defrag
del
deltree
dir
diskpart*
diskperf
diskraid
dism - (dply .isos)
dispdiag
djoin - (join domain)
driverquery - (all driver information!)
echo
endlocal - (break out of a script's localalized context)
erase
esentutl - (storage engine mgmt)
eventcreate
expand - (unzip archive)
Extrac32 - (unzip .cab)
extract - (unzip archive)
fc - (compare file sets)
find - (srch for text in file or files)
Findstr - (regex "")
finger - user(s) info
Fltmc - (filter driver installer)
fondue - (new/experimental Windows features)
format - (format drive for some file system)
fsutil - (filesys utiles)
ftp - (chell for ftp comms; "quit")
ftype - default programs
getmac - get MAC of all network controllers on system
gpresult - (grp policy)
gpupdate
icacls
iscsicli - (iSCSI initiator)
klist - Kerberos tickets
Ksetup - (for a kerberos-enabled server)
ktmutil - (kernal transaction mgr utility)
label - (volume label of disks)
licensingdiag - (Windows product activation info)
loadhigh(lh), lock - (old DOS cmds)
lodctr - (registry values for perf counters)
logman - (event trace session)
logoff - (until Win7)
makecab - (cainet maker)
manage-bde - (Bitlocker drive enc)
mklink - (create symbolic link)
mode - (COM/LPT ports - check "CON" device further)
mofcomp - .mof* file display
more
mount - (until SFU was discontinued...)
mountvol - (use this instead)
move
mrinfo - (rounter info)
msg
msiexec - (start an install)
muiunattend - (unattended install)
nbtstat - (see connection info)
net - (cfg network settings)
net1 - ("" "" Y2K issue wkrnd/patch for net)
netcfg - (installs WinPE)
netsh - (network shell, net mgmt)
netstat - (displays listening ports, connects)
nltest - (test secure channels between machines across trusted domains)
nslookup - (hostname from IP)
openfiles - (remote cmd)
path
pathping - (tracert w/net latency, more info)
pause - (Press any key to continue...)
ping
pkgmgr - (windows pkg mgr)
pnpunattend - (unattended driver install)
pnputil
popd
powercfg
print
prompt
pushd
rasautou
rasdial*
rcp - (deprecated)
rd
reagentc - (win recovery)
recover - (recover a file deleted, but not yet overwritten)
reg - (registry cmds)
regini - (hange registry permissions and registry values from the command line)
Regsvr32 - (register .dll as component)
relog - (new perf append to existuing perf data)
rem
ren
repair-bde - (Bitlocker repair)
replace
rmdir
robocopy - (robust copy)
route - (maniupulate network routing tables)
Rpcping
runas
schtasks
sdbinst - (SDB db files, used by OpenOffice)
secedit - (compare current sec levels to a template to ensure no unneeded access, etc.)
setspn - (set service principle name for an AD account)
setx - (user env variable config)
sfc - (System File Checker)
shutdown - (automate poweroff)
sort
sxstrace - tracing
subst - (assoc local path with drive letter; similiar to net use)
takeown - regain access to object
taskkill - (force kill a process)
tasklist - (running proccesses; used by taskmgr.exe, etc.)
tcmsetup - (to set up or disable the Telephony Application Programming Interface (TAPI) client)
telnet
tftp (deprecated?)
time
timeout
title - (cmd prompt window label)
tracerpt - trace rpt
tracert - Internet Control Message Protocol (ICMP) Echo Request messages to a specified remote computer with increasing Time to Live (TTL) field values and displays the IP address and hostname, if available, of the router interfaces between the source and destination.
tree - (awesome)
typeperf - (cmd perf data)
tzutil - (time zones)
unlodctr - (uninstalls a perf counter in registry)
vaultcmd - (manage Windows stored creds)
ver
vol
vssadmin - (volume shadow copy admin)
w32tm - (windows time)
wecutil - (win evt collector)
where - (find by regex)
whoami
winmgmt - (WMI)
winrm - (remote mgmt)
winrs - (remote sh)
winsat - (system assesment tool)
wmic - (WMI CLI)
wsmanhttpconfig
xcopy
xwizard - (register data in Windows, often from a preconfigured XML file)


-------POWERSHELL---------------------------------------------------
Get-Command -Name {..}
get-alias
Get-Help Get-EventLog
Get-ChildItem c:/
$var
(no concept of scope- ALL is glbl)
Remove-Item
//ex. of getting some scv column data...
Get-Command -Verb Export | Select-Object CommandType, Name, Version, Source | Export-Csv -NoTypeInformation -Path C:\NewFolder\ExportCommands.CSV
//Outfile is useful
Get-Command -Verb Export | Select-Object CommandType, Name, Version, Source | Out-File C:\NewFolder\ExportCommands.txt
Get-Process -Id 10500 | Stop-Process
Get-EventLog -LogName System -Newest 5
Clear-EventLog "Windows PowerShell"
Get-WmiObject -List -Class Win32*
Enter-PSSession Computer1
Invoke-Command -ComputerName Computer1, Computer2, Computer3, -ScriptBlock {Get-Process}
//Create a new (persistant) session, and save it
$session = New-PSSession -ComputerName Computer1, Computer2
Set-ExecutionPolicy
Get-ExecutionPolicy
Get-Service | Where-Object {$_.status -eq "stopped"}
//Create html from basic data structs (in this case, ps cmdlet aliases)
get-alias | convertto-html > aliases.htm
invoke-item aliases.htm
Get-EventLog -Log "Application"
Stop-Process -processname note*
Get-Service | Where-Object {$_.Status -eq 'Running'}
Get-AuthenticodeSignature somescript.ps1 @(Get-ChildItem cert:\CurrentUser\My -codesigning)[0] -IncludeChain "All" -TimestampServer "http://timestamp.verisign.com/scripts/timstamp.dll"
Get-Process | ForEach-Object {Write-Host $_.name -foregroundcolor cyan}
Clear-Content C:\Temp\TestFile.txt
Clear-Content -path * -filter *.TXT –force (all text files force clear)
Checkpoint-Computer -Description "My 2nd checkpoint" -RestorePointType "Modify_Settings"
Get-ComputerRestorePoint | format-list
Compare-Object $obj1 $obj2
 [string[]]$arrayFromFile = Get-Content -Path 'C:\someplace\file.txt'
 foreach ($uri in $arrayFromFile) {
   yt-dl -f 140 $uri
  }
$settings = $TextData | ConvertFrom-StringData
ConvertTo-SecureString [-String] SomeString
Get-Service wuauserv -ComputerName chi-dc04,chi-p50,chi-core01 |
Export-Clixml -Path c:\work\wu.xml
Get-AppLockerPolicy
New-ItemProperty
$ourObject = New-Object -TypeName psobject
/////////////////////////////////////////////////////
$url = http://<webapp>.azurewebsites.net/CreateSite.asmx
$proxy = New-WebServiceProxy $url
$spAccount = "<username>"
$spPassword = Read-Host -Prompt "Enter password" –AsSecureString
$projectGuid = ""
$createOneNote = $false
$proxy | gm -memberType Method
New-WSManInstance winrm/config/Listener
-SelectorSet @{Address="*";Transport="HTTPS"}
-ValueSet @{Hostname="Test01";CertificateThumbprint="01F7EB07A4531750D920CE6A588BF5"}
/////////////////////////////////////////////////////
Get-Process | Sort-Object name -Descending | Select-Object -Index 0,1,2,3,4
New-Alias np c:\windows\system32\notepad.exe
Set-StrictMode
Wait-Job
Write-Progress -PercentComplete (($var1/$var2) * 100))
$job = Start-Job -ScriptBlock { Set-PSBreakpoint C:\DebugDemos\MyJobDemo1.ps1 -Line 8; C:\DebugDemos\MyJobDemo1.ps1 }
Debug-Job $job
Get-Counter -Counter "\Processor(_Total)\% Processor Time" -SampleInterval 2 -MaxSamples 3
Test-Path C:\Scripts\Archive
Get-WinEvent -ListLog *
Invoke-TroubleshootingPack (Get-TroubleshootingPack C:\Windows\diagnostics\system\networking)
Measure-Command
Get-Process | Measure-Object VirtualMemorySize -Sum
New-EventLog -LogName Wtf_Log -Source SomewhereOutThere
Receive-Job -Name HighMemProcess
Register-EngineEvent PowerShell.Exiting -Action {"PowerShell exited at " + (Get-Date) | Out-File c:\log.txt -Append}
Register-ObjectEvent
Remove-Event
Set-PSDebug
Start-Sleep
Tee-Object
Test-AppLockerPolicy
Test-ComputerSecureChannel
Trace-Command
Write-Debug "`$return has $($return.count) items"

-------VISUAL STUDIO----------------------
Ctrl+, . for Autosuggest
Sort usings by Right-click on using references

--------.NET------------------------------------------------------
--------------------------C#--------------------------------------
//switch expression*
car foo = line switch {
case 0: foo = 1; break;
case 0: foo = 1; break;
default: for = 0; break;
}
XDocument.Parse is for string XML
XDocument.Load is for XML *Files*
[,] is multidimensional array and [][] is array of arrays.
//collection initializer
List<Coord> ls = new List<Coord>() { new Coord { x = 1, y = 2 }, new Coord { x = 11, y = 12 }};
//lambda expression value
var filteredList = list.Where(o => o.id == targetGUID);
//Make the internals visible to the test assembly for unit testing private dependencies, etc.
[assembly: InternalsVisibleTo("MyTestAssembly")] in the AssemblyInfo.cs file.
//Obsolete attribute to warn that an assembly may go away and that alternatives should be used asap
Obsolete("This method will be deprecated soon. You could use XYZ alternatively.")]
//To prevent a repetition of the execution, change the LINQ result to List after execution
var result = masterCollection.Where(i => i > 100).ToList();
Console.WriteLine(result.Count()); //no extra Linq executions
Console.WriteLine(result.Average()); //no extra Linq executions
//catch Generic Exception and throw for more detail
catch (Exception)
      throw;
//Generic Type using a common Interface
protected class MyGenricClass<T> where T : IMyInterface
public void MyGenericMethod<T>(T t) where T : IMyInterface
//using obj reference for brevity and cleaner code
using (SqlConnection conn = new SqlConnection(strConnection)) { ... }
//aslias namespaces for brevity if you need to explicitly spell out the namespace anywhere
using Excel = Microsoft.Office.Interop.Excel;
var excelapp = new Excel.Application();
//object initializer
Janitor jenkins = new Janitor() { Name = "Jenkins", Address = "1212 DeplPipelnSciptzzz" };
//null checks
if (string.IsNullOrEmpty(s))
//Connection String
"Server=myServerAddress;Database=myDataBase;User Id=myUsername;
Password=myPassword;"
//Entity Framework Optimizer/Escape Hatch
using (var db = new MyContext())
{
    db.Query<FooBar>().FromSql("SELECT ProductID, udf_GetNameFromId(ID3) FROM Products");
}
//JSON Serialize and Deserialize with Newtonsoft
string serial = JsonConvert.SerializeObject(genericObject);
var deserial = JsonConvert.DeserializeObject<APIGenericItemsResponse>(await response.Content.ReadAsStringAsync());
//XML Serialize using System.Xml.Serialization
 public void TestSerialize(XMLEntityCollection ents)
     {
       XmlSerializer xmlSerializer = new XmlSerializer(ents.GetType());
       using (StringWriter stringWriter = new StringWriter())
       {
         xmlSerializer.Serialize(stringWriter, ents);
         Assert.IsNotNull(stringWriter);
       }
     }
//XML Deserialize using System.Xml.Serialization
XmlSerializer serializer = new XmlSerializer(typeof(XMLEntityCollection));
       using (StringReader reader = new StringReader(xml))
       {
         XMLEntityCollection ents = (XMLEntityCollection)serializer.Deserialize(reader);
         TestSerialize(ents);
       }
-------------------------VB--------------------------------------
Dim i As Integer = 1
Begin Function(ByVal a As String) As Double
     Return 37
End Function
Namespace MyNamespace
End Namespace
Public Class Manager
     Inherits Employee
End Class
Public Overridable Function CalculateSalary() As Integer
End Function
Public Overrides Function CalculateSalary() As Integer
End Function
MyBase (base in C#)
Public Interface IEmployee
    Property EmployeeID() As Integer
    Property Name() As String
    Property Age() As Integer
    Function CalculateSalary() As Integer
End Interface
Public Class Manager
Implements IEmployee
End Class

--------PYTHON-----------------------------
#cool-youtube-API
youtube-dl -f 140 $uri
#formatting opts for youtube-dl

[info] Available formats for P9pzm5b6FFY:
format code extension resolution  note 
140         m4a       audio only  DASH audio , audio@128k (worst)
160         mp4       144p        DASH video , video only
133         mp4       240p        DASH video , video only
134         mp4       360p        DASH video , video only
135         mp4       480p        DASH video , video only
136         mp4       720p        DASH video , video only
17          3gp       176x144     
36          3gp       320x240     
5           flv       400x240     
43          webm      640x360     
18          mp4       640x360     
22          mp4       1280x720    (best)
#reverse string
a =  "NotPalindrome"
print("Reverse is",a[::-1])
#transpose matrix
mat = [[1, 2, 3], [4, 5, 6]]
zip(*mat)
#store array as indiv vars
a = [1, 2, 3]
x, y, z = a
#print array elments as string
a = ["This", "is", "a", "string"]
print(" ".join(a))
#print coords of 2 combined lists
list1 = ['a', 'b', 'c', 'd']
list2 = ['p', 'q', 'r', 's']
for x, y in zip(list1,list2):
...    print(x, y)
#switch var vals in 1 line
a=2
b=4
b, a =a, b
#execute recursion without loops
print("cool"*2+' '+"beans"*5)
#convert matrix to list without loop
import itertools
a = [[1, 2], [3, 4], [5, 6]]
list(itertools.chain.from_iterable(a))

-------JAVASCRIPT------------------------------------
//Use "var" or "let" when creating any variables Assignment to an undeclared variable automatically //results in a global variable being created. Avoid global variables.
var a = 'not Globl';
=== instead of == (former compares value and type)
//Be careful when using typeof, instanceof and constructor.
var arr = ["a", "b", "c"];
typeof arr;   // return "object"
arr  instanceof Array // true
//get random item from an array
var items = [12, 548 , 'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' , 2145 , 119];
var  randomItem = items[Math.floor(Math.random() * items.length)];
//get random number in a specific range
var x = Math.floor(Math.random() * (max - min + 1)) + min;
//Trim String prototype extension function
String.prototype.trim = function(){return this.replace(/^s+|s+$/g, "");};
//Append array to array
var array1 = [12 , "foo" , {name "Joe"} , -2458];
var array2 = ["Doe" , 555 , 100];
Array.prototype.push.apply(array1, array2);
//Object to Array
var argArray = Array.prototype.slice.call(arguments);
//Verify numeric
function isNumber(n){
    return !isNaN(parseFloat(n)) && isFinite(n);
}
//verify Array type
function isArray(obj){
    return Object.prototype.toString.call(obj) === '[object Array]' ;
}
//Max and Min
var  numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
var maxInNumbers = Math.max.apply(Math, numbers);
var minInNumbers = Math.min.apply(Math, numbers);
//Empty the array
var myArray = [12 , 222 , 1000 ];
myArray.length = 0;
//use splice() not delete() for removing JS array elements
var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ];
items.length; // return 11
items.splice(3,1) ;
items.length; // return 10
//use map() to loop through array
var squares = [1,2,3,4].map(function (val) {
    return val * val;
});
//rounding a decimal numeric
var num =2.443242342;
num = num.toFixed(4);
//check object props
for (var name in object) {
    if (object.hasOwnProperty(name)) {
        // do something with name                 
    }
}
//Serialize and Deserialize
var person = {name :'Saad', age : 26, department : {ID : 15, name : "R&D"} };
var stringFromPerson = JSON.stringify(person);
/* stringFromPerson is equal to "{"name":"Saad","age":26,"department":{"ID":15,"name":"R&D"}}"   */
var personFromString = JSON.parse(stringFromPerson);
/* personFromString is equal to person object  */
//Best/fastest JS looping structure
var sum = 0;
for (var i = 0, len = arrayNumbers.length; i < len; i++) {
    sum += arrayNumbers[i];
}
//Pass functions (not string ref of function) to SetTimeout() and SetInterval()
setInterval(doSomethingEverySecond, 1000);
setTimeout(doSomethingEveryFiveSeconds, 5000);
//Clone a type
function clone(object) {
    function OneShotConstructor(){};
    OneShotConstructor.prototype= object;
    return new OneShotConstructor();
}
clone(Array).prototype ;  // []
//HTML escape function
function escapeHTML(text) {
    var replacements= {"<": "&lt;", ">": "&gt;","&": "&amp;", """: "&quot;"};                   
    return text.replace(/[<>&"]/g, function(character) {
        return replacements[character];
    });
}
//Set timeouts on async function calls
var xhr = new XMLHttpRequest ();
xhr.onreadystatechange = function () {
    if (this.readyState == 4) {
        clearTimeout(timeout);
        // do something with response data
    }
}
var timeout = setTimeout( function () {
    xhr.abort(); // call error callback
}, 60*1000 /* timeout after a minute */ );
xhr.open('GET', url, true);

xhr.send();

//deal with websocket timeout
var timerID = 0;
function keepAlive() {
    var timeout = 15000;
    if (webSocket.readyState == webSocket.OPEN) {
        webSocket.send('');
    }
    timerId = setTimeout(keepAlive, timeout);
}
function cancelKeepAlive() {
    if (timerId) {
        cancelTimeout(timerId);
    }
}

-------T-SQL-----------------------------------------------------------
SELECT dateadd(mm, datediff(mm, 1, getDate()), 0) as FirstOfTheMonth
SELECT dateadd(ms, -3, dateadd(mm, datediff(m, 0, getDate()) + 1, 0)) as LastOfTheMonth
SELECT dateadd(qq, datediff(qq, 0, getDate()), 0) as FirstDayOfQtr
SELECT dateadd(wk, datediff(wk, 0, dateadd(dd, 6 - datepart(day, getDate()), getDate())), 0)  --(First Monday of Month)
--Find all instances of a 'string' within a string (varchar/nvarchar)
CREATE FUNCTION dbo.FindPatternLocation
(
    @string NVARCHAR(MAX),
    @term   NVARCHAR(255)
)
RETURNS TABLE
AS
    RETURN
    (
      SELECT pos = Number - LEN(@term)
      FROM (SELECT Number, Item = LTRIM(RTRIM(SUBSTRING(@string, Number,
      CHARINDEX(@term, @string + @term, Number) - Number)))
      FROM (SELECT ROW_NUMBER() OVER (ORDER BY [object_id])
      FROM sys.all_objects) AS n(Number)
      WHERE Number > 1 AND Number <= CONVERT(INT, LEN(@string)+1)
      AND SUBSTRING(@term + @string, Number, LEN(@term)) = @term
    ) AS y);
--Windowing for running totals, referencing related rows and row group totals
SELECT xact_amt,
     SUM(xact_amt) OVER (ORDER BY xact_datetime) AS running_total
FROM SOME_DB.dbo.SOME_TABLE
 --Get ids from a csv of ids
 SELECT * FROM string_split('100,101,201,301,411,414', ',')
--Push a series of values into one row
 SELECT playerID,
 STUFF((select '; ' + teamID
      from Managers
      where teamID like('%P%')
            group by teamID
      for xml path('')), 1, 1, '') allTeams
 FROM Managers
--Dynamic SQL
 DECLARE @mult bit = 0
 DECLARE @sqlToExecute varchar(500)
 DECLARE @srvWest varchar(50) = 'WestZoneSqlSrv08'
 DECLARE @srvEast varchar(50) = 'EastZoneSqlSrv08'
 IF @mult = 0
      SET @sqlToExecute = 'SELECT TOP 1 OrderId, PersonId FROM ALGO.dbo.[Order]'
 ELSE
      SET @sqlToExecute = 'SELECT TOP 1 OrderId, PersonId FROM ' + @srvEast + '.ALGO.dbo.[Order] UNION ALL SELECT TOP 1 OrderID, PersonId FROM ' + @srvWest + '.ALGO.dbo.Order' 
 EXEC(@sqlToExecute)
--CTE
WITH Entity (EntityID, Name, ParentID, Tree)
AS
(
   SELECT ID, Val1, Val2 FROM SomeDbServer.dbo.SomeDatabase;
)

SELECT * FROM Entity;

-------GIT------------------------------------------------------
git log
git diff
git init
git branch
git branch -a
git branch <branchname> ((new branch))
git switch <branchname> ((same as checkout))
git merge <branchname> ((merge another branch into current working branch))
git push origin <branchname>
git push -u origin <branchname>
git pull origin <branchname>
git remote add origin <ssh or https URI>

--------WinDbg--------
!sos.threadpool (Strike subset of modules useful (yet safe) for debugging .NET)
!sos.savemodule
!sos.finalizequeue
!mex.us
!mex.aspxpagesext
!mex.mthreads / !sos.threads
!mex.dae
!mex.clrstack2

!sym noisy
g - (Go)
r - (Registers)
d - (virtual memory commands)
!teb - (thread environment block)
!peb - (process execution block)
~{thread id}|| ~*k to execute "each thread" and assoc k cmd on them
k - (look at stacks in debugger => top is end, bottom is init/start 00000000)
? - (evaluation cmd to get HEX equiv)
lm (loaded modules (lm v m malware => show verbose module (m)atching 'malware'))
du - (display Unicode value)
.crash - (forces blue screen crash and .dmp)

-------REGEX--------------------------------------------------
(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?
File Path with Filename and extension
/((\/|\\|\/\/|https?:\\\\|https?:\/\/)[a-z0-9 _@\-^!#$%&+={}.\/\\\[\]]+)+\.[a-z]+$/
 File Path with optional Filename, extension
/^(.+)/([^/]+)$/
File Name with extension having 3 chars
/^[\w,\s-]+\.[A-Za-z]{3}$/
/* Match IPv4 address */
/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/
/* Match IPv6 address */
/(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/
/* Match both IPv4, IPv6 addresses */
/((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))/
Elements with Attributes /<\/?[\w\s]*>|<.+[\W]>/
Slug /^[a-z0-9]+(?:-[a-z0-9]+)*$/
Digits
    Whole Numbers – /^\d+$/
    Decimal Numbers – /^\d*\.\d+$/
    Whole + Decimal Numbers – /^\d*(\.\d+)?$/
    Negative, Positive Whole + Decimal Numbers – /^-?\d*(\.\d+)?$/
    Whole + Decimal + Fractions – /[-]?[0-9]+[,.]?[0-9]*([\/][0-9]+[,.]?[0-9]*)*/
Alphanumeric without space – /^[a-zA-Z0-9]*$/
Alphanumeric with space – /^[a-zA-Z0-9 ]*$/
Common email Ids – /^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6})*$/
Uncommon email ids – /^([a-z0-9_\.\+-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/
Password Strength
Complex: Should have 1 lowercase letter, 1 uppercase letter, 1 number, 1 special character and be at least 8 characters long
/(?=(.*[0-9]))(?=.*[\!@#$%^&*()\\[\]{}\-_+=~`|:;"'<>,./?])(?=.*[a-z])(?=(.*[A-Z]))(?=(.*)).{8,}/
Moderate: Should have 1 lc letter, 1 UC letter, 1 number, and be at least 8 characters long
/(?=(.*[0-9]))((?=.*[A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z]))^.{8,}$/
/* Username */
    Alphanumeric string that may include _ and – having a length of 3 to 16 characters –
    /^[a-z0-9_-]{3,16}$/
/* Date Format YYYY-MM-dd */
/([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))/
    Time Format HH:MM 12-hour, optional leading 0
    /^(0?[1-9]|1[0-2]):[0-5][0-9]$/
    Time Format HH:MM 12-hour, optional leading 0, Meridiems (AM/PM)
    /((1[0-2]|0?[1-9]):([0-5][0-9]) ?([AaPp][Mm]))/
    Time Format HH:MM 24-hour with leading 0
    /^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/
    Time Format HH:MM 24-hour, optional leading 0
    /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/
    Time Format HH:MM:SS 24-hour
    /(?:[01]\d|2[0123]):(?:[012345]\d):(?:[012345]\d)/


/* PowerShell has interesting return value behavior; vars are kept in global scope unless explicitly removed
$a = "Hello, World"
return $a
$a = "Hello, World"
$a
return */

-------DATA LAKE--------
Intermittent data holding area; a function of time restrictions, best for unstruct'd data/Ops Log/Config Data....... (for monitoring apps before a problem happens or gets worse)



References:

https://modernweb.com/45-useful-javascript-tips-tricks-and-best-practices/

https://pythontips.com/2015/04/19/nifty-python-tricks/#more-580

https://www.freelancer.com/community/articles/top-16-c-programming-tips-tricks

https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/inheritance 

https://www.debuggex.com/

https://digitalfortress.tech/tricks/top-15-commonly-used-regex/