Showing posts with label training. Show all posts
Showing posts with label training. Show all posts

Tuesday, July 2, 2019

Creating an IIS Redirect Rule from Subdomain to the Root Domain

IIS Rewrite Rules have a lot of inherent complexity.  They use regular expressions and are difficult to debug.  The server variables have little documentation provided by Microsoft.  Recently we had an ask from the business to redirect any requests for subdomains to the main domain.  While this is simple to understand it is difficult to write.

Before you create and debug a rewrite rule you need a couple things:
1.  Install IIS by going into Programs and Features then Windows Features
2.  Install the Web Platform Installer https://www.microsoft.com/web/downloads/platform.aspx  This installs modules for IIS like NuGet installs packages for .NET
3.  Use the Web Platform Installer to install the Rewrite Module

Here is the end result:



Match URL
The thing that hung me up for most of the time was the match url.  This is not the full URL as you would expect but simply the page that was requested like default.aspx.  This is Mistake #1 from Lex Li:  https://blog.lextudio.com/the-very-common-mistakes-when-using-iis-url-rewrite-module-a2ab7e4fee59

Condition Order
In order to do back references to conditions (see the {C:2} and {C:3} variables) you have to put the negate false conditions first.  If you don't the back reference does not work.

HTTP_HOST Matching
If you do not put the regular expression carat ^ for start and the dollar $ sign for end, IIS will redirect until the URL is too long and it throws an error.

Putting It All Together
https://www. - We always want to redirect to secure www
{C:2} and {C:3} - This is a back reference to the last condition, the last set of parenthesis.
{R:1} - This is the requested page from the Match URL

Debugging the Redirect Rule

1.  Here is some excellent documentation how to create a simple test file to debug your rewrite rule:

2.  I used Expresso to debug the regular expression to match the subdomain.rootdomain.  You can also use IIS by double clicking on the Re-write module for the site.    http://www.ultrapico.com/expresso.htm  

3.  What I found to be very useful was to change the redirect url to a query string to see what the variables were.  
<action type="Redirect" url="http://www.somesitethatdoesnotexist.com/?{C:2}-{R:1}" appendQueryString="false" />


Here is the reference documentation from Microsoft:
https://docs.microsoft.com/en-us/iis/extensions/url-rewrite-module/url-rewrite-module-20-configuration-reference





Monday, February 11, 2019

Augmenting Salesforce CLI Commands for VS Code


I have been working with the Salesforce Extension Pack for VS Code and I have been mostly pleased with the capabilities.  On my current project, I find myself constantly switching between orgs.  I was tired of typing in the command to list out the current org and the command to switch the current org.  
There is a great hotkey VS Code extension called terminal-command-keys that allows you to create a hotkey that executes a terminal command.  The Salesforce CLI with hotkeys; what could be better!
Here are the steps to use
  1. Install the VS Code extension terminal-command-keys
  2. Edit your keybindings.json by pressing Ctrl-Shift-P on the PC or Command-Shift-P on the Mac.  Edit the file on the right



Add a command to list all your orgs by pressing Ctrl-Shift-l
    {
    "key" : "ctrl+shift+l",
    "command": "terminalCommandKeys.run",
    "args" :
        {
            "cmd": "sfdx force:org:list",
            "saveAllFiles": false
        }
    },

Add a command to upload the current file by pressing Ctrl-Shift-u
    {
        "key": "ctrl+shift+u",
        "command": "terminalCommandKeys.run",
        "args": {
            "cmd": "sfdx force:source:deploy --sourcepath  ${file} --loglevel fatal",
            "newTerminal": false,
            "saveAllFiles": true,
            "showTerminal": true
        }
    },

Add a command to switch to your development org.  In my case, the alias is BossSand. Replace with the alias for your org.
    {
        "key" : "ctrl+shift+d",
        "command": "terminalCommandKeys.run",
        "args" :
        {
            "cmd": "sfdx force:config:set defaultusername=BossSand",
            "saveAllFiles": false
        }
    },

Add a command to switch to your test org.  In my case the alias is BossStage. Replace with the alias for your org.
    {
        "key" : "ctrl+shift+v",
        "command": "terminalCommandKeys.run",
        "args" :
        {
            "cmd": "sfdx force:config:set defaultusername=BossStage",
            "saveAllFiles": false
        }   
    }


Friday, January 18, 2019

Debugging Salesforce Tests with VS Code

Debugging in Salesforce is relatively new and it immature compared to debugging in Visual Studio or Eclipse.  Even Microsoft Access has a better debugger than Salesforce.  Essentially logs files are created when running tests and then the log files are used to step through the code.  It is after the fact debugging, you cannot change the path that the code has gone.

If you haven't already, set up VS Code for Salesforce


  1. Click the Debug icon
  2. In the drop down list at the top under Debug, Add Configuration.  Select Apex Replay Debugger
  3. Make sure that you have pulled all your code and tests down from source control or from your org.
  4. Using Ctrl-Shift-P on Windows or Command-Shift-P on a Mac, select SFDX: Turn On Apex Debug Log for Replay Debugger
  5. Set a break point in your test
  6. Run your test by clicking Run Test above the test method name in VS Code 
  7. Using Ctrl-Shift-P on Windows or Command-Shift-P on a Mac, select SFDX: Turn Off Apex Debug Log for Replay Debugger
  8. Using Ctrl-Shift-P on Windows or Command-Shift-P on a Mac, select SFDX: Get Apex Debug Logs
  9. Click the Debug icon
  10. Click the Launch Apex Replay Debugger
  11. You can see local variables on the left and you can step into code

Setting Up VS Code with Salesforce

These are step by step instructions to get VS Code working with Salesforce.


  1. Go to your Sandbox, under Setup search for Dev Hub.  Enable Dev Hub and GA.  This will allow you to create scratch orgs.
  2. Install the Salesforce CLI which will allow you to push and pull code and run tests:   https://developer.salesforce.com/tools/sfdxcli
  3. Install VS Code which is now the standard for editing code for Salesforce:  https://code.visualstudio.com/download
  4. Install Java if you do not have it installed yet.  The Salesforce Extension Pack requires it.  https://www.java.com/en/download/
  5. Install the Salesforce Extension Pack.  In VS Code, click the extensions icon and search for Salesforce Extension Pack.
  6. Install Lightning Web Components extension in VS Code
If your Salesforce code is in your org and not in source control then you are in Classic Development and not Salesforce DX.  

Classic Development Mode (directly interact with an Org)



* After creating the project, create these folders under the default folder before doing a Retrieve Source From Org:  

  • classes
  • objects

Salesforce DX Mode (your source is in GitHub or Bitbucket)

Example of cloning a repository, creating a scratch org and pushing the code

git clone https://github.com/dreamhouseapp/dreamhouse-sfdx
cd dreamhouse-sfdx
sfdx force:config:set defaultdevhubusername=your@username.com
sfdx force:org:create -a dreamhouse -s -f config\project-scratch-def.json -d 7
sfdx force:source:push
sfdx force:user:permset:assign -n dreamhouse
sfdx force:org:open -p /lightning/page/home

Wednesday, September 5, 2018

Using Caching in the .NET Framework

Caching is easy to use in the .NET Framework

According to Microsoft:
"In the .NET Framework 3.5 and earlier versions, ASP.NET provided an in-memory cache implementation in the System.Web.Caching namespace. In previous versions of the .NET Framework, caching was available only in the System.Web namespace and therefore required a dependency on ASP.NET classes. In the .NET Framework 4, the System.Runtime.Caching namespace contains APIs that are designed for both Web and non-Web applications."

Here are a couple methods to Load and Save from the Memory Cache.  If the value is not found, it will be null.  

public static class Cache
{
        public static TResult Load<TResult>(string cacheKeyName)
        {
            ObjectCache cacheInstance = MemoryCache.Default;
            return (TResult)cacheInstance[cacheKeyName];
        }

        public static T Save<T> (string cacheKeyName, DateTimeOffset expirationDate, T value)
        {
            CacheItemPolicy cacheItemPolicy = new CacheItemPolicy();
            cacheItemPolicy.AbsoluteExpiration = expirationDate;
            ObjectCache cacheInstance = MemoryCache.Default;
            cacheInstance.Set(cacheKeyName, value, cacheItemPolicy);
            return value;
        }
}

Example Call to Load and Save


Here is an example of using the load and save with a stopwatch so that the time saved can be shown:


        [Test]
        public void SimpleLoadAndSaveTest()
        {
            Stopwatch watch = Stopwatch.StartNew();
            string json = Cache.Load<string>("JsonValue");

            if (json == null)
            {
                json = GetJsonFromWebService("cf4174ce-96d2-495c-b58a-427d35f64a20");
                Cache.Save("JsonValue", DateTimeOffset.Now.AddMinutes(20), json);
            }
            watch.Stop();
            Console.WriteLine(watch.ElapsedMilliseconds);

            watch.Restart();
            json = Cache.Load<string>("JsonValue");
            watch.Stop();
            Console.WriteLine(watch.ElapsedMilliseconds);
        }

        public string GetJsonFromWebService(string value)
        {
            Thread.Sleep(1000);
            return "{ \"Value\" : \"" + value + "\" }";
        }

Cache Class


I have created a larger caching class where methods can be passed into shorten the code:


    public static class Cache
    {
        public static TResult Load<TResult>(string cacheKeyName)
        {
            ObjectCache cacheInstance = MemoryCache.Default;
            return (TResult)cacheInstance[cacheKeyName];
        }

        public static T Save<T> (string cacheKeyName, DateTimeOffset expirationDate, T value)
        {
            CacheItemPolicy cacheItemPolicy = new CacheItemPolicy();
            cacheItemPolicy.AbsoluteExpiration = expirationDate;
            ObjectCache cacheInstance = MemoryCache.Default;
            cacheInstance.Set(cacheKeyName, value, cacheItemPolicy);
            return value;
        }


        public static TResult Load<TResult>(string cacheKeyName, int expirationMinutes, Func<TResult> serviceFunction)
        {
            return Load<TResult>(cacheKeyName, DateTimeOffset.Now.AddMinutes(expirationMinutes), serviceFunction);
        }

        public static TResult Load<TResult>(string cacheKeyName, int expirationMinutes, Func<string, TResult> serviceFunction, string stringArg)
        {
            return Load<TResult>(cacheKeyName, DateTimeOffset.Now.AddMinutes(expirationMinutes), serviceFunction, stringArg);
        }

        public static TResult Load<TResult>(string cacheKeyName, int expirationMinutes, Func<long, TResult> serviceFunction, long longArg)
        {
            return Load<TResult>(cacheKeyName, DateTimeOffset.Now.AddMinutes(expirationMinutes), serviceFunction, longArg);
        }

        public static TResult Load<TResult>(string cacheKeyName, int expirationMinutes, Func<int, TResult> serviceFunction, int intArg)
        {
            return Load<TResult>(cacheKeyName, DateTimeOffset.Now.AddMinutes(expirationMinutes), serviceFunction, intArg);
        }

        public static TResult Load<TResult>(string cacheKeyName, DateTime expirationDate, Func<TResult> serviceFunction)
        {
            return Load<TResult>(cacheKeyName, new DateTimeOffset(expirationDate), serviceFunction);
        }

        public static TResult Load<TResult>(string cacheKeyName, DateTime expirationDate, Func<string, TResult> serviceFunction, string stringArg)
        {
            return Load<TResult>(cacheKeyName, new DateTimeOffset(expirationDate), serviceFunction, stringArg);
        }

        public static TResult Load<TResult>(string cacheKeyName, DateTime expirationDate, Func<long, TResult> serviceFunction, long longArg)
        {
            return Load<TResult>(cacheKeyName, new DateTimeOffset(expirationDate), serviceFunction, longArg);
        }

        public static TResult Load<TResult>(string cacheKeyName, DateTime expirationDate, Func<int, TResult> serviceFunction, int intArg)
        {
            return Load<TResult>(cacheKeyName, new DateTimeOffset(expirationDate), serviceFunction, intArg);
        }

        public static TResult Load<TResult>(string cacheKeyName, DateTimeOffset expirationDateOffset, Func<TResult> serviceFunction) 
        {
            TResult cachedObject = Load<TResult>(cacheKeyName);

            if (cachedObject == null)
            {                
                cachedObject = Save(cacheKeyName, expirationDateOffset, serviceFunction());
            }

            return cachedObject;
        }

        public static TResult Load<TResult>(string cacheKeyName, DateTimeOffset expirationDateOffset, Func<string, TResult> serviceFunction, string stringArg)
        {
            TResult cachedObject = Load<TResult>(cacheKeyName);

            if (cachedObject == null)
            {
                cachedObject = Save(cacheKeyName, expirationDateOffset, serviceFunction(stringArg));
            }

            return cachedObject;
        }

        public static TResult Load<TResult>(string cacheKeyName, DateTimeOffset expirationDateOffset, Func<long, TResult> serviceFunction, long longArg)
        {
            TResult cachedObject = Load<TResult>(cacheKeyName);

            if (cachedObject == null)
            {
                cachedObject = Save(cacheKeyName, expirationDateOffset, serviceFunction(longArg));
            }

            return cachedObject;
        }

        public static TResult Load<TResult>(string cacheKeyName, DateTimeOffset expirationDateOffset, Func<int, TResult> serviceFunction, int intArg)
        {
            TResult cachedObject = Load<TResult>(cacheKeyName);

            if (cachedObject == null)
            {
                cachedObject = Save(cacheKeyName, expirationDateOffset, serviceFunction(intArg));
            }

            return cachedObject;
        }

    }

