iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 29
0
Software Development

如何讓程式碼告訴你他在做什麼?系列 第 30

Day-29 Morpheus : Free Your Mind

  • 分享至 

  • xImage
  •  

在開始之前,先把一個熱門好一陣子的框架拿出來談談吧

Middleware

詳細請參考上方連結的微軟官方說明文件,我一直覺的微軟現在的MSDN Document做的非常的好

就算不是M$使用者也可以看一下拿回自己擅長的領域用亦可

這裡簡單介紹所需要關注的重點

藉由 Context 這種具有上下文特性的 DTO 來貫穿整個流程,並且依照 Context 最後的結果來做為結果值

以 Http Service 為例就是 HttpContext ,HttpContext 具有 Request 的資訊以及,Response 最後回傳的內容

並且由每一個經過的方法來做調整,所以每一個方法都可以處理這次的 Request 當然也可以阻斷流程進行

在 .Net Core中,每一個流程都是一個 delegate 叫做 RequestDelegate


public delegate Task RequestDelegate(HttpContext context);

所以說,如果有HttpContext而且還有RequestDelegate,那就可以執行該委派


public Task ProcessRequest(HttpContext context, RequestDelegate request)
    => request(context);

這其實就是 Owin Middleware 的原型,但這樣還不夠,這樣必須等到執行階段才能開始組合

所以這次借用科學上一個很常用的做法叫做假說

簡單來講就是假裝已經有了,先自我催眠一下(誤)

所以就假裝已經有HttpContext存在的情況下


private HttpContext _context;

pubilc Task Request(RequestDelegate request)
    => ProcessRequest(_context,request);

如此一來這整個程式最終還是會變回Func<HttpContext,Task>也就是RequestDelegate

所以最後演變成


public RequestDelegate Middleware(RequestDelegate request)
    => ctx => request(ctx);

而這樣有什麼好處呢?這表示可以這樣做


public RequestDelegate Middleware(RequestDelegate request)
    => async ctx => {
        // do anything you wait before process request
        await request(ctx);
        // do anything you wait after process request
    };

而且這樣做完之後往後傳遞並不會有型別上的不同,後續的人一樣可以做相同的事情

這次就來利用這樣的特性來完成所需要的功能吧

於前篇所做的ChainFactory中,做那樣的調整的目的就是為了這件事情


    public class ChainFactory : IChainFactory
    {
        private readonly IHandler _handler;

        public ChainFactory(IHandler handler)
        {
            _handler = handler;
        }

        public IChain<T> Create<T>(Func<T> func)
        {
            return new LazyChain<T>(Handle(factory));
        }

        public IChainAwaiter<T> Create<T>(Task<T> task)
        {
            return new ChainAwaiter<T>(Handle(task));
        }

        private Func<T> Handle<T>(Func<T> factory)
        {
            var result = factory();
            _handler.Handle(new ResultContext(() => result));
            return () => result;
        }

        private Task<T> Handle<T>(Task<T> task)
        {
            _handler.Handle(new ResultContext(() => task.Result));
            return task;
        }
    }

如此一來就可以將IHandler接上接下來要使用的對象

這裡要注意的是,Func<>Task<>特性不同點

  • Func<>:每一次執行都會重做一次全部的過程,所以當取得一次結果之後,將結果重新包裹回傳
  • Task<>:當執行完畢後,每一次 await 都會取得完全相同的物件,所以利於後續撰寫則回傳 Task

ChainFactory.Handle這個方法就如同前述的Middleware的結構

所以不管此處我們如何包裹原本的物件,總之回傳一樣的就行了

而此處只有在對於取得的結果做 Handle,但對於前面的參數方法沒有 Handle 到

所以接下來會在要連同外面複雜的擴充方法問題一併解決掉

備註:


  • 如您目前是團隊工作,則請遵守團隊所訂下的撰寫規範,此篇文章僅為參考建議使用
  • Middleware 的用法在近期的MVC Framework中是非常常見的
  • 此框架原出處似乎為 Ruby 但現在 .Net , PHP 的MVC 幾乎都是這個框架
  • 解決方案並不受語言限制,使用方法也不受問題限制
  • Free Your Mind

上一篇
Day-28 想要做什麼東西,蓋工廠就對了
下一篇
Day-30 一切的努力,都只是為了那唯一的目標
系列文
如何讓程式碼告訴你他在做什麼?31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
台灣碼農
iT邦新手 5 級 ‧ 2018-01-16 23:14:05

這哪招,你忘了我每天檢查嗎

我要留言

立即登入留言