http://docs.asp.net/en/latest/security/authorization/simple.html 這裡描述怎麼設定頁面授權的方式,可是卻都沒有提到如果說沒授權的人要頁面轉至登入畫面的方式

經過網頁上的查詢及測試後. 在1.0.0-rc1-update1的版本裡,設定方式如下

  1. startup.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication();
.....
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCookieAuthentication(options =>
{
options.LoginPath = "/Home/Login";
options.AutomaticAuthenticate = true;
options.AutomaticChallenge = true;
});
....
}

到這裡為止就可以做出跟以前一樣遇到沒有授權的頁面就轉到登入畫面了

###參數說明

重點在於AutomaticAuthenticate 及 AutomaticChallenge 這兩個參數 他的說明如下:

  1. AutomaticAuthenticate: If true the authentication middlleware alter the request user coming in. If false the authentication middleware will only provide identity when explicitly indicated by the AuthenticationScheme.
  2. AutomaticChallenge: If true the authentication middleware should handle automatic challenge. If false the authentication middleware will only alter responses when explicitly indicated by the AuthenticationScheme.

這裡出現另外一個參數 AuthenticationScheme AuthenticationScheme: The AuthenticationScheme in the options corresponds to the logical name for a particular authentication scheme. A different value may be assigned in order to use the same authentication middleware type more than once in a pipepline.

這表示在Controller裡的[Authorize]可以指定AuthenticationScheme, 就可以做出很有彈性的權限設定轉址或是其他後續動作了

1
2
[Authorize(ActiveAuthenticationSchemes ="abc")]
public IActionResult Index(){}

##update 設定頁面授權的方式在這裡 http://docs.asp.net/en/latest/security/authentication/cookie.html

Reference

ASP.NET 5/MVC 6 自訂使用Claim驗証

之前沒有特別留意ngOptions在1.4版裡面修正了一些東西,包含track by的用法 先簡單的描述一下狀況

1
2
3
4
5
6
7
8
9
10
11
12
13
$scope.options = [
{id:1,display:"1"},
{id:2,display:"2"},
{id:3,display:"3"},
{id:4,display:"4"},
{id:5,display:"5"}
] ;

$scope.selected = 3;

// html
<select ng-options="m.id as m.display for m in options"
ng-model="selected"></select>

這種寫法應該算是很常見的用法

但是這樣子的寫法經過1.4版處理後, 仔細去看他的html會變成

1
2
3
4
5
6
7
<select ng-options="m.id as m.display for m in options" ng-model="selected">
<option label="1" value="number:1">1</option>
<option label="2" value="number:2">2</option>
<option label="3" value="number:3" selected="selected">3</option>
<option label="4" value="number:4">4</option>
<option label="5" value="number:5">5</option>
</select>

竟然多了型別…>"<, 這表示如果我的$scope.selected = '3’時,就會選不到東西了

好吧,那如果用track by呢

1
2
<select ng-options="m.id as m.display for m in options track by m.id" 
ng-model="selected"></select>

DOM

1
2
3
4
5
6
7
8
<select ng-options="m.id as m.display for m in options track by m.id" ng-model="selected">
<option value="?" selected="selected"></option>
<option label="1" value="1">1</option>
<option label="2" value="2">2</option>
<option label="3" value="3">3</option>
<option label="4" value="4">4</option>
<option label="5" value="5">5</option>
</select>

這樣子看起來正常多了,但是$scope.selected的值不管是使用 3 or 「3」 都選不到東西. 只有給他options裡面的某一個object他才會被選定。 所以看起來track by是用 for m的m當作選定的值,那 select as label不就沒用了,沒用就拿掉他

1
2
<select ng-options="m.display for m in options track by m.id" 
ng-model="selected"></select>

DOM

1
2
3
4
5
6
7
8
<select ng-options="m.id as m.display for m in options track by m.id" ng-model="selected">
<option value="?" selected="selected"></option>
<option label="1" value="1">1</option>
<option label="2" value="2">2</option>
<option label="3" value="3">3</option>
<option label="4" value="4">4</option>
<option label="5" value="5">5</option>
</select>

看起來都一樣了

結論 用track by: select裡的ng-model會是以object的型態呈現, 不需要再寫select as xxxx了. 不用track by: 就看所表示的select是怎樣的型態,ng-model就是怎樣的型態,但是多了型別的判斷

Classes

Class的組成元素:

  1. Constructor

  2. Prototype methods:

  3. Static methods: 不需要New class就可以使用, 類似C#的Static

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}

