0%

install-package T1.Standard

Instead of using exceptions extensively, we should use Either as a replacement.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public Result SayHello(string name)
{
if( name == "hack" ) {
throw new Exception("Bad Request");
}
return new Result
{
ErrorMessage = string.Empty
};
}

try {
return SayHello("xxxx");
} catch (Exception e1) {
return new Result {
ErrorMessage = e1.Message
};
}

This is a C# implementation of the “Either” type. The Either type is a functional programming concept that allows you to represent values that can be one of two types, “left” or “right”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public Either<Result, Exception> SayHello(string name)
{
if( name == "hack" ) {
return new Either<Result, Exception>(new Exception("Bad Request"));
}
return new Either<Result, Exception>(new Result
{
ErrorMessage = $"Hi {name}"
});
}

return SayHello("xxx").Match(
result => result,
ex => new Result {
ErrorMessage = string.Empty,
}
);

T1.SourceGenerator

We provide following features

  • Simple Auto Mapping Clone Object Function
  • Simple Auto Mapping any interface to WebApi Client Class

How do I get started ?

First, install T1.SourceGenerator nuget package.
Attach AutoMapping Attribute on any class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using T1.SourceGenerator.Attributes;
namespace MyDemoApp;

[AutoMapping(typeof(Employee))]
public class User
{
public string Name { get; set; }
public int Level { get; set; }
public int Vip { get; set; }
}

public class Employee
{
public string Name { get; set; }
public float Level { get; set; }
public int Vip { get; }
}

Then in your application code, execute the mappings:

1
2
var source = new User();
var dto = source.ToEmployee();

If you hope change ToEmployee() method to other extension method, you can do this:

1
2
3
4
5
6
7
[AutoMapping(typeof(Employee), "CloneToEmployee")]
public class User
{
public string Name { get; set; }
public int Level { get; set; }
public int Vip { get; set; }
}

Then in your application code, execute the mappings:

1
2
var source = new User();
var dto = source.CloneToEmployee();

How to get Auto Mapping WebApiClient class ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[WebApiClient(ClientClassName = "SamApiClient", Namespace = "ConsoleDemoApp")]
public interface IMyApiClient
{
[WebApiClientMethod("mgmt/test1", Method = InvokeMethod.Get, Timeout = "00:00:10")]
void Test(Request1 req);

[WebApiClientMethod("mgmt/test2", Timeout = "00:00:30")]
void Test2();

[WebApiClientMethod("mgmt/test3")]
Response1 Test3();

[WebApiClientMethod("mgmt/test4")]
Response1 Test4(int a);
}

Then in your application code, execute the code:

1
2
3
using T1.SourceGenerator;

var client = new SamApiClient(null);

If you prefer a different namespace (“ConsoleDemoApp”), you can custom it.

1
2
3
4
5
[WebApiClient(ClientClassName = "SamApiClient", Namespace = "ConsoleDemoApp")]
public interface IMyApiClient
{
...
}

If you need constructor injection, you can do it like in the following program example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[WebApiClient(ClientClassName = "SamApiClient", Namespace = "ConsoleDemoApp")]
[WebApiClientConstructorInject(MyConfig), "myConfig")]
public interface IMyApiClient
{
...
}

partial class SamApiClient
{
partial void Initialize()
{
BaseUrl = _myConfig.BaseUrl;
}
}

Even if you need to specify a variable using a special method for constructor injection, you can do it this way.

1
2
3
4
5
6
[WebApiClient(ClientClassName = "SamApiClient", Namespace = "ConsoleDemoApp")]
[WebApiClientConstructorInject(typeof(IOption<MyConfig>), "myConfig", AssignCode="myConfig.Value")]
public interface IMyApiClient
{
...
}

It will produce the following code.

1
2
3
4
5
6
7
8
public class SamApiClient
{
public SamApiClient(IHttpClientFactory httpClientFactory,
IOption<MyConfig> myConfig)
{
_myConfig = myConfig.Value;
}
}

T1.Standard.Extensions

Simple Parse Command Line Sample

1
2
3
4
5
6
7
8
9
10
11
12
var commandLine = @"1 2";

var args = commandLine
.ParseCommandArgsLine()
.ToArray();

var expected = new[]
{
"1",
"2"
};
expected.ToExpectedObject().ShouldEqual(args);

It can parse quote string command line

1
2
3
4
5
6
7
8
9
10
11
12
var commandLine = @"1 '2 3'";

var args = commandLine
.ParseCommandArgsLine()
.ToArray();

var expected = new[]
{
"1",
"'2 3'"
};
expected.ToExpectedObject().ShouldEqual(args);

parse line str to command args

1
2
3
4
5
6
7
8
9
10
11
12
var commandLine = @"1 2";

var args = commandLine
.ParseCommandArgsLine()
.ToArray();

var expected = new[]
{
"1",
"2"
};
expected.ToExpectedObject().ShouldEqual(args);

ParseCommandArgs will cut the string according to single or double quotation marks.

1
2
3
4
5
6
7
8
9
10
11
12
13
var commandLine = @"1 '2 3'";

var args = commandLine
.ParseCommandArgsLine()
.ToArray();

var expected = new[]
{
"1",
"'2 3'"
};

expected.ToExpectedObject().ShouldEqual(args);

T1.Standard.Linq.LinqToDataTableExtension

string/object Dictionary List to DataTable Sample

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var dictList = new List<Dictionary<string, object>> {
new Dictionary<string, object>
{
{"Id", 1},
{"Name", "Jack"},
{"Birth", DateTime.Parse("2022-05-01")}
},
new Dictionary<string, object>
{
{"Id", 2},
{"Name", "Flash"},
{"Birth", DateTime.Parse("2022-05-01")}
}
};

var datatable = dictList.ToDataTable();

string/object Dictionary List Deep to DataTable Sample

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var dictList = new List<Dictionary<string, object>> {
new Dictionary<string, object>
{
{"Id", 1},
{"Name", "Jack"},
{"Birth", DateTime.Parse("2022-05-01")},
{"Price", null},
},
new Dictionary<string, object>
{
{"Id", 2},
{"Name", "Flash"},
{"Birth", DateTime.Parse("2022-05-01")},
{"Price", 123m},
{"Home", null},
}
};

var datatable = dictList.DeepToDataTable();

Assert.Equal(typeof(decimal), dt.Columns["Price"]!.DataType);
Assert.Equal(typeof(string), dt.Columns["Home"]!.DataType);

T1.Standard.Collections.TreeBuilder

ReduceTree

Universal way to convert List of items to Tree, Build the tree as completely as possible

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var userList = new[]
{
new MyUser { Path = "", Name = "A1" },
new MyUser { Path = "", Name = "A2" },
new MyUser { Path = "demo", Name = "B1" }
};

var actual = _treeBuilder.ReduceTree(userList,
x => x.Path,
x => _treeBuilder.GetParentPath(x),
x => _treeBuilder.QueryParentPaths(x.Path)
).ToList();

var expected = new List<TreeBuilder.TreeItem<MyUser, string>>
{
new TreeBuilder.TreeItem<MyUser, string>()
{
Id = "",
ParentId = null,
Item = new MyUser {Path = "", Name = "A1"},
Children = new List<TreeBuilder.TreeItem<MyUser, string>>()
},
new TreeBuilder.TreeItem<MyUser, string>()
{
Id = "",
ParentId = null,
Item = new MyUser {Path = "", Name = "A2"},
Children = new List<TreeBuilder.TreeItem<MyUser, string>>()
},
new TreeBuilder.TreeItem<MyUser, string>()
{
Id = "demo",
ParentId = null,
Item = new MyUser {Path = "demo", Name = "B1"},
Children = new List<TreeBuilder.TreeItem<MyUser, string>>()
},
};

expected.ToExpectedObject().ShouldEqual(actual);

GenerateTree

This will only create a fully structured tree

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var userList = new[]
{
new MyUser {Path = "", Name = "A1"},
new MyUser {Path = "demo/name", Name = "C1"},
};

var actual = _treeBuilder.GenerateTree(userList,
x => x.Path,
x => _treeBuilder.GetParentPath(x.Path)
).ToList();

var expected = new List<TreeBuilder.TreeItem<MyUser, string>>
{
new TreeBuilder.TreeItem<MyUser, string>()
{
Id = "",
ParentId = null,
Item = new MyUser {Path = "", Name = "A1"},
Children = new List<TreeBuilder.TreeItem<MyUser, string>>()
},
};

expected.ToExpectedObject().ShouldEqual(actual);

dotnet add package T1.Standard

If you need strong type conversion

1
2
var dataTable = new DataTable();
IEnumerable<User> list = dataTable.Cast<User>();

You can also convert to ‘IEnumerable<object>’

1
2
var dataTable = new DataTable();
IEnumerable<object> list = dataTable.Cast(typeof(User));

1
2
3
4
5
Visual C++ ->
Visual C++ 2015
Common Windows Application Develop Tool ->
Tool (1.2) & Windows 10 SDK (10.0.10586)
Windows 10 SDK (10.0.10586)

Enter cmd.exe

1
2
3
4
5
6
$npm config set msvs_version 2015 --global

The above can avoid the following parameters for each installation
npm install [package name] --msvs_version=2015

$npm install electron-prebuilt --save

