Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Thursday, November 27, 2014

 

  • View – just markup/view logic
  • Directives – eg ng-repeat,
  • Controller – eg code inside MainController which is linked via ng-controller
  • Services – reusable code

Countdown

setTimeout is a js function to do something in x ms

setContinue will continue to invoke every x ms

angular provides a service which wraps these funcitons $timeout and $interval.

Good to use theses services

  • Unit testable
  • Databinding issues

$http is a service.. but needs .get
$interval is a service.. but doesn’t need a .

5:30 of 8:50

var app = angular.module('my-app', []); // Injecting in the services we need? var MainController = function($scope, $http, $interval) { var onUserComplete = function(response) { $scope.user = response.data; // Service - More of an object API $http.get($scope.user.repos_url) .then(onRepos, onError) }; var onRepos = function(response) { $scope.repos = response.data; } var onError = function(reason) { $scope.error = "Could not fetch the data"; }; var decrementCountdown = function() { $scope.countdown --; if ($scope.countdown < 1) { $scope.search($scope.username); } } var startCountdown = function() { // Service - Function - can directly invoke it $interval(decrementCountdown, 1000, $scope.countdown); } $scope.search = function(username) { $http.get("https://api.github.com/users/" + username) .then(onUserComplete, onError); }; $scope.username = "angular" $scope.message = "Github Viewer"; $scope.repoSortOrder = "-stargazers_count"; $scope.countdown = 5; startCountdown(); } app.controller("MainController", MainController);

HTML:

<!DOCTYPE html> <html ng-app="my-app"> <head> <script data-require="angular.js@*" data-semver="1.3.1" src="//code.angularjs.org/1.3.1/angular.js"></script> <link rel="stylesheet" href="style.css" /> <script src="script.js"></script> </head> <body ng-controller="MainController"> <h1>{{message}}</h1> <div>{{error}}</div> {{ countdown }} <form name="searchUser" ng-submit="search(username)"> <!-- required validation--> <input type="search" required placeholder="username to find" ng-model="username" /> <input type="submit" value="Search" /> </form> <div ng-include="'userdetails.html'" ng-show="user"></div> </body> </html>

Build your own Services

  • resuable logic
  • shared data (eg sharing between controllers)
  • manage complexity (in a controller)

Many different ways to register a service with Angular

// angular is in the global namespace, no dependencies for this module var app = angular.module('githubViewer', []); // Injecting in the services we need? var MainController = function( $scope, github, $interval, $log, $anchorScroll, $location) { var onUserComplete = function(data) { $scope.user = data; // Service - More of an object API github.getRepos($scope.user).then(onRepos, onError) }; var onRepos = function(data) { $scope.repos = data; $location.hash("userDetails"); $anchorScroll(); } var onError = function(reason) { $scope.error = "Could not fetch the data"; }; var decrementCountdown = function() { $scope.countdown --; if ($scope.countdown < 1) { $scope.search($scope.username); } } var countdownInterval = null; var startCountdown = function() { // Service - Function - can directly invoke it countdownInterval = $interval(decrementCountdown, 1000, $scope.countdown); } $scope.search = function(username) { // In developer tools can see output $log.info("Searching for " + username); github.getUser(username).then(onUserComplete, onError); if(countdownInterval) { $interval.cancel(countdownInterval); // Blanking out the coundown number $scope.countdown = null; } }; $scope.username = "angular" $scope.message = "Github Viewer"; $scope.repoSortOrder = "-stargazers_count"; $scope.countdown = 5; startCountdown(); } app.controller("MainController", MainController);

HTML

<!DOCTYPE html> <html ng-app="githubViewer"> <head> <script data-require="angular.js@*" data-semver="1.3.1" src="//code.angularjs.org/1.3.1/angular.js"></script> <link rel="stylesheet" href="style.css" /> <script src="script.js"></script> <script src="github.js"></script> </head> <body ng-controller="MainController"> <h1>{{message}}</h1> <div>{{error}}</div> {{ countdown }} <form name="searchUser" ng-submit="search(username)"> <!-- required validation--> <input type="search" required placeholder="username to find" ng-model="username" /> <input type="submit" value="Search" /> </form> <div ng-include="'userdetails.html'" ng-show="user"></div> </body> </html>

