【F# + ASP.NET MVC】 カスタム非同期コントローラーを作成するには(その2)

◆ 参考

Asynchronous Workflow Controller

◆ Controller

namespace Sample.Controllers

open Unchecked
open System
open System.Web.Mvc
open System.Web.Mvc.Async
open System.Net

exception PreserveStackTraceWrapper of exn

// カスタム非同期コントローラー
// そのままコピペ。。。後で詳細を調べてみよう。
type FSharpAsyncController() = 
    inherit AsyncController()

    override __.CreateActionInvoker() = 
        upcast {   
            new AsyncControllerActionInvoker() with
                member __.GetControllerDescriptor(controllerContext) =
                    let controllerType = controllerContext.Controller.GetType()
                    upcast {
                        new ReflectedControllerDescriptor(controllerType) with
                            member ctrlDesc.FindAction(controllerContext, actionName) =
                                let forwarder = base.FindAction(controllerContext, actionName) :?> ReflectedActionDescriptor
                                if (forwarder <> null && forwarder.MethodInfo.ReturnType = typeof<Async<ActionResult>>) then 
                                    let endAsync' = ref (defaultof<IAsyncResult -> Choice<ActionResult, exn>>)
                                    upcast {
                                        new AsyncActionDescriptor() with
                                            member actionDesc.ActionName = forwarder.ActionName
                                            member actionDesc.ControllerDescriptor = upcast ctrlDesc
                                            member actionDesc.GetParameters() = forwarder.GetParameters()
                                            member actionDesc.BeginExecute(controllerContext, parameters, callback, state) =
                                                let asyncWorkflow = 
                                                    forwarder.Execute(controllerContext, parameters) :?> Async<ActionResult>
                                                    |> Async.Catch
                                                let beginAsync, endAsync, _ = Async.AsBeginEnd(fun () -> asyncWorkflow)
                                                endAsync' := endAsync
                                                beginAsync((), callback, state)
                                            member actionDesc.EndExecute(asyncResult) =
                                                match endAsync'.Value(asyncResult) with
                                                    | Choice1Of2 value -> box value
                                                    | Choice2Of2 why -> raise <| PreserveStackTraceWrapper(why)
                                    } 
                                else 
                                    upcast forwarder 
                    } 
        }

type HomeController() = 
    // カスタム非同期コントローラーを継承
    inherit FSharpAsyncController()
    // 非同期処理
    member this.Index() = 
        let v = this.View()
        async {
            // WebページのHTMLを取得
            let wc = new WebClient()
            let! html = wc.AsyncDownloadString(
                            new Uri("http://www.google.co.jp"))
            // 非同期処理の結果をセット
            this.ViewData.["Html"] <- html
            return v :> ActionResult
        }
                

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中