Example using Func with Caching

The function can be passed in that will fill the data if it does not exist in the cache.

        [Test]
        public void CacheTestUsingFunc()
        {
            Stopwatch watch = Stopwatch.StartNew();
            string json = Cache.Load<string>("JsonValue", 20, GetJsonFromWebService, "cf4174ce-96d2-495c-b58a-427d35f64a20");
            watch.Stop();
            Console.WriteLine(watch.ElapsedMilliseconds);

            watch.Restart();
            json = Cache.Load<string>("JsonValue", 20, GetJsonFromWebService, "cf4174ce-96d2-495c-b58a-427d35f64a20");
            watch.Stop();
            Console.WriteLine(watch.ElapsedMilliseconds);
        }

        public string GetJsonFromWebService(string value)
        {
            Thread.Sleep(1000);
            return "{ \"Value\" : \"" + value + "\" }";
        }

Thursday, June 1, 2017

Debugging Jasmine Tests with Karma and Visual Studio Code

  1. The Visual Studio Code Debugger only works with specific combinations of the Debugger for Chrome, Visual Studio Code, Angular CLI and Angular.  Make sure you are using the latest version of all libraries, extensions and tools or you will get the dreaded Breakpoint ignored because generated code not found.  For example, Angular 4.0 with the 1.0 version of Angular CLI does not work but Angular 4.1.3 with Angular CLI 1.0.6 works fine.
  2. Install the Visual Studio Code Extension, Chrome Debugger by clicking on the extensions icon on the left in Visual Code, searching for Chrome and clicking Install.
  3. On the Debug menu, click Open Configurations.




4. Modify your .vscode\launch.json to be this:
{
"version""0.2.0",
"configurations": [
{
"type""chrome",
"request""launch",
"name""Launch Chrome against localhost",
"webRoot""${workspaceRoot}"
},
{
"type":"chrome",
"request""launch",
"name""Launch Chrome against Karma",
"webRoot""${workspaceRoot}"
}
]
}
5.  CLOSE ALL Chrome Browsers
6.  Run npm start at the command line in the directory for your application.

7. Run karma start at another command window in the directory for your application
8. Click the Debug icon on the left
9. Set a breakpoint
10. Choose Launch Chrome against Karma.  After the browser comes up, refresh it.




Friday, April 28, 2017

Jasmine Examples

Example of a Simple Test

describe('a super simple test', () => {
it('should be true', () => {
expect(true).toBe(true);
});
it('should be false', () => {
expect(false).toBe(false);
});
});

Setup and Teardown


describe("A set of tests using beforeEach and afterEach", () => {
var x = 0;
beforeEach(function() {
x += 1;
});
afterEach(function() {
x = 0;
});
it("is just a function, so it can contain any code", () => {
expect(x).toEqual(1);
});
it("can have more than one expectation", () => {
expect(x).toEqual(1);
expect(true).toEqual(true);
});
});

Expect Matching


expect(myValue).toBe(true); // Use JS strict equality
expect(myValue).not.toBe(true);
expect(myValue).toEqual(482); // Use deep equality, recursive search through objects
expect(myValue).toBeDefined();
expect(myValue).not.toBeDefined();
expect(myValue).toBeUndefined();
expect(myValue).toBeTruthy(); // Boolean cast testing
expect(myValue).toBeFalsy();
expect(myValue).toContain('sometext'); // Find item in array
expect(e).toBeLessThan(pi);
expect(pi).toBeGreaterThan(e);
expect(x).toBeCloseTo(y, 2); // x to be close to y by 2 decimal points
Exception Matching
expect(function() {
MyMethod(1, '2')
}).toThrowError();
expect(function() {
MyMethod(1, '2')
}).toThrow(new Error('Invalid parameter type.')

Spies

Spies can stub any function and tracks calls to it and all arguments.
A spy only exists in the describe or it block in which it is defined, and will be removed after each spec.

describe('SuperAwesomeModule', function() {
beforeEach(function() {
// track all calls to SuperAwesomeModule.coolHelperFunction()
// and also delegate to the actual implementation
spyOn(SuperAwesomeModule, 'coolHelperFunction').and.callThrough();
});
describe('featureA', function() {
it('should ...', function() {
expect(SuperAwesomeModule.featureA(2)).toBe(5);

// matchers for spies
expect(SuperAwesomeModule.coolHelperFunction).toHaveBeenCalled();
expect(SuperAwesomeModule.coolHelperFunction).toHaveBeenCalledTimes(1);
});
});
});
Spies: and.returnValue
Useful when you want to stub out return values
describe('SuperAwesomeModule', function() {
beforeEach(function() {
spyOn(SuperAwesomeModule, 'coolHelperFunction').and.returnValue('myValue');
});
});

Karma Resources

Karma is a test runner for testing JavaScript and TypeScript.  
Install Karma
yarn global add karma-cli
Run all tests
karma start 
Testing Angular 2 Apps with Jasmine and Karma
https://www.youtube.com/watch?v=yG4FH60fhUE
Unit Testing Recipes for Angular 2
http://slides.com/victormejia/unit-testing-ng2#/ 

Example karma.conf.js


This file uses the new Angular CLI (the namespace has changed).  

// Karma configuration file, see link for more information
// https://karma-runner.github.io/0.13/config/configuration-file.html

module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
files: [
{ pattern: './src/test.ts', watched: false }
],
preprocessors: {
'./src/test.ts': ['@angular/cli']
},
mime: {
'text/x-typescript': ['ts','tsx']
},
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
angularCli: {
environment: 'dev'
},
reporters: config.angularCli && config.angularCli.codeCoverage
? ['progress', 'coverage-istanbul']
: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};

Thursday, April 13, 2017

Angualar CLI Resources

Links

Usage

Installation
npm install -g @angular/cli
New Project
ng new <project-name>
Generate a component
ng generate <component-name>
Run the server on http://localhost:4200
ng serve <project-name>

Videos

How to get productive immediately on Angular 2 with Angular-CLI
https://www.youtube.com/watch?v=sc8wAwn4dn4&t=1s
Simple Angular 2 App With Angular CLI
https://www.youtube.com/watch?v=QMQbAoTLJX8

Tutorials

The Ultimate Angular CLI Reference Guide
https://www.sitepoint.com/ultimate-angular-cli-reference/
Angular 2 Tutorial: Create a CRUD App with Angular CLI
https://www.sitepoint.com/angular-2-tutorial/

Cheat Sheets

Yarn Package Manager Resources

Overview


Yarn is a node package manager for your code that is better than npm or bower. Yarn is created by Facebook in collaboration with Google, Exponent, and Tilde.
Benefits
  • Faster than npm. It is around 3 to 4 times faster than npm without any cache. It downloads the dependencies in parallel. It is much faster once it is cached. https://www.youtube.com/watch?v=yksxtxqORvY
  • Deterministic. It will install the same consistent reproducable package dependencies and versions. npm depends on the install order and is non-deterministic (it may download a new minor or patch version) which could break your project.
  • Works offline
  • Supports other repos/formats
  • Backward compatible to npm.
  • Has Emojies 😎

Setup

Install Yarn
https://yarnpkg.com/en/docs/install OR npm install -g yarn

Configure Proxy
yarn config set proxy http://username:password@yourproxyserver:8080/
yarn config set https-proxy http://username:password@yourproxyserver:8080/

Change Angular CLI to use yarn
ng set = --global packageManager=yarn
Migrating from npm. Run this in your project directory.
yarn

Videos

Chris Courses: Intro to Yarn
https://www.youtube.com/watch?v=7n467QmiANM
Coding The Smart Way: Yarn Package Manager
https://www.youtube.com/watch?v=6JxSYFnW4rc

Tuitorials


Cheat Sheets