github.js service:

(function() { // revealing module pattern var github = function($http) { var getUser = function(username) { // when getUser is called, they are going to get back a promise return $http.get("https://api.github.com/users/" + username) .then(function(response) { // as this is in .then, this is returned as a promise/callback return response.data; }); }; var getRepos = function(user){ return $http.get(user.repos_url) .then(function(response) { return response.data; }); }; return { getUser: getUser, getRepos: getRepos }; }; var module = angular.module("githubViewer"); module.factory("github", github); }());
| | # 

depends on angular-route.js, ng-route, and configure $routeProvider

default.html will become a layour/shell view – menu and footer

  • index.html (shell)
  • main.html (searching)
  • user.html (user details)
  • repo.html (repo details)

Idea is: **done modules in wrong order.. come back to this**

| | # 
# Wednesday, November 26, 2014

https://api.github.com/users/angular

ng-click and ng-submit

<body ng-controller="MainController"> <h1>{{message}}</h1> <div>{{error}}</div> {{ username }} <form name="searchUser"> <!-- push the username into the $scope --> <input type="search" placeholder="username to find" ng-model="username" /> <input type="submit" value="Search" ng-click="search(username)" /> </form> <div> <h2>{{ user.name }}</h2> <img ng-src="{{user.avatar_url}}" title="{{user.name}}" /> </div> </body>

then

var app = angular.module('my-app', []); var MainController = function($scope, $http) { var onUserComplete = function(response) { $scope.user = response.data; }; var onError = function(reason) { $scope.error = "Could not fetch the user"; }; $scope.search = function(username) { $http.get("https://api.github.com/users/" + username) .then(onUserComplete, onError); }; $scope.username = "angular" $scope.message = "Github Viewer"; } app.controller("MainController", ["$scope", "$http", MainController]);

image

HTML Validation

<!-- using ng-submit so can do validation --> <form name="searchUser" ng-submit="search(username)"> <!-- required validation--> <input type="search" required placeholder="username to find" ng-model="username" /> <input type="submit" value="Search" /> </form>

image

ng-repeat

https://api.github.com/users/angular/repos 
image
<table> <thead> <tr> <th>Name</th> <th>Stars</th> <th>Language</th> </tr> </thead> <!-- ng-repeat is like a foreach loop --> <tbody> <tr ng-repeat="repo in repos"> <td>{{repo.name}}</td> <!-- number is a filter --> <td>{{repo.stargazers_count | number}}</td> <td>{{repo.language}}</td> </tr> </tbody> </table>
and

var onUserComplete = function(response) { $scope.user = response.data; $http.get($scope.user.repos_url) .then(onRepos, onError) }; var onRepos = function(response) { $scope.repos = response.data; }

When the user has come back from github, do another call to get the repo’s, then put that into scope.

Filters

eg currency, date, filter (search), json (good for debugging), limitTo (eg take), lowercase, uppercase, orderBy

image

Order: <select ng-model="repoSortOrder"> <option value="+name">Name</option> <option value="-stargazers_count">Stars</option> <option value="+language">Language</option> </select> <table> <thead> <tr> <th>Name</th> <th>Stars</th> <th>Language</th> </tr> </thead> <!-- orderyBy minus is descending sort order --> <tbody> <tr ng-repeat="repo in repos | orderBy:repoSortOrder"> <td>{{repo.name}}</td> <!-- number is a filter --> <td>{{repo.stargazers_count | number}}</td> <td>{{repo.language}}</td> </tr> </tbody> </table>
$scope.username = "angular" $scope.message = "Github Viewer"; $scope.repoSortOrder = "-stargazers_count";

ng-show ng-hide ng-include

image

<!-- show if we do have a user - a string can be 'true'.. ie undefined is false --> <div ng-show="user"> <h2>{{ user.name }}</h2> <img ng-src="{{user.avatar_url}}" title="{{user.name}}" width="80" height="80" />Order: <select ng-model="repoSortOrder"> <option value="+name">Name</option> <option value="-stargazers_count">Stars</option> <option value="+language">Language</option> </select> </div> <!-- hide this if we don't have a user --> <table ng-hide="!user"> <thead> <tr> <th>Name</th> <th>Stars</th> <th>Language</th> </tr> </thead>
<!-- using ng-submit so can do validation --> <form name="searchUser" ng-submit="search(username)"> <!-- required validation--> <input type="search" required placeholder="username to find" ng-model="username" /> <input type="submit" value="Search" /> </form> <div ng-include="'userdetails.html'" ng-show="user"></div>

Directives

used ng-click

ng-mouseover, ng-doubleclick, ng-keypress

customdirectives eg dragndrop, bootstrap widgets

| | # 
# Monday, November 24, 2014

$scope – dollar is a sign that the component is angular eg attached model to $scope

4:17 of ControllerBasics

image
Not defined the controller function yet.

http://plnkr.co/edit/c9Ze2H89FGa4eEdeO72N?p=preview

image

 

var app = angular.module('my-app', [], function() { }) app.controller('MainController', function($scope) { // Object literal syntax var person = { firstName: "Scott", lastName: "Allen", imageSrc: "http://odetocode.com/Images/scott_allen_2.jpg" }; $scope.message = "Hello, Angular!"; $scope.person = person; })

then:

<html ng-app="my-app"> <head> <script data-require="angular.js@*" data-semver="1.3.1" src="//code.angularjs.org/1.3.1/angular.js"></script> <link rel="stylesheet" href="style.css" /> <script src="script.js"></script> </head> <body ng-controller="MainController"> <h1>{{message}}</h1> Length of title: {{message.length}} <div> <div>First name: {{person.firstName}}</div> <div>Last name: {{person.lastName}}</div> <div> <!-- Once angular is up and running and evaluated the expression it will load --> <img ng-src="{{person.imageSrc}}" title="{{person.firstName}} {{person.lastName}}" /> </div> </div> </body> </html>

$http Service

var app = angular.module('my-app', [], function() { }) app.controller('MainController', function($scope, $http) { var onUserComplete = function(response) { $scope.user = response.data; }; var onError = function(reason) { $scope.error = "Could not fetch the user"; }; $http.get("https://api.github.com/users/robconery") // a promise .then(onUserComplete, onError); $scope.message = "Hello, Angular!"; })

or

// angular is in the global namespace var app = angular.module('my-app', []); var MainController = function($scope, $http) { var onUserComplete = function(response) { $scope.user = response.data; }; var onError = function(reason) { $scope.error = "Could not fetch the user"; }; $http.get("https://api.github.com/users/robconery") // a promise .then(onUserComplete, onError); $scope.message = "Hello, Angular!"; } //app.controller("MainController", MainController); // For minification need to tell Angular explicitly it's dependencies app.controller("MainController", ["$scope", "$http", MainController]);

I prefer this syntax.

<!DOCTYPE html> <html ng-app="my-app"> <head> <script data-require="angular.js@*" data-semver="1.3.1" src="//code.angularjs.org/1.3.1/angular.js"></script> <link rel="stylesheet" href="style.css" /> <script src="script.js"></script> </head> <body ng-controller="MainController"> <h1>{{message}}</h1> <div> {{error}} </div> <div> <div> User: {{user.name}} </div> <div> Location: {{user.location}} </div> <div> <img ng-src="{{user.avatar_url}}" title="{{user.name}}" /> </div> </div> </body> </html>
Next module on Views and Directives..

| | # 

Google project, now OS

builtwith.angular.js

youtube, msnbc

plnkr.co

image

<ng-app> – application directive

<body ng-app> <h1>Hello Plunker!</h1> {{ 843 / 42}} </body>

Binding expression – double {{

Monokai editor, and no autorefresh in editor.

image
F12 for developer tools in chrome, and then right click to clear the console messages.

JavaScript Patterns

  • Functions as abstractions
  • Functions to build modules
  • Functions to avoid global variables
var work = function() { console.log("working hard!"); }; //work();

Then

var work = function() { console.log("working hard!"); }; // Generic function which logs, and does error handling // Functions as abstractions var doWork = function(f) { console.log("starting"); try { f(); } catch(ex) { console.log(ex); } console.log("end"); }; // Pass the varibla work (which is a function) // into doWork which executes the first function doWork(work);

Functions as Modules

// Revealing module pattern var createWorker = function() { // Private implementation details var workCount = 0; var task1 = function() { workCount += 1; console.log("task1 " + workCount); }; var task2 = function() { workCount += 1; console.log("task2 " + workCount); }; return { // Public API // Job1 points to task1 job1: task1, job2: task2 }; } // Global variable (bad) var worker = createWorker(); worker.job1(); worker.job2(); worker.job2(); worker.job2();

Global Variables

variables defined outside of any other function.  createWorker and worker above

In JS they are evil!

var program = function() { // Revealing module pattern var createWorker = function() { // Private implementation details var workCount = 0; var task1 = function() { workCount += 1; console.log("task1 " + workCount); }; var task2 = function() { workCount += 1; console.log("task2 " + workCount); }; return { // Public API // Job1 points to task1 job1: task1, job2: task2 }; } // Global variable (bad) var worker = createWorker(); worker.job1(); worker.job2(); worker.job2(); worker.job2(); } program();

1 global variable now.

// Immediately invoked fucntion expression "iffy" // Anonymous function (function() { // Revealing module pattern var createWorker = function() { // Private implementation details var workCount = 0; var task1 = function() { workCount += 1; console.log("task1 " + workCount); }; var task2 = function() { workCount += 1; console.log("task2 " + workCount); }; return { // Public API // Job1 points to task1 job1: task1, job2: task2 }; } // Global variable (bad) var worker = createWorker(); worker.job1(); worker.job2(); worker.job2(); worker.job2(); }());

A lot of JS libraries use IFFY’s to control the scope of variables, and avoid global variables!

| | # 
# Monday, November 17, 2014

https://chocolatey.org/

choco install Atom

choco install notepadplusplus

choco install ccleaner

choco install paint.net

choco install dropbox

choco install filezilla

choco install vlc

choco install 7zip

| | # 
# Tuesday, November 11, 2014
( VPN )

I keep my VPN alive from my desktop PC at work, so can dial in from home/other offices.  Sometimes the VPN drops (for whatever reason)

Setup a task in Task Scheduler:

image

image
When a VPN disconnect is detected, wait for a minute, then run.  Keep running every 30minutes for a day.

and the batch file that is run is:

rasdial “nameofVPN” username password

| | # 
( regex )

public static void Main(){ var security = "123-12-1234"; var pattern = @"^\d{3}-\d{2}-\d{4}$"; var result = Regex.Match(security, pattern); Console.WriteLine(result); }

d – Digit

public static void Main(){ var security = "ABC 123"; //var security = "123 ABC"; var pattern = @"(^\d{3} [A-Z]{3}$)|(^[A-Z]{3} \d{3}$)"; var result = Regex.Match(security, pattern); Console.WriteLine(result); }

Or..

public static void Main() { #if DEBUG Console.WriteLine("Mode=Debug"); #else Console.WriteLine("Mode=Release"); #endif #if TRACE Console.WriteLine("Mode=On"); #else // never called Console.WriteLine("Mode=Off"); #endif }

Trace On is called in Debug and Release modes.

Crypto

public static void Main() { string data = "asdf"; byte[] userData = GetBytes(data); using (SHA256 shaM = new SHA256Managed()) { var result = shaM.ComputeHash(userData); } } static byte[] GetBytes(string str) { byte[] bytes = new byte[str.Length * sizeof(char)]; System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length); return bytes; }

Strong Names

A strong name consists of the assembly's identity — its simple text name, version number, and culture information (if provided) — plus a public key and a digital signature.

You can use strong naming to ensure that when you load a DLL you get exactly the DLL you were expecting and not some other DLL that happens to have the same name.

http://stackoverflow.com/questions/2982780/what-is-strong-name-in-net

| | # 
# Wednesday, November 05, 2014

As part of the c# there is a section on reflection:

Attributes eg

[Serializable] class Person { public string FirstName { get; set; } public string LastName { get; set; } }

asdf
[Fact] [Trait(“Category”, “Unit Test”)] public void MyUnitTest() { }

can derive from this:

public class CategoryAttribute : TraitAttribute { public CategoryAttribute(string value) : base(“Category”, value){ } } public class UnitTestAttribute : CategoryAttribute { public UnitTestAttribute() : base(“Unit Test”){ } }

then

[Fact] [UnitTest] public void MySecondUnitTest() {}

Interesting.

Reflection

Reflection enables an application to collection information about itself

public static void Main() { int i = 42; // GetType is a method on Object System.Type type = i.GetType(); // System.Int32 Console.WriteLine(type); }

If you want a plug-in system, and you drop in an assembly in a directory.  Need to use reflection.

class Program { public interface IPlugin { string Name { get; } string Description { get; } bool Load(MyApplication application); } public class MyApplication{} public static void Main() { Assembly pluginAssembly = Assembly.Load("testassembly"); var plugins = from type in pluginAssembly.GetTypes() //where typeof(IPlugin).IsAssignableFrom(type) && !type.IsInterface where !type.IsInterface select type; foreach (Type pluginType in plugins) { // Returns null instances IPlugin plugin = Activator.CreateInstance(pluginType) as IPlugin; } } }

and then the testassembly:
namespace testassembly { public interface IPlugin { string Name { get; } string Description { get; } bool Load(MyApplication application); } public class MyPlugin : IPlugin { public string Name { get { return "MyPlugin"; } } public string Description { get { return "My Sample Plugin"; } } public bool Load(MyApplication application) { return true; } } public class MyApplication { } }

Am not understanding this yet….
public static void Main() { Assembly myAssembly = Assembly.GetExecutingAssembly(); // Bring back classes Type[] myAssemblysTypes = myAssembly.GetTypes(); foreach (Type myType in myAssemblysTypes) { Console.WriteLine("myType Name: {0}", myType.Name); } // ConsoleAppliation2.exe Module[] myAssemblysModules = myAssembly.GetModules(); foreach (Module myModule in myAssemblysModules) { Console.WriteLine("myModule Name: {0}", myModule.Name); } // Assembly name and version var x = new MyApplication(); // mscorlib 4.0.0 // testassembly 1.0.0.0 AssemblyName[] referencedAssemblyNames = myAssembly.GetReferencedAssemblies(); foreach (AssemblyName assemblyName in referencedAssemblyNames) { Console.WriteLine("Assembly Name: {0}", assemblyName.Name); Console.WriteLine("Assembly Version: {0}", assemblyName.Version); } // Fields **not working Type t = typeof(Program); FieldInfo[] fields = t.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); foreach (FieldInfo fi in fields) { Console.WriteLine("Field name {0}", fi.Name); Console.WriteLine("Field value {0}", fi.GetValue(null)); } }

not working yet :-)
var blah = new Blah(); blah.Age = 42; DumpObject(blah); } static void DumpObject(object obj) { FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); foreach (FieldInfo field in fields) { if (field.FieldType == typeof(int)) { Console.WriteLine(field.GetValue(obj)); } } } } public class Blah { public int Age { get; set; } private int _age; public Blah() { _age = 41; } }

Code that works, showing how to get values or public and private fields using reflection.

// Run a method on Blah MethodInfo doSomethingMethod = blah.GetType().GetMethod("DoSomething", new Type[] { typeof(int) }); int result = (int)doSomethingMethod.Invoke(blah, new object[] { 42 }); Console.WriteLine(result);

and the method is

public int DoSomething(int x) { return x + 1; }

CodeDom and lambdas to generate code

CodeDom to create an object graph that can be converted to a source file/binary assembly that can be executed.

public static void Main() { var compileUnit = new CodeCompileUnit(); var myNamespace = new CodeNamespace("MyNamespace"); myNamespace.Imports.Add(new CodeNamespaceImport("System")); var myClass = new CodeTypeDeclaration("MyClass"); var start = new CodeEntryPointMethod(); var cs1 = new CodeMethodInvokeExpression( new CodeTypeReferenceExpression("Console"), "WriteLine", new CodePrimitiveExpression("Hello World!")); compileUnit.Namespaces.Add(myNamespace); myNamespace.Types.Add(myClass); myClass.Members.Add(start); start.Statements.Add(cs1); var provider = new CSharpCodeProvider(); using (var sw = new StreamWriter("HelloWorld.cs", false)) { var tw = new IndentedTextWriter(sw, " "); provider.GenerateCodeFromCompileUnit(compileUnit, tw, new CodeGeneratorOptions()); tw.Close(); } }

which generated:

//------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. // Runtime Version:4.0.30319.34014 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // </auto-generated> //------------------------------------------------------------------------------ namespace MyNamespace { using System; public class MyClass { public static void Main() { Console.WriteLine("Hello World!"); } } }

wow!

Lambda functions were introduced in C#3.  It is a compact method to create an anonymous method.

// Func type takes 2 ints and returns and int. // Lambda - anonymous method Func<int, int, int> addFunc = (x, y) => x + y; Console.WriteLine(addFunc(2, 3));

Expression Trees

// The expression is first constructed with a call to Console.Write and Console.WriteLine. BlockExpression blockExpr = Expression.Block( Expression.Call(null,typeof(Console).GetMethod("Write", new Type[] { typeof(String) }),Expression.Constant("Hello ")), Expression.Call(null,typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) }),Expression.Constant("World!")) ); // Expression is compiled to an Action (as no return) Expression.Lambda<Action>(blockExpr).Compile()();

asdf
| | # 
# Tuesday, November 04, 2014
public static void Main() { int n = 0; // Trying to accessing a local varialbe from another thread var up = Task.Run(() => { for (int i = 0; i < 1000000; i++){ // Reads the value and adds 1 n++; } }); for (int i = 0; i < 1000000; i++){ // Reads the value and subtracts 1 n--; } // Wait for task to complete execution up.Wait(); // Get a different result each time Console.WriteLine(n); }

If the add thread reads then adds, at the same time the subtract thread reads and subtracts, we’re not going to get the expected total of 0.

int n = 0; var _lock = new object(); var up = Task.Run(() => { for (int i = 0; i < 1000000; i++) { // no way other thread can change value while this one is working on it lock (_lock) { n++; } } }); for (int i = 0; i < 1000000; i++) { lock (_lock) { n--; } } // Wait for task to complete execution up.Wait(); Console.WriteLine(n);

Volatile

Disables compiler optimisations.. enforces code order.

InterLocked

private static void Main() { int n = 0; var up = Task.Run(() => { for (int i = 0; i < 1000000; i++) { Interlocked.Increment(ref n); } }); for (int i = 0; i < 1000000; i++) { Interlocked.Decrement(ref n); } up.Wait(); Console.WriteLine(n); }

 

CancellationTasks

private static void Main() { var cancellationTokenSource = new CancellationTokenSource(); CancellationToken token = cancellationTokenSource.Token; Task task = Task.Run(() => { while (!token.IsCancellationRequested) { Console.Write("*"); Thread.Sleep(1000); } }, token); Console.WriteLine("Press enter to stop the task"); Console.ReadLine(); cancellationTokenSource.Cancel(); Console.WriteLine("Press enter to end the application"); Console.ReadLine(); }
| | #