Design

Design
asp.net mvc

2019年1月30日 星期三

C#基礎 關於float、double、decimal 浮點計算精度問題

C#中關於浮點計算 float、double、decimal  有這三中 實數型可以使用
但是我們都知道使用float、double會有小數點計算不準確的情況
特別是跟錢有關係的最好都使用高精準度decimal,知所以會叫高精準度就代表也有精度損失的時候,不過跟比float、double算是商業上夠用了等等下面會舉個例子

我們先來看小數點計算精度損失的例子
可以發現我們float、double計算都出現精度損失的問題這種問題如果不理會
後續會造成很大的嚴重後果 所以最好都使用decimal



當然我剛有提到decimal雖然擁有高精度但是就代表也會有精度損失的問題下面就舉個例子
可以看到我們的結果不是我們要的10000000000000000000000000000.1
不過這是比較極端的例子 正常也不會到這麼大的位數



再來我們再進行比對時資料結構一些問題 往往會需要先toString()在進行比對
可以發現我們float、double都是 true 原因是轉為字串float、double會自動把小數點後的零去除
但是卻發現decimal是false  原因是轉為字串 小數點後的零被保存下來
這時我們需要去除小數點後的零  stackoverflow 上的大神 有一招很酷的方法
就是我們的decimal 除掉 1.000000000000000000000000000000000
就會神奇發現我們小數點後的零都不見了 這時我們就可以擴充成方法作為使用  在進行比對我們就可以解決上述的問題



以上是C# 浮點精度 需要注意的事項  還是乖乖用decimal吧  雖然這是small tips不過還是開發時不可不注意的東西,以下是程式碼



namespace 練習
{
    class Program
    {
        static void Main(string[] args)
        {

            //float
            float f = 1.1f;
            f += 1.1f;

            //double
            double d = 1.1d;
            d += 1.1d;

            //decimal
            decimal de = 1.1m;
            de += 1.1m;

            Console.WriteLine("{0:G50}", f);
            Console.WriteLine("{0:G50}", d);
            Console.WriteLine("{0:G50}", de);


            //decimal 精度損失的例子
            decimal dd = 10000000000000000000000000000m;
            dd += 0.1m;
            Console.WriteLine("{0:G50}", dd);

            //float 比對
            float f1 = 1.1f;
            float f2 = 1.100f;
            Console.WriteLine(f1.ToString() == f2.ToString());

            //decimal 比對
            double d1 = 1.1d;
            double d2 = 1.100d;
            Console.WriteLine(d1.ToString() == d2.ToString());

            //decimal 比對
            decimal de1 = 1.1m;
            decimal de2 = 1.100m;
            Console.WriteLine(de1.ToString() == de2.ToString());

            decimal Money1 = 1.1m;
            decimal Money2 = 1.100m;

            //去除小數點後的零 方便作比對用
            Console.WriteLine(Money1.Streamline().ToString() == Money2.Streamline().ToString());


            Console.Read();
        }

    }


    
}

namespace CustomExtensions
{
    public static class Extension
    {
        public static decimal Streamline(this decimal d)
        {
            return d / 1.000000000000000000000000000000000m;
        }
    }
}

2018年11月21日 星期三

NativeScript 心得

最近想寫練習android & ios手機原生 NativeScript 現在剛好有支援angular 跟 vue 我是選擇vue來做開發 angular 我也有看一下 也是大同小異  ,  我自己在環境上花了不少時間 遇到不少坑  整體開發還可以看的出來Nativescirpt 還有需要改進很多地方 , 因為手邊沒有mac所以先選擇android先做練習 ,
主要是要熟練native的布局例如gridlayout .stacklayout .等等  還有native的structure整體什麼東西做什麼事情,部分的地方還是要靠native去撰寫 ,最好的話看一下原生java是怎寫的,  其他就如寫vue javascirpt typescript css部分支援 比較不一樣的就是router 改用 manual routing 不過這也沒什麼問題  ,官方的document都寫得滿清楚的 也有Demo參考 ,我覺得如果原本就熟練vue的話 邊學邊開發是完全沒問題 ,我覺得最大的好處是  我寫一版就能支援android跟ios系統 ,   不過還是要注意部分語法還是要寫android跟ios差異判斷,還支援Hot Reload 整理開發速度會快非常多 目前已經快寫完 簡單的youtube播放器 支援編輯自己的音樂清單 跟背景播放功能
到時候可能會上google play. 也不一定會上, 算是在學得新技能方面 解鎖成就(1/1) 



2018年10月30日 星期二

在winform內鑲Selenium控制

最近研究出可以在winform內鑲瀏覽器用Selenium控制的方法,這樣就不用每次導出視窗 造成一些問題 也比較美觀,主要方法是透過CefSharp內核把chrome鑲入winform,ChromiumWebBrowser的RemoteDebuggingPort建立個本個遠端路徑,再透過 Selenium ChromeOptions的DebuggerAddress 去做畫面的顯示

程式碼如下
 public partial class Form1 : Form
    {
        private readonly ChromiumWebBrowser browser;
        private static readonly bool DebuggingSubProcess = Debugger.IsAttached;

        private ISelenium selenium;
        private StringBuilder verificationErrors;

        public Form1()
        {
            InitializeComponent();

            var settings = new CefSettings();
            settings.RemoteDebuggingPort = 8088;
            settings.IgnoreCertificateErrors = true;
            Cef.Initialize(settings);
            browser = new ChromiumWebBrowser(url)
            {
                Dock = DockStyle.Fill,
            };
            browser.CreateControl();
            this.Controls.Add(browser);
        }

        public static void GO()
        {
            var driverService = ChromeDriverService.CreateDefaultService();
            driverService.HideCommandPromptWindow = true;

            ChromeOptions options = new ChromeOptions();
            options.DebuggerAddress = "127.0.0.1:8088";
            options.AddArguments("--enable-logging");
            using (var driver = new ChromeDriver(driverService, options))
            {
               //doSomething
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            GO();
        }
    }

2018年10月16日 星期二

Cassandra 自己winform寫了個GUI

待補充
內容 最近因為有工作上 有大量log紀錄的需求 原本是有使用mongodb,redis 這兩種nosql 就試看看新的Cassandra query語法不是那麼有善 , 網路上能用的GUI好像都要收費 因為語法相對簡單我這邊就自己用 winform寫了個GUI 方便查詢 有需要再聯繫我



2018年10月2日 星期二

簡易 HttpClient Post泛型請求

簡易 HttpClient Post泛型請求
我們使用httpclient get or post
常常會想要紀錄log或是回傳exceptional或是做一些事情
發現一直在寫重複的東西 如果我們寫個泛型的靜態方法是不是就乾淨多了




class Program
   {
       static void Main(string[] args)
       {
 
           string url = "http://jsonplaceholder.typicode.com/posts";
           var data = new PostModel();
           data.title = "foo";
           data.body = "bar";
           data.userId = 1;
           var c = HttpClient<PostModelResultModel>(url, data);           
           Console.WriteLine(JsonConvert.SerializeObject(c));
           Console.Read();
 
       }
 
       /// <summary>
       /// 如果沒有post參數的話
       /// </summary>
       /// <typeparam name="TResult"></typeparam>
       /// <param name="url"></param>
       /// <returns></returns>
       protected static TResult HttpClient<TResult>(string url) where TResult : class
       {
           return HttpClient<stringTResult>(url, string.Empty);
       }
 
 
       protected static TResult HttpClient<TPostTResult>(string url, TPost PostData) where TResult : class where TPost : class
       {
 
           var client = new HttpClient();
 
           var task = client.PostAsJsonAsync(url, PostData);
   
           //10秒timeout
           var hasimeOut = task.Wait(10000);
           if (!hasimeOut)
           {
               Console.WriteLine("timeout了");
               Console.Read();
           }
           var response = task.Result;
 
           var jsonString = response.Content.ReadAsStringAsync();
      
           var settings = new JsonSerializerSettings
           {
               NullValueHandling = NullValueHandling.Ignore,
             
           };
 
           //反序列
           var Result = JsonConvert.DeserializeObject<TResult>(jsonString.Result);
 
           return Result;
       }
 
 
 
 
       public class ResponseBase<TResult> {
 
           [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
           public int Code { getset; }
           [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
           public string message { getset; }
           [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
           public TResult data { getset; }
 
       } 
 
 
 
       public class PostModel
       {
           public string title { getset; }
           public string body { getset; }
           public int userId { getset; }
       }
 
 
       public class ResultModel
       {
           public string title { getset; }
           public string body { getset; }
           public int userId { getset; }
           [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
           public string test { getset; }
       }
 
   }

2018年9月19日 星期三

Selenium C# 簡單運用

Selenium 是為瀏覽器自動化(Browser Automation)需求所設計的一套工具集合,讓程式可以直接驅動瀏覽器進行各種網站操作。
應用的範圍滿廣泛的,除了自動化測試以外還可以當做爬蟲使用.
請NuGet 以下兩項
Selenium.Support
Selenium.WebDriver

底下簡單做個google搜訊範例 很直覺的啟動driver導頁到google 找search元件 輸入Submit 整體來說沒什麼難度 較進階的用法 會需要用到等待頁面加載完或是一些瀏覽器的問題跟操作 基本上大同小異

    using (var driver = new ChromeDriver())
            {
                driver.Navigate().GoToUrl("https://www.google.com.tw/");
                var search = driver.FindElementById("lst-ib");
                search.SendKeys("hi");
                search.Submit();
            }


我自己寫滿多的東西的,覺得目前來說各方面支援度都很夠用 推薦

2018年6月25日 星期一

懶得用DB 那就建個.json資料 來webapi CRUD吧

有時候懶得搞DB 這時候我們就可以本地建個JSON檔或是XML檔來當做資料庫
當然我不推崇這種方法 因為這會有很多問題 一方面效能 一方面資安 等等各種問題

那至於該怎做呢 方便我們前端呼叫做存取 這邊用webapi 當作範例
這邊依照飲料做為範例 先定義我們的Model格式吧





public class Type
    {
        public string Size { get; set; }
        public int Price { get; set; }
    }

    public class Drink
    {
        public int Drinkid { get; set; }
        public string DrinkName { get; set; }
        public List type { get; set; }
        public string Remarks { get; set; }
    }

    public class Blend
    {
        public string blendName { get; set; }
        public int Price { get; set; }
    }

    public class StoreModel
    {
        public int id { get; set; }
        public string StoreName { get; set; }
        public string Url { get; set; }
        public List Drink { get; set; }
        public List blend { get; set; }
        public string StoreRemarks { get; set; }
    }

再來就是簡單的CRUD 這邊自行看看吧 這邊都是邏輯都很簡單都是一照我們ID去找我們的資料再來重新復寫我們的資料

 public class StoreController : ApiController
    {

        [AllowAnonymous]
        [HttpPost]
        public List GetStore()
        {
            var mappedPath = System.Web.Hosting.HostingEnvironment.MapPath("~/Store/Store.json");

            return JsonConvert.DeserializeObject>(File.ReadAllText(mappedPath));

        }

        [AllowAnonymous]
        [HttpPost]
        public StoreModel GetStorebyID(int id)
        {
            var mappedPath = System.Web.Hosting.HostingEnvironment.MapPath("~/Store/Store.json");
            using (StreamReader r = new StreamReader(mappedPath))
            {
                string json = r.ReadToEnd();
                return JsonConvert.DeserializeObject>(json).Find(x => x.id == id);
            }
        }


        [AllowAnonymous]
        [HttpPost]
        public bool DeleteById(int id)
        {
            try
            {
                var mappedPath = System.Web.Hosting.HostingEnvironment.MapPath("~/Store/Store.json");
                var json = JsonConvert.DeserializeObject>(File.ReadAllText(mappedPath)).Find(x => x.id != id);
                var list = new List();
                list.Add(json);
                File.WriteAllText(mappedPath, JsonConvert.SerializeObject(list));
                return true;
            }
            catch (Exception e)
            {
                return false;
            }
        }

        [AllowAnonymous]
        [HttpPost]
        public bool Add(StoreModel StoreModel)
        {
            try
            {
                var mappedPath = System.Web.Hosting.HostingEnvironment.MapPath("~/Store/Store.json");
                var json = JsonConvert.DeserializeObject>(File.ReadAllText(mappedPath));
                json.Add(StoreModel);
                File.WriteAllText(mappedPath, JsonConvert.SerializeObject(json));
                return true;
            }
            catch (Exception e)
            {
                return false;
            }
        }

    }

這邊就簡單做個紀錄

2018年6月23日 星期六

vscode 起手vue cli

最近剛有新筆電 開始想寫些side project 經過一陣子的磨練發現自己寫工具的能力大大提升
心想那何不增加自己的github stat,剛好把這些過程稍微紀錄一下生篇文章給需要的人
vscode 算現在最潮的editor, vue 也從library漸漸發展成framework 那就開始吧

首先先安裝vscode吧
https://code.visualstudio.com/

再來安裝我們的nodejs
https://nodejs.org/en/
左邊LTS算是穩定版  右邊算是現在的版本
我們就選擇穩定版吧  這個看個人需求


再來就可以開始安裝我們的vue cli了
vue cli 可以幫助我們在開發vue上快速建立起我們的環境及基本的設定
相關文件可以參考
https://cli.vuejs.org/guide/


首先開啟我們的vscode 在我們的終端機開輸入我們以下語法
 
npm install -g @vue/cli



安裝完後我們就可以透過vue cli的建立起我們的專案

vue init webpack my-project



然後就會要你輸入一些東西 專案名阿 什麼的

幫方便的是他連webpack都自動幫你封裝好了
至於webapck有時間再來詳細說明
我們精美的範例就出來的



接下來我們把專案run起來吧
cd到我們的專案 然後輸入 npm run dev  就可以看到我們8080 port就有我們的vue基本畫面接下來就可以開心開發我們的vue 網頁了
 cd my-project
npm run dev


這是vue cli 最基本中的基本用法  , 未來在來分享些架構上的東西
有任何問題可以在底下留言

2017年11月14日 星期二

2017/11/14 近況

因為工作的關系 一直在寫前端,已經好一陣子沒回去碰.Net的東西,也很久沒更新blogger,雖然前端變強了...哈哈,回頭翻發現自己之前寫了很多code 原本要拿來寫文章的都難產了,近期應該會想慢慢再去回顧一下並開始寫一些相關blog.

其實前端我也想寫,不過近期前端各種framework版本變化太快,要寫的話可能就後面再來處理,目前還是想惡補一下.net的部分 很多東西以前寫過 現在想講卻一時沒辦法講出很好的解釋.

其實滿有趣的.前端後端 我到底比較偏好哪邊,我是哪邊都無法割捨
回顧的話自己也算有進步了,更多解釋更多邏輯,現在比較能從以前經驗裡找到答案
我很佩服固定在寫blog的各位微軟MVP始終保持熱情,甚至是當作人生中的一個不可或缺的部分,我想朝著你們邁進,也給自己一個期許.

Mars 
2017/11/14



處理好我們每次的Web Api吧 Web Api Handlers Message

什麼是Handlers Message?
message handler is a class that receives an HTTP request and returns an HTTP response.
Typically, a series of message handlers are chained together. The first handler receives an HTTP request, does some processing, and gives the request to the next handler. At some point, the response is created and goes back up the chain. This pattern is called a delegating handler.

這樣做有什麼好處呢
我們從中處理拿到的資料 或是紀錄我們之間傳輸的值 我們就不必傻傻的在每個controller或是其他地方寫相同的邏輯 這時候我們就可以透過這種方式做處理

簡單說如下圖

public class RequestAndResponseLoggerDelegatingHandler : DelegatingHandler
{
    public IDataAccess Data { get; set; }

    protected override async Task SendAsync(
                            HttpRequestMessage request, 
                                 CancellationToken cancellationToken)
    {
        var started = DateTime.UtcNow;
        var requestContent = await request.Content.ReadAsStringAsync();

        var response = await base.SendAsync(request, cancellationToken);

        var responseContent = await response.Content.ReadAsStringAsync();
        await Log(started, request, response, requestContent, responseContent);
        return response;
    }

    private async Task Log(DateTime start, HttpRequestMessage request, 
                             HttpResponseMessage response, string requestContent, 
                                string responseContent)
    {
        var finished = DateTime.UtcNow;           
        var info = new ApiLogEntry(start, finished, requestContent, responseContent, 
                                        request, response);
        Data.Log(info);
    }
}
最後我們在註冊到我剛剛所寫的方法 當然也可以註冊很多層
public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MessageHandlers.Add(new RequestAndResponseLoggerDelegatingHandler1());
        config.MessageHandlers.Add(new RequestAndResponseLoggerDelegatingHandler2());

        // Other code not shown...
    }
}
或者是我們在WebApiConfig綁定 特定的路徑 這都是不錯的處理方式
public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "Route1",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "Route2",
            routeTemplate: "api2/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional },
            constraints: null,
            handler: new MessageHandler2()  // per-route message handler
        );

        config.MessageHandlers.Add(new MessageHandler1());  // global message handler
    }
}
參考連結
https://stackoverflow.com/questions/27176329/web-api-request-content-empty 
https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/http-message-handlers