8 people like it.

Asynchronous Controller Helper

The snippet declares a helper for creating asynchronous controllers for ASP.NET MVC 3. It declares a new base class for asynchronous actions that exposes a computation builder for writing actions using F# asynchronous workflows.

Asynchronous Utilities for ASP.MVC

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
/// A computation builder that is almost the same as stnadard F# 'async'.
/// The differnece is that it takes an ASP.NET MVC 'AsyncManager' as an
/// argumnet and implements 'Run' opration, so that the workflow is 
/// automatically executed after it is created (using the AsyncManager)
type AsyncActionBuilder(asyncMgr:Async.AsyncManager) = 

  (Boilerplate code that exposes 'async' operations)

  /// Run the workflow automatically using ASP.NET AsyncManager
  member x.Run(workflow) = 
    // Specify that there is some pending computation running
    asyncMgr.OutstandingOperations.Increment() |> ignore
    async { // Run the asynchronous workflow 
            let! res = workflow
            // Store the result of the workflow, so that it 
            // is passed as an argument to 'Completed' method.
            asyncMgr.Parameters.["result"] <- res
            // Notify the manager that the workflow has completed
            asyncMgr.OutstandingOperations.Decrement() |> ignore }
    |> Async.Start
     

/// An F# specific asynchronous controller that provides 
/// member 'AsyncAction' as a simple way of creating 
/// asynchronous actions (hiding 'AsyncManager').
type FSharpAsyncController() = 
  inherit AsyncController()
  member x.AsyncAction = 
    // Create new asynchronous builder using the current AsyncManager
    new AsyncActionBuilder(x.AsyncManager)

Sample Asynchronous Controller

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
[<HandleError>]
type MainController() =
  inherit FSharpAsyncController()

  // Standard synchronous action that just renders view
  member x.Index() = x.View()

  // Asynchronous action that uses F# asynchronous workflows
  // to download a web page and then returns the length (in bytes)
  member x.LengthAsync(url:string) = x.AsyncAction {
    let wc = new WebClient()
    let! html = wc.AsyncDownloadString(url)
    return html.Length }

  // Called after the completion of workflow created by 'LengthAsync'
  // (the result of the workflow is passed as parameter named 'result')
  member x.HelloCompleted(result:int) =
    // Pass the result to the View
    x.ViewData.Model <- result
    x.View()
Multiple items
type AsyncActionBuilder =
  new : asyncMgr:obj -> AsyncActionBuilder
  member Bind : v:Async<'k> * f:('k -> Async<'l>) -> Async<'l>
  member Combine : a:Async<unit> * b:Async<'j> -> Async<'j>
  member Delay : f:(unit -> Async<'i>) -> Async<'i>
  member For : s:seq<'g> * f:('g -> Async<unit>) -> Async<unit>
  member Return : v:'h -> Async<'h>
  member ReturnFrom : a:Async<'f> -> Async<'f>
  member Run : workflow:Async<'a> -> unit
  member TryFinally : a:Async<'e> * b:(unit -> unit) -> Async<'e>
  member TryWith : a:Async<'d> * b:(exn -> Async<'d>) -> Async<'d>
  ...

Full name: Script.AsyncActionBuilder


 A computation builder that is almost the same as stnadard F# 'async'.
 The differnece is that it takes an ASP.NET MVC 'AsyncManager' as an
 argumnet and implements 'Run' opration, so that the workflow is
 automatically executed after it is created (using the AsyncManager)


--------------------
new : asyncMgr:obj -> AsyncActionBuilder
val asyncMgr : obj
Multiple items
type Async
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitTask : task:Task<'T> -> Async<'T>
static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T>
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async<Task<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:CancellationToken -> unit
static member SwitchToContext : syncContext:SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<CancellationToken>
static member DefaultCancellationToken : CancellationToken

Full name: Microsoft.FSharp.Control.Async

--------------------
type Async<'T>

Full name: Microsoft.FSharp.Control.Async<_>
member x.Bind(v, f) = async.Bind(v, f)
  member x.Combine(a, b) = async.Combine(a, b)
  member x.Delay(f) = async.Delay(f)
  member x.Return(v) = async.Return(v)
  member x.For(s, f) = async.For(s, f)
  member x.ReturnFrom(a) = async.ReturnFrom(a)
  member x.TryFinally(a, b) = async.TryFinally(a, b)
  member x.TryWith(a, b) = async.TryWith(a, b)
  member x.Using(r, f) = async.Using(r, f)
  member x.While(c, f) = async.While(c, f)
  member x.Zero() = async.Zero()
val x : AsyncActionBuilder
member AsyncActionBuilder.Run : workflow:Async<'a> -> unit

Full name: Script.AsyncActionBuilder.Run


 Run the workflow automatically using ASP.NET AsyncManager
val workflow : Async<'a>
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
val async : AsyncBuilder

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
val res : 'a
static member Async.Start : computation:Async<unit> * ?cancellationToken:Threading.CancellationToken -> unit
Multiple items
type FSharpAsyncController =
  inherit obj
  new : unit -> FSharpAsyncController
  member AsyncAction : (obj -> 'b)

Full name: Script.FSharpAsyncController


 An F# specific asynchronous controller that provides
 member 'AsyncAction' as a simple way of creating
 asynchronous actions (hiding 'AsyncManager').


--------------------
new : unit -> FSharpAsyncController
member FSharpAsyncController.AsyncAction : (obj -> 'b)

Full name: Script.FSharpAsyncController.AsyncAction
Multiple items
type MainController =
  inherit FSharpAsyncController
  new : unit -> MainController
  member HelloCompleted : result:int -> 'a
  member Index : unit -> 'c
  member LengthAsync : url:string -> 'b

Full name: Script.MainController

--------------------
new : unit -> MainController
val x : MainController
member MainController.Index : unit -> 'c

Full name: Script.MainController.Index
member MainController.LengthAsync : url:string -> 'b

Full name: Script.MainController.LengthAsync
val url : string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
property FSharpAsyncController.AsyncAction: obj -> 'b
Multiple items
type WebClient =
  inherit Component
  new : unit -> WebClient
  member BaseAddress : string with get, set
  member CachePolicy : RequestCachePolicy with get, set
  member CancelAsync : unit -> unit
  member Credentials : ICredentials with get, set
  member DownloadData : address:string -> byte[] + 1 overload
  member DownloadDataAsync : address:Uri -> unit + 1 overload
  member DownloadFile : address:string * fileName:string -> unit + 1 overload
  member DownloadFileAsync : address:Uri * fileName:string -> unit + 1 overload
  member DownloadString : address:string -> string + 1 overload
  ...

Full name: System.Net.WebClient

--------------------
WebClient() : unit
member MainController.HelloCompleted : result:int -> 'a

Full name: Script.MainController.HelloCompleted
val result : int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
Raw view Test code New version

More information

Link:http://fssnip.net/4z
Posted:12 years ago
Author:Tomas Petricek
Tags: async , asynchronous workflows , asp.net , web , mvc