Each development new Electron App, first create folder C:\sample-app1, and cmd c:\sample-app1

1
2
3
4
5
6
7
sample-app1/
├── package.json
├── main.js
├── webpack.config.js
└── app/
├── mainWindow.html
└── mainWindow.jsx
  • Create package.json file
1
2
3
4
5
{
"name": "electron-example",
"version": "0.1.0",
"main": "main.js"
}

PS:If package.json Not specified main field,Electron default use index.js file.

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
'use strict';

const electron = require('electron');
// app: Control application lifecycle module
const app = electron.app;

// BrowserWindow: Create a native window module
const BrowserWindow = electron.BrowserWindow;

// Reserve a global object to avoid JavaScript object GC resulting window automatically closes
let mainWindow;

function createWindow () {
// Create browser window
mainWindow = new BrowserWindow({width: 800, height: 600});

// Load mainWindow.html for view
mainWindow.loadURL('file://' + __dirname + '/app/mainWindow.html');

// Open Developer Tools
mainWindow.webContents.openDevTools();

// When browser window closed,will send 'closed' signal,and run callback
mainWindow.on('closed', function() {
mainWindow = null;
});
}

// When Electron initialization is completed and begin establish the new window,
// will send 'ready' signal,and run callback
app.on('ready', createWindow);

// app quit
app.on('window-all-closed', function () {
// For OSX User platform, force user press Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
}
});

app.on('activate', function () {
// For OSX
if (mainWindow === null) {
createWindow();
}
});

app/mainWindow.html is show window view

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>My Electron-React app</title>
</head>
<body>
<div id="content">
Hello World!!
</div>
</body>
</html>

In sample-app1 Folder, install package

1
$npm install electron-prebuilt

Run

$ node_modules/.bin/electron .

Second parameter is: package.json Folder path

Run webpack to generate new app/built/mainWindow.js file

$ ./node_modules/.bin/webpack

Start Run

$ node_modules.bin\electron .

In order to facilitate future easy to use,we will put instructions into package.json ,

1
2
3
4
5
"scripts": {
"start": "./node_modules/.bin/electron ./",
"electron-rebuild": "./node_modules/.bin/electron-rebuild",
"webpack": "./node_modules/.bin/webpack"
}

After only need to run

$ npm run webpack && npm start

  • Download and installing Visual Studio Code
  • Download node.js

Open VS Code when you are ready and use Shift + Command + p to access the command panel.
Go ahead and type “install extensions”: and type

tslint

go to node.js cmd

npm install -g tslint

install VS code extensions

Wallaby.js


Create a new folder for your project and create a new package.json file:

1
2
3
$ mkdir ts-vscode-boilerplate
$ cd ts-vscode-boilerplate
$ npm init

We are now ready to install the third party dependencies:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
npm install  --save-dev browser-sync
npm install --save-dev browserify
npm install --save-dev chai
npm install --save-dev gulp
npm install --save-dev gulp-istanbul
npm install --save-dev gulp-mocha
npm install --save-dev gulp-sourcemaps
npm install --save-dev gulp-tslint
npm install --save-dev gulp-typescript
npm install --save-dev gulp-uglify
npm install --save-dev run-sequence
npm install --save-dev tslint
npm install --save-dev typescript
npm install --save-dev vinyl-buffer
npm install --save-dev vinyl-source-stream

Configuring your VS Code preferences
Click on 「Workspace Settings」. Two files should be displayed on screen:

install node.js
install python 2.x

1
npm config set msvs_version 2015 --global

It must avoid each installation, for example:

1
npm install [package name] --msvs_version=2015

install electron-prebuilt

1
npm install electron-prebuilt --save

our application file system:

1
2
3
4
5
6
7
your-app/
├── package.json
├── app.js
├── webpack.config.js
└── app/
├── main.html
└── main.jsx

run sample

1
./node_modules/.bin/electron .

you can pack your application

1
npm i electron-packager

modify package.json file

1
2
3
4
"scripts": {
"start": "electron .",
"build": "electron-packager . MyFirstApp --ignore=node_modules/electron-* --platform=win32 --arch=x64 --version=0.32.3"
}

and run

npm run build

and use asar

npm i asar

modify package.json file

1
2
3
4
5
"scripts": {
"start": "electron .",
"build": "electron-packager . MyFirstApp --ignore=node_modules/electron-* --platform=win32 --arch=x64 --version=0.32.3",
"package": "asar pack MyFirstApp-win32-x64/resources/app MyFirstApp-win32-x64/resources/app.asar && rm -rf MyFirstApp-win32-x64/resources/app"
}

run package

npm run package

install webpack

1
2
npm install webpack --save
npm insall webpack-target-electron-renderer --save