[DajSięPoznać#13] WebAPI w F#: Unity, MemoryCache, ActionFilters

Wstęp

“There are only two hard things in Computer Science: cache invalidation and naming things”, jak mówi znany cytat. Ale dane cache’ować należy, zwłaszcza w przypadku, gdy mamy pełną kontrolę nad ich przepływem oraz gdy nie zmieniają się zbyt często.

Unity

Unity jest jednym z prostszych kontenerów IoC, który łatwo wstawić do projektu WebAPI. W F# wygląda to tak: tworzymy Resolver

type UnityResolver(container: IUnityContainer) =
    member x.unityContainer = container

    interface IDependencyResolver with    

        member x.GetService(serviceType:Type) =
            try
                x.unityContainer.Resolve(serviceType)
            with
                | 😕 ResolutionFailedException -> null
    
        member x.GetServices(serviceType:Type) =
            try
                x.unityContainer.ResolveAll(serviceType)
            with
                | 😕 ResolutionFailedException -> new List<obj>() :> IEnumerable<obj>

        member x.BeginScope() =
            let child = x.unityContainer.CreateChildContainer()
            new UnityResolver(child) :> IDependencyScope

        member x.Dispose() =
            x.unityContainer.Dispose()

Jak widać, jeśli jest taka potrzeba, to nie ma problemu, by metoda F# zwracała null (jeżeli typem wyjściowym jest typ z .NET). Sam Resolver użyty zostaje przy konfiguracji aplikacji w Global.asax.fs.

let container = new UnityContainer()
container.RegisterInstance(client) |> ignore //ElasticClient instance
config.DependencyResolver <- new UnityResolver(container)

 

ActionFilter i MemoryCache

Najprostszym narzędziem do budowy cache’a jest MemoryCache System.Runtime.Caching. W połączeniu z ActionFilterAttribute można zbudować prosty filtr, który dla wskazanej metody sprawdzi, czy w pamięci znajduje wyliczoną już wartość i jeśli tak, to przerywa dalsze procesorwanie i zwraca tą wartość. Web API przestanie przetwarzać request, jeżeli w metodzie OnActionExecuting ustawimy wartość dla pola Response. W przypadku, gdy cache jest pusty, jego wartość zostanie ustawiona po wyjściu z przetwarzania metody w OnActionExecuted.

type MemoryCacheFilterAttribute(key:string) =
    inherit ActionFilterAttribute()

    member val cacheKey = key with get,set

    override x.OnActionExecuting(actionContext:HttpActionContext) =
        let value = MemoryCache.Default.Get x.cacheKey

        if not(value = null) then            
            let content = new StringContent(value.ToString(), Encoding.UTF8, "application/json");
            actionContext.Response <- new HttpResponseMessage()
            actionContext.Response.Content <- content  
        ()

    override x.OnActionExecuted(actionContext:HttpActionExecutedContext) =
        let policy = new CacheItemPolicy();
        policy.AbsoluteExpiration <- DateTimeOffset.Now.AddHours(1.0); 
        let value = actionContext.Response.Content.ReadAsStringAsync().Result 
        MemoryCache.Default.Set(x.cacheKey, value, policy)
        ()

Użycie filtra sprowadza się do umieszczenia atrybutu nad metodą kontrolera z podaniem klucza jako parametru.

Advertisements

One thought on “[DajSięPoznać#13] WebAPI w F#: Unity, MemoryCache, ActionFilters

  1. Pingback: [DajSięPoznać] Podsumowanie | When the smoke is going down

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s