Google Code Prettify

[Web API]實用的開發範例 - 前端資料存取

這個範例我在撰寫時是有分為 Web API (REST web service) 及用戶端二大模塊,現在有很多的工程在前端 (用戶端) 的實作都是以 Javascript 這類的前端工程工具來製作,這些前端工具是有它的好處,至少在視覺上就能提高很多,但是;將它拿來向後端 (資料庫或Web服務) 拿資料,總覺得不太安全,由其是客戶的經營及生產方面的工程。


聲明:
1. 本範例屬中高階工程技術範疇,不適合初學者。
2. 學習本範例需要對 Web API 有基礎的概念。


以下的範例主要是示範前端 (C#) 向後端 Web API (REST web service) 拿資料,而我們會提供需權限認證及免權限認證二類的資料來源,而權限認證我們是以令牌 (Token) 的方式進行控管的。


修改 Web API 的控制器 (ValuesController.cs) :

\Controllers\ValuesController.cs
using System;
using System.Web.Http;

namespace LocalAccountsApp.Controllers
{
    [Authorize]
    public class ValuesController : ApiController
    {
        // GET api/values
        [AllowAnonymous]
        [HttpGet]
        [Route("api/GetValues")]
        public string GetValues()
        {
            return "嗨, 您來了.(http get)";
        }
        [HttpGet]
        [Route("api/GetAuthValues")]
        public string GetAuthValues()
        {
            var userName = this.RequestContext.Principal.Identity.Name;
            return String.Format("嗨, {0} 您來了.(http get)[by auth]", userName);
        }
        [AllowAnonymous]
        [HttpPost]
        [Route("api/PostValues")]
        public string PostValues()
        {
            return "嗨, 您來了.(http post)";
        }
        [HttpPost]
        [Route("api/PostAuthValues")]
        public string PostAuthValues()
        {
            var userName = this.RequestContext.Principal.Identity.Name;
            return String.Format("嗨, {0} 您來了.(http post)[by auth]", userName);
        }
    }
}



前端建立主控台應用程式專案,並修改 Program.cs :

\Program.cs
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;

using Newtonsoft.Json;

namespace HttpWebRequestGetTokenByPasswordExample
{
    public class MorseDataControl
    {
        MorseHttpWeb morseHttpWeb = new MorseHttpWeb();
        #region Get
        public string GetValues(string url)
        {
            return morseHttpWeb.GetHttpWeb(url);
        }
        public string GetAuthValues(string url, string accessToken)
        {
            return morseHttpWeb.GetHttpWeb(url, accessToken);
        }
        public async Task<string> GetValuesAsync(string url)
        {
            return await morseHttpWeb.GetHttpWebAsync(url);
        }
        public async Task<string> GetAuthValuesAsync(string url, string accessToken)
        {
            return await morseHttpWeb.GetHttpWebAsync(url, accessToken);
        }
        #endregion
        #region Post
        public string PostValues(string url, string query)
        {
            return morseHttpWeb.PostHttpWeb(url, query);
        }
        public async Task<string> PostValuesAsync(string url, string query)
        {
            return await morseHttpWeb.PostHttpWebAsync(url, query);
        }
        public string PostAuthValues(string url, string query, string accessToken)
        {
            return morseHttpWeb.PostHttpWeb(url, query, accessToken);
        }
        public async Task<string> PostAuthValuesAsync(string url, string query, string accessToken)
        {
            return await morseHttpWeb.PostHttpWebAsync(url, query, accessToken);
        }
        #endregion
    }
    public class MorseHttpWeb
    {
        /// <summary>
        /// 取得令牌
        /// </summary>
        /// <param name="url"></param>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <returns>令牌 (Token)</returns>
        public accessToken GetAccessToken(string url, string username, string password)
        {
            accessToken ret = new accessToken();
            WebRequest request = HttpWebRequest.Create(url);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";

            // 方法1:
            // NameValueCollection outgoingQueryString = HttpUtility.ParseQueryString(String.Empty);
            // outgoingQueryString.Add("grant_type", "password");
            // outgoingQueryString.Add("username", username);
            // outgoingQueryString.Add("password", password);
            // byte[] postBytes = new ASCIIEncoding().GetBytes(outgoingQueryString.ToString()); // 轉成 byte[]

            //方法2:
            string s = string.Format("username={0}&password={1}&grant_type=password", username, password);
            byte[] postBytes = new ASCIIEncoding().GetBytes(s); // 轉成 byte[]

            Stream postStream = request.GetRequestStream();//取得用以寫入要求資料的 Stream 物件。
            postStream.Write(postBytes, 0, postBytes.Length);
            postStream.Flush();
            postStream.Close();

            using(WebResponse response = request.GetResponse()) {
                using(StreamReader streamReader = new StreamReader(response.GetResponseStream())) {
                    ret = JsonConvert.DeserializeObject<accessToken>(streamReader.ReadToEnd().Replace(".", ""));
                }
            }
            return ret;
        }
        /// <summary>
        /// 取得令牌(非同步)
        /// </summary>
        /// <param name="url"></param>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <returns>令牌 (Token)</returns>
        public async Task<accessToken> GetAccessTokenAsync(string url, string username, string password)
        {
            accessToken ret = new accessToken();
            WebRequest request = HttpWebRequest.Create(url);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";

            // 方法1:
            // NameValueCollection outgoingQueryString = HttpUtility.ParseQueryString(String.Empty);
            // outgoingQueryString.Add("grant_type", "password");
            // outgoingQueryString.Add("username", username);
            // outgoingQueryString.Add("password", password);
            // byte[] postBytes = new ASCIIEncoding().GetBytes(outgoingQueryString.ToString()); // 轉成 byte[]

            //方法2:
            string s = string.Format("username={0}&password={1}&grant_type=password", username, password);
            byte[] postBytes = new ASCIIEncoding().GetBytes(s); // 轉成 byte[]

            Stream postStream = await request.GetRequestStreamAsync(); //傳回以非同步作業方式將資料寫入網際網路資源的 Stream
            postStream.Write(postBytes, 0, postBytes.Length);
            postStream.Flush();
            postStream.Close();

            using(WebResponse response = await request.GetResponseAsync()) {
                using(StreamReader streamReader = new StreamReader(response.GetResponseStream())) {
                    ret = JsonConvert.DeserializeObject<accessToken>((await streamReader.ReadToEndAsync()).Replace(".", ""));
                }
            }
            return ret;
        }
        /// <summary>
        /// HTTP GET Method Process
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="accessToken">令牌 (Token)</param>
        /// <returns></returns>
        public string GetHttpWeb(string uri, string accessToken = null)
        {
            string retVal = "";
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
            request.Method = "GET";
            if(accessToken != null)
                request.Headers.Add("Authorization", "Bearer " + accessToken);
            try {
                using(var response = request.GetResponse())
                    if(response != null) {
                        var reader = new StreamReader(response.GetResponseStream());
                        if(reader != null)
                            retVal = reader.ReadToEnd();
                    }
            }
            catch(Exception ex) {
                Console.WriteLine("Error: " + ex.ToString());
            }
            return retVal;
        }
        /// <summary>
        /// HTTP GET Method Process(非同步)
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="accessToken">令牌 (Token)</param>
        /// <returns></returns>
        public async Task<string> GetHttpWebAsync(string uri, string accessToken = null)
        {
            string retVal = "";
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
            request.Method = "GET";
            if(accessToken != null)
                request.Headers.Add("Authorization", "Bearer " + accessToken);
            try {
                using(var response = await request.GetResponseAsync())
                    if(response != null) {
                        var reader = new StreamReader(response.GetResponseStream());
                        if(reader != null)
                            retVal = await reader.ReadToEndAsync();
                    }
            }
            catch(Exception ex) {
                Console.WriteLine("Error: " + ex.ToString());
            }
            return retVal;
        }
        /// <summary>
        /// HTTP POST Method Process
        /// </summary>
        /// <param name="post_url"></param>
        /// <param name="post_query_string"></param>
        /// <returns></returns>
        public string PostHttpWeb(string post_url, string post_query_string, string accessToken = null)
        {
            var ret = "";
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(post_url);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            if(accessToken != null)
                request.Headers.Add("Authorization", "Bearer " + accessToken);
            try {
                using(var writer = new StreamWriter(request.GetRequestStream())) writer.Write(post_query_string);
                using(var response = request.GetResponse()) {
                    var reader = new StreamReader(response.GetResponseStream());
                    if(reader != null)
                        ret = reader.ReadToEnd();
                }
            }
            catch(Exception ex) {
                Console.WriteLine("Error: " + ex.ToString());
            }
            return ret;
        }
        /// <summary>
        /// HTTP POST Method Process(非同步)
        /// </summary>
        /// <param name="post_url"></param>
        /// <param name="post_query_string"></param>
        /// <param name="accessToken">令牌 (Token)</param>
        /// <returns></returns>
        public async Task<string> PostHttpWebAsync(string post_url, string post_query_string, string accessToken = null)
        {
            var ret = "";
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(post_url);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            if(accessToken != null)
                request.Headers.Add("Authorization", "Bearer " + accessToken);
            try {
                using(var writer = new StreamWriter(await request.GetRequestStreamAsync())) writer.Write(post_query_string);
                using(var response = await request.GetResponseAsync()) {
                    var reader = new StreamReader(response.GetResponseStream());
                    if(reader != null)
                        ret = await reader.ReadToEndAsync();
                }
            }
            catch(Exception ex) {
                Console.WriteLine("Error: " + ex.ToString());
            }
            return ret;
        }
    }
    public class MorseProcess
    {
        public MorseProcess()
        {
        }
        public async Task HttpWebTest() { 
            string userName = "xxxxxx@gmail.com";
            string userPassword = "xxxxxx";
            string urlString = "https://localhost:8087/token";

            Console.WriteLine((new MorseDataControl()).GetValues("https://localhost:8087/api/GetValues"));
            Console.WriteLine(await (new MorseDataControl()).GetValuesAsync("https://localhost:8087/api/GetValues"));
            Console.WriteLine((new MorseDataControl()).PostValues("https://localhost:8087/api/PostValues", ""));
            Console.WriteLine(await (new MorseDataControl()).PostValuesAsync("https://localhost:8087/api/PostValues", ""));

            accessToken t = (new MorseHttpWeb()).GetAccessToken(urlString, userName, userPassword); // 令牌
            accessToken tAsync = (new MorseHttpWeb()).GetAccessToken(urlString, userName, userPassword); // 令牌
            Console.WriteLine("Token 1: " + t.access_token);
            Console.WriteLine("Token 2: " + tAsync.access_token);

            Console.WriteLine((new MorseDataControl()).GetAuthValues("https://localhost:8087/api/GetAuthValues", t.access_token));
            Console.WriteLine(await (new MorseDataControl()).GetAuthValuesAsync("https://localhost:8087/api/GetAuthValues", t.access_token));
            Console.WriteLine((new MorseDataControl()).PostAuthValues("https://localhost:8087/api/PostAuthValues", "", t.access_token));
            Console.WriteLine(await (new MorseDataControl()).PostAuthValuesAsync("https://localhost:8087/api/PostAuthValues", "", t.access_token));
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            (new MorseProcess()).HttpWebTest().Wait();
            Console.Write("Press any key...");
            Console.ReadKey();
        }
    }
    public class accessToken
    {
        public dynamic access_token { get; set; }
        public string token_type { get; set; }
        public int expires_in { get; set; }
        public string userName { get; set; }
        public DateTime issued { get; set; }
        public DateTime expires { get; set; }
    }
}


執行結果: