2017年5月26日 星期五

C# WebAPI 與 Angular2 透過 Http.post 傳遞參數做資料新增

之前一篇 提到,透過 http.get 來進行資料的 Query,Query 參數主要是透過網址列來傳遞。
而為了符合 RESTful 架構風格,因此在新增資料時,我們使用的是 http.post


承接上一篇的例子,在這邊我們仍以 ValuesController.cs 作為例子
Step 1. 同樣的步驟,我們在必須先建一個類別來接收 http.post 傳遞過來的參數,這邊我們命名為 MyData
    public class MyData
    {
        public string fab { get; set; }
        public string shop { get; set; }
        public string date { get; set; }
        public string qty { get; set; }
    }

Step 2. 將 POST預設的 code 標註起來,因為傳遞的參數不是一的字串(string),而是剛剛建立的 MyData 類別。
Http.post 就是從Post Body 取得參數,前面加的是[FromBody]。function 裡的內容就是透過 SQL 語法去將資料存到資料庫裡。
        //// POST api/values
        //public void Post([FromBody]string value)
        //{
        //}
        // POST api/values
        public void Post([FromBody]MyData value)
        {
            Console.Write(value);
        }

前端 Angular2的部分也很簡單,幾乎只是將原本的 get 改成 post 再多傳遞一個變數"body"
Step 3. 我們在網頁上多加一個按鈕,讓這個按鈕觸發 save()
save(){
        let options = new RequestOptions();
        let headers = new Headers({ 'Content-Type': 'application/json',
        'Accept': 'q=0.8;application/json;q=0.9' });
        options.headers = headers;
        let body = {
                'fab': 'Fab01',
                'shop': 'Shop01',
                'date': '2017/05/26',
                'qty': 100
        }

        let url = '/api/values/';
        this._http.post(url,body, options)
                .subscribe(next => console.log('ok'));
}


如此,即完成 Http.post 的實作。
這裡可以透過 Chrome 瀏覽器,打開 F12 編輯視窗,選擇 Network 可以看到傳送出去的http body如下:
Request Payload:
{ "fab": "Fab01", "shop": "Shop01", "date": "2017/05/26", "qty": 100 }
另外也可以 Fiddler 來查看 

2017年4月25日 星期二

建立 C# WebAPI 與 Angular2 做 Http.get 溝通

因為這個部分是小太陽一開始學習 Angular2 首要想完成的地方,中間當然遇到了許多難關,一一的克服後,撰寫這篇文章希望對大家有所幫助!
本範例是前端網頁傳遞多個Query參數,到後端Web API 搜尋資料庫後,將 DataTable 回傳到前端的範例。

Step 1. 建立 C# Web API (vs2012)
1) 新增專案 >> Web >> ASP.NET MVC 4 WEB 應用程式
2) 範本選取 Web API

Web API專案完成建立後,會預設建立一個 ValuesController.cs,我們以此Controller 來進行範例。
Step 2. 因為要傳遞多個參數,所以會用一個類別將參數接起來,所以這邊會建一個 QueryParams 類別,用來接參數。
    public class QueryParams
    {
        public string fab { get; set; }
        public string shop { get; set; }
        public string date { get; set; }    //  YYYY/MM/DD - YYYY/MM/DD
    }

Step 3.  Http.get 是透過 URL 來傳遞參數,所以在接參數的前面加一個 [FromUri],如果是 Http.post 就是從Post Body 取得參數,前面加的是[FromBody]。本範例就不著墨在DBConnector上面了,小太陽用的是 Oracle.ManagedDataAccess。
        // GET api/values
        //public IEnumerable<string> Get()
        //{
        //    return new string[] { "value1", "value2" };
        //}
        public DataTable Get([FromUri]QueryParams queryParams)
        {
            DBConnector db = new DBConnector("MyDB");
            string strSQL = @"select '{0}', '{1}', '{2}' from dual";
            strSQL = string.Format(strSQL, queryParams.fab
                                         , queryParams.shop
                                         , queryParams.date);
            string errorStr = "";
            DataTable dt = db.selectSQL(strSQL, out errorStr);
            return dt;
        }

接下來是前端 Angular2的部分,假設你已經透過這篇建好專案了 ng2 建立新專案 
並且解決 Cross Domain問題 解決 ng2 的 Cross Domain 問題
Step 4. 那麼我們開始在 app.component.ts 來呼叫 Http.get 吧
import { Component, OnInit } from '@angular/core';
import {URLSearchParams,  Headers,   Http,   RequestOptions} from '@angular/http';
@Component({
  selector: 'app-root',
  templateUrl: `
  <h1>
  <pre>{{data|async|json}}</pre>
</h1>
  `,
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
  data: any;
  constructor(private http: Http){}
  ngOnInit(){
    let options = new RequestOptions();
    let headers = new Headers({ 'Content-Type': 'application/json',
                                     'Accept': 'q=0.8;application/json;q=0.9' });
    options.headers = headers;
    let params: URLSearchParams = new URLSearchParams();
    params.set('fab', 'myFab');
    params.set('shop', 'myShop');
    params.set('date', '2017/04/24');
    options.search = params;

    let url = '/api/values/';
    this.data = this.http.get(url,options).map(response => response.json());
  }
}


如果是使用 Chrome 瀏覽器,打開 F12 編輯視窗,選擇 Network 可以看到傳送出去的網址如下:
Request URL:
http://localhost:4200/api/values/?fab=myFab&shop=myShop&date=2017/04/24

這時候在Web API 中設中斷點就可以看到傳進來的參數。
而Angular2 的畫面也會將回傳回來的 DataTable轉為 json放到 data 變數裡,下面是最後網頁呈現的結果:
[
  {
    "'MYFAB'": "myFab",
    "'MYSHOP'": "myShop",
    "'2017/04/24'": "2017/04/24"
  }
]

2017年4月17日 星期一

利用 Moment.js 將日期轉換為字串

Step 1. 安裝 moment 套件
npm install moment

Step 2. 在 TypeScript 中 import moment 套件
import * as moment from 'moment';

Step 3. 將日期格做轉為字串語法如下
var mDate = moment();
var today = mDate.format("MM/DD/YYYY");   // 轉為 MM/DD/YYYY 字串格式
var day7 = mDate.add(7,'days').format("MM/DD/YYYY");     // 加7天

2017年4月5日 星期三

解決 ng2 的 Cross Domain 問題

當我們在開發環境使用 Angular2 要去後端 Web API 取資料時,出現以下錯誤
No 'Access-Control-Allow-Origin' header is present on the requested resource.

這是因為後端的 Web API 沒有支援 Cross Origin Resource Sharing (CORS)
這時,我們可以在Client端設定,透過 Proxy 轉發網址

Step 1. 於根目錄(與package.json同層) 建立 proxy.config.json 檔案,內容如下
(其中 KyleAPI 是Web API 的名稱,target 指的是 Visual Studio 執行後產生 IIS Express 的站台IP)
{
  "/KyleAPI": {
    "target": "http://localhost:47496",
    "secure": false
  }
}

Step 2. 修改package.json檔案,將npm 指令中的 start 加上proxy-config,並指向proxy.config.json 檔案
"start": "ng serve",
↓↓↓
"start": "ng serve --proxy-config proxy.config.json",

Step 3. 重新啟動 npm start,並在程式中的 url 只要改成下面這段即可
    //let url = 'http://localhost:47496/KyleAPI/api/values/';
    let url = '/KyleAPI/api/values/';
這時我們的 proxy 設定會自動將 /KyleAPI/api/values/ 網址轉為 http://localhost:47496/KyleAPI/api/values/


當你將開發的 Angular2 與 Web API 部署到 IIS 上之後,請把他們放在一起(詳見這一篇),這時候就不需要這個設定了

ng2 檔案資料夾介紹

開發 angular2 必須要有幾個關鍵的資料夾與檔案
a. 資料夾的部分
node_modules
Node.JS 的一些模組
e2e
End-to-end (E2E) Tests 測試用

b. app資料夾裡面
*.spec
Unit Tests 用的檔案
app.module.ts
用來註冊其他的 NgModule 到 root NgModule 裡面
main.ts
用來綁定 platform-browser-dynamic 與 NgModule

c. 檔案部分
package.json
定義有多少 npm 指令可以執行
protractor.config.js
e2e 測試用的config檔
systemjs.config.js
Mapping angular2 載入的模組

2017年4月4日 星期二

ng2 建立新專案

建立 Angular2 專案的步驟,在官網也有介紹。 https://angular.io/docs/ts/latest/cli-quickstart.html
這邊只是單存的紀錄一下自己的學習筆記

Step 1. 必須先安裝 node.js (小太陽裝的是node-v7.3.0-x86.msi 這個版本),安裝完畢即可使用 cmd 操作 npm 指令
查看版本
node -v
npm -v

Setp 2. 設定連外網的 Proxy (如果你的環境需要設定連外網的話)
npm config set proxy=http://192.168.xx.xxx:8080
檢查設定值
npm config list

Step 3. 透過 angular cli 安裝 Angular2 環境
npm install -g angular-cli

Step 4. 安裝完畢後,可以開始操作 ng 指令
查看 help
ng --help
建立一個 demo 專案
ng new 專案名稱
 (這個階段要有耐心點,等它跑完,因為小太陽跑到下面這段以為結束了... 強制關閉,結果就是專案Create失敗)
Installing packages for tooling via npm.
(看到下面這段才算建立專案完成)
Project '專案名稱' successfully created.

Step 5. 執行測試
cd 專案名稱
ng serve
開啟網頁輸入 http://127.0.0.1:4200,網頁出現 app works! 表示建立專案成功囉!

2017年3月23日 星期四

Web Service 傳遞自定物件

測試了一下,如何使用 Web Service 傳定自定的物件

1) Web Service 端
Step 1. 先自定一個物件,名叫 Hero,設定為可序列化類別
一定要加入 public Hero() { } 這行,不然會出現「無法序列化 XXX.Hero,因為它沒有參數建構函式。」的錯誤
    [Serializable]
    public class Hero
    {
        public int id { get; set; }
        public string name { get; set; }
        public Hero() { }
        public Hero(int id, string name)
        {
            this.id = id;
            this.name = name;
        }
    }

Step 2. 撰寫 Web Service 方法
        [WebMethod]
        public List<Hero> GetHeroes()
        {
            List<Hero> lstHero = new List<Hero>();
            lstHero .Add(new Hero(1, "Kyle"));
            lstHero .Add(new Hero(2, "Paul"));
            return lstHero ;
        }

2) Web Client 端
上面的 Web 參考名為 localhost,類別為 WebService1
用下面這兩段就可以將 Hero 物件接回去了
        localhost.WebService1 CallWebService = new localhost.WebService1();
        localhost.Hero[] heroes = CallWebService.GetHeroes();

後續也可以將 localhost.Hero[] 轉回為自定的物件 Hero
            List<Hero> lstHero = new List<Hero>();
            for (int i = 0; i < heroes.Length; i++)
            {
                lstHero.Add(new Hero(heroes[i].id, heroes[i].name));
            }