get area() {
return this.calcArea()
}

calcArea() {
return this.height * this.width;
}

static distance(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;

return Math.sqrt(dx*dx + dy*dy);
}

}

Hoisting: Class並沒有Hoisting特性,所以需要先定義才可以使用,這點須注意

Class inheritance

Class也可以有繼承的性質 範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Animal { 
constructor(name) {
this.name = name;
}

speak() {
console.log(this.name + ' makes a noise.');
}
}

class Dog extends Animal {
speak() {
console.log(this.name + ' barks.');
}
}

Super的用法

Super用來呼叫Parent的function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Cat { 
constructor(name) {
this.name = name;
}

speak() {
console.log(this.name + ' makes a noise.');
}
}

class Lion extends Cat {
speak() {
super.speak(); // <= this call Cat's speak function
console.log(this.name + ' roars.');
}
}

Default args

可以將在function的參數給予預設值

1
2
3
function fnWithDefaultArg(a,b=[]){
// some codes
}

Spread operator

The spread operator allows an expression to be expanded in places where multiple arguments (for function calls) or multiple elements (for array literals) are expected.

1
2
3
4
5
function fn(a,b,c){
// some codes
}
var args = [1,2,3];
fn(...args); <= spread operator

A more powerful array literal

1
2
var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes']; // ["head", "shoulders", "knees", "and", "toes"]

A better push

1
2
3
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1.push(...arr2);

現在SPA的網站越來越盛行,下載檔案的功能在ajax下是有點麻煩,但是感謝HTML5下的Blob功能。網路上就有相對應的js功能出來 所以,引用這位大大的程式 (https://github.com/eligrey/FileSaver.js),其相關限制都有在該專案上描述

所以使用方法如下 (Client端)

1
2
3
4
5
6
7
8
9
10
$http.post('api url', query, { responseType: 'arraybuffer' }).then(function (response) {        
var filename = (filename);
var expectedMediaType = (file-Content-Type);
openSaveAsDialog(filename, response.data, expectedMediaType);
});

function openSaveAsDialog(filename, content, mediaType) {
var blob = new Blob([content], { type: mediaType });
saveAs(blob, filename);
}

重點 : responseType 要設定為 arraybuffer

(Server端) Webapi要回傳的httpresponseMessage內容如下, 不好意思程式碼是VB, 因為這個專案是用VB開發的,但是基本觀念的一樣的

1
2
3
4
5
6
7
8
9
10
Dim response As HttpResponseMessage = New HttpResponseMessage()
' _ms 是 MemoryStream, 這裡是因為要將NPOI所產生的excel檔做下載, 然而我將NPOI所產生出來的東西
' 存入到 MemoryStream裡, 重點是ByteArrayContent
Dim _filename as string = (filename)
If _ms IsNot Nothing Then
response.Content = New ByteArrayContent(_ms.ToArray())
End If
response.Content.Headers.ContentType = New Headers.MediaTypeHeaderValue("application/octet-stream")
response.Content.Headers.ContentDisposition = New Headers.ContentDispositionHeaderValue("attachment") With {.FileName = HttpUtility.UrlPathEncode(_filename)}
Return Task.FromResult(response)

以上的動作就可以讓ajax的call直接做下載檔案的動作,就不用另外產生一個form然後做post到新視窗後再下載了 ^^

Destructuring

可以將值從陣列或是物件裡取出並設定到變數上

syntax

1
2
3
[a, b] = [1, 2]
[a, b, ...rest] = [1, 2, 3, 4, 5]
{a, b} = {a:1, b:2}

Destructuring arrays

1
2
3
4
5
6
7
8
9
var foo = ["one", "two", "three"];

// without destructuring
var one = foo[0];
var two = foo[1];
var three = foo[2];

// with destructuring
var [one, two, three] = foo;

其他用法 1.Multiple-value returns

1
2
3
4
5
6
function f() {
return [1, 2];
}
var a, b;
[a, b] = f();
console.log("A is " + a + " B is " + b);

2.Ignoring some returned values

1
2
3
4
5
6
7
function f() {
return [1, 2, 3];
}
var a, b;
[a, ,b] = f();
console.log("A is " + a + " B is " + b);
// A is 1 B is 3

3.衍伸用法: Pulling values from a regular expression match

1
2
3
4
5
6
var url = "https://developer.mozilla.org/en-US/Web/JavaScript";

var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
var [, protocol, fullhost, fullpath] = parsedURL;

console.log(protocol); // logs "https"

Destructuring objects

1
2
3
4
5
var o = {p: 42, q: true};
var {p, q} = o;

console.log(p); // 42
console.log(q); // true

另外一種用法, 將物件裡的值設定到新的變數名稱上

1
2
3
4
5
6
7
8
9
// syntax
// {object.propertyName: VariableName} = object

// Assign new variable names
var o = {p: 42, q: true};
var {p: foo, q: bar} = o;

console.log(foo); // 42
console.log(bar); // true

衍生用法: Function argument defaults

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var [missing = true] = [];
console.log(missing);
// true

var { message: msg = "Something went wrong" } = {};
console.log(msg);
// "Something went wrong"

var { x = 3 } = {};
console.log(x);
// 3

function removeBreakpoint({ url, line, column }={}) {
// ...
}
1
2
3
4
5
6
7
8
9
10
function drawES6Chart({size = 'big', cords = { x: 0, y: 0 }, radius = 25} = {}) 
{
console.log(size, cords, radius);
// do some chart drawing
}

drawES6Chart({
cords: { x: 18, y: 30 },
radius: 30
});

另外一種情境 Module (non-ES6) loading

1
const { Loader, main } = require('toolkit/loader');

REF: Several demos and usages for ES6 destructuring.

懶得再去微軟的網站找了,所以在此備註

CTRL+SHIFT+G 在交談中切換重要屬性 CTRL+D, DEL 刪除交談 退格鍵 封存交談 CTRL+Q 標示為已讀取 CTRL+U 標示為未讀取 CTRL+R 回覆目前郵件 CTRL+SHIFT+R 全部回覆 CTRL+F 轉寄目前郵件 CTRL+E,F3 搜尋 Alt+C 接受會議邀請 Alt+D 拒絕會議邀請 Alt+N 暫訂會議邀請 CTRL+N 建立新的電子郵件 CTRL+SHIFT+M 建立新的電子郵件 CTRL+SHIFT+V 移到檢視 CTRL+1 切換至 [郵件] CTRL+2 切換至 [行事曆] CTRL+SHIFT+I 切換至 [收件匣] CTRL+SHIFT+O 切換至 [寄件匣]

ALT+I 新增附件 CTRL+M 手動同步帳戶 F9 手動同步帳戶 CTRL+ + 放大 CTRL+ - 縮小 ALT+S 傳送郵件 Ctrl + Enter 傳送郵件 F6 在區域間移動 F7 切換鍵盤瀏覽

在ES2015裡面,幾個比較大的改變Part1

Arrow Function

人真的可以在懶惰一點,為了不要寫__function__這幾個字,就有 ()=>{} 的出現。這就是Arror Function 跟Lambda的表示法很像, 真的用法也是跟那個一樣

1
2
3
4
5
6
7
8
9
10
11
12
// Old
var old = function(n) {
return n * n;
};

// with Arror Functions express 1
let new_1 = (n) => n * n;

// with arror function express 2
let new_2 = (n) => {
return n * n;
};

另外一個要注意的是Arrow Scope的問題,

1
2
3
4
5
6
7
8
9
10
11
12
var hendrik = {
this.name = "Hendrik";

sayHello: (names) => {
names.forEach((name)=>{
console.log(`${this.name} greets ${name}`);
});
}
}
hendrik.sayHello(['frikkie']);
// output
// hendrik greets frikkie

String templates

最快樂的事情非屬這個, 文字串的組合可以用 ` (鍵盤左上角流水符號的那個鍵), 可以讓你多行編輯文字字串 在配合 ${變數} 來將變數顯示在文字裡面。 這樣子就不用一堆的 『加號』 來串文字了,超快樂的

1
2
3
4
5
6
7
8
9
10
11
// old
function sayHello(name, surname){
console.log('hello there ' + name + ' ' + surname + ', the time is now ' + new Date());
}

// new way
function sayHello_new(name, surname){
console.log(`hello there ${name} ${surname},
the time is now ${new Date()}`);
}

FYI: 新版的C#/VB.net也有將此功能加入,已經可以不用string.format + 無數的{流水號}了

Let

非常重要 要將使用var來定義變數的改用let來定義變數, 這樣子就可以避免同樣名稱的變數在不同的scope被覆蓋的情形發生

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
//=== old ===
var
name = 'Fido',
breed = 'schnauzer',
owners = ['Hendrik', 'Alice']
;

console.log(name + '(' + breed + '):');

for(var i = 0; i < owners.length; i++){
var name = owners[i];

console.log('Owner ' + name);
}

console.log(name);
//output
// Fido(schnauzer):
// Owner Hendrik
// Owner Alice
// Alice (被改變掉了)

//=== new ===
let fname = 'Fido',
breed = 'schnauzer',
owners = ['Hendrik', 'Alice']
;

console.log(`${fname} (${breed}):`);

for(let i = 0; i < owners.length; i++){
let fname = owners[i];
console.log(`Owner ${fname}`);
}

console.log(fname);
// output:
// Fido (schnauzer):
// Owner Hendrik
// Owner Alice
// Fido

const

常數,當變數一旦被指定為const時,就不可以被改變了

1
2
3
4
const pi = Math.PI;

pi = 123;
// this will cause error message

準備練習環境

  1. VSCode
  2. Gulp
  3. browersync
  4. Typescript

設定項目

  1. tsconfig.json
1
2
3
4
5
6
7
8
9
{
"compilerOptions": {
"target": "ES5",
"module": "amd",
"sourceMap": false,
"watch": true,
"outDir": "public/"
}
}
  1. tasks.json
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"version": "0.1.0",
"command": "gulp",
"isShellCommand": true,
"tasks": [
{
"taskName": "watch",
"isBuildCommand": true,
"showOutput": "silent",
"problemMatcher": "$tsc"
}
]
}
  1. gulpfile.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
var gulp = require('gulp'),
browserSync = require('browser-sync').create(),
typescript = require('gulp-tsc');

gulp.task('browser-sync',function(){
browserSync.init({
server:{
baseDir:"./"
}
})
})

gulp.task('compile',function(){
gulp.src(['src/**/*.ts'])
.pipe(typescript())
.pipe(gulp.dest('public/'))
.pipe(browserSync.reload({stream:true}));
});

gulp.task('watch',['browser-sync'],function(){
gulp.watch(['src/**/*.ts'],['compile']);
});

gulp.task('default',['watch']);

gulpfile會做兩件事情

  1. 當ts檔案有異動的時候做Compile並輸出到public的資料夾下
  2. 透過browsersync更新瀏覽器

這樣子就可以專心來練習javascript了

###ReportViewer的遠端報表的設定方式

  1. 如果需要設定登入使用者的權限時, 需要實作IReportServerCredentials, 但是如果需要就抄下面的Code 用法:
1
ReportViewer1.ServerReport.ReportServerCredentials = New CustomReportCredentials(username, password, domain)
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
Imports System.Net
Public Class CustomReportCredentials
Implements Microsoft.Reporting.WebForms.IReportServerCredentials

' local variable for network credential
Private strUserName As String
Private strPassWord As String
Private strDomainName As String
Public Sub New(ByVal UserName As String, ByVal PassWord As String, ByVal DomainName As String)
strUserName = UserName
strPassWord = PassWord
strDomainName = DomainName
End Sub
Public ReadOnly Property ImpersonationUser() As System.Security.Principal.WindowsIdentity Implements Microsoft.Reporting.WebForms.IReportServerCredentials.ImpersonationUser
Get
' not use ImpersonationUser
Return Nothing
End Get
End Property
Public ReadOnly Property NetworkCredentials() As System.Net.ICredentials Implements Microsoft.Reporting.WebForms.IReportServerCredentials.NetworkCredentials
Get
' use NetworkCredentials
Return New NetworkCredential(strUserName, strPassWord, strDomainName)
End Get
End Property
Public Function GetFormsCredentials(ByRef authCookie As System.Net.Cookie, ByRef userName As String, ByRef password As String, ByRef authority As String) As Boolean Implements Microsoft.Reporting.WebForms.IReportServerCredentials.GetFormsCredentials
' not use FormsCredentials unless you have implements a custom autentication.
authCookie = Nothing
password = authority = Nothing
Return False
End Function
End Class
  1. ServerReportUrl要指定SSRS的Report Server URL, 而不是Report Manager URL。因為這個URL的錯誤,讓我一直遇到404的錯誤. ex: http://serverIP/ReportServer

  2. ReportPath就是根據Root的相對應位置而設定,不需要.rdlc(localReport就需要搭配附檔名)

  3. 如果有參數要設定, 使用方式如下

1
2
3
Dim objParms As New System.Collections.ObjectModel.Collection(Of ReportParameter)
objParms.Add(New ReportParameter("param1", "param1 value"))
ReportViewer1.ServerReport.SetParameters(objParms)