Created
June 21, 2012 16:43
-
-
Save panesofglass/2966916 to your computer and use it in GitHub Desktop.
ApiController in F# Interactive
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#I @"..\packages\Microsoft.Net.Http.2.0.20505.0\lib\net40" | |
#I @"..\packages\Microsoft.AspNet.WebApi.Core.4.0.20505.0\lib\net40" | |
#I @"..\packages\Microsoft.AspNet.WebApi.Client.4.0.20505.0\lib\net40" | |
#I @"..\packages\ImpromptuInterface.5.6.7\lib\net40" | |
#I @"..\packages\ImpromptuInterface.FSharp.1.1.0\lib\net40" | |
#I @"..\packages\Newtonsoft.Json.4.5.6\lib\net40" | |
#I @"..\packages\Unquote.2.2.1\lib\net40" | |
#r "System.Net.Http.dll" | |
#r "System.Net.Http.Formatting.dll" | |
#r "System.Web.Http.dll" | |
#r "ImpromptuInterface.dll" | |
#r "ImpromptuInterface.FSharp.dll" | |
#r "Newtonsoft.Json.dll" | |
#r "Unquote.dll" | |
open System | |
open System.Collections.Generic | |
open System.Net | |
open System.Net.Http | |
open System.Threading.Tasks | |
open System.Web.Http | |
open System.Web.Http.Controllers | |
open System.Web.Http.Dispatcher | |
// NOTE: This is a post-RC update that will be available in the RTM bits. | |
// http://aspnetwebstack.codeplex.com/SourceControl/changeset/changes/07f8232f33af | |
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. | |
/// <summary> | |
/// Provides an implementation of <see cref="IAssembliesResolver"/> with no external dependencies. | |
/// </summary> | |
type AssembliesResolver() = | |
interface IAssembliesResolver with | |
/// <summary> | |
/// Returns a list of assemblies available for the application. | |
/// </summary> | |
/// <returns>A <see cref="Collection{T}"/> of assemblies.</returns> | |
member x.GetAssemblies() = | |
let assemblies = new List<_>(AppDomain.CurrentDomain.GetAssemblies()) | |
assemblies.Add(System.Reflection.Assembly.GetExecutingAssembly()) | |
assemblies :> ICollection<_> | |
// NOTE: This is a post-RC update that will be available in the RTM bits. | |
// http://aspnetwebstack.codeplex.com/SourceControl/changeset/changes/07f8232f33af | |
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. | |
/// <summary> | |
/// Provides an implementation of <see cref="IHttpControllerTypeResolver"/> with no external dependencies. | |
/// </summary> | |
type HttpControllerTypeResolver (?predicate) = | |
let _isControllerTypePredicate = defaultArg predicate HttpControllerTypeResolver.IsControllerType | |
static member IsControllerType (t: Type) = | |
System.Diagnostics.Contracts.Contract.Assert(t <> null) | |
t <> null | |
&& t.IsClass | |
&& t.IsVisible | |
&& t.Name.EndsWith(DefaultHttpControllerSelector.ControllerSuffix, StringComparison.OrdinalIgnoreCase) | |
&& not t.IsAbstract | |
&& typeof<IHttpController>.IsAssignableFrom(t); | |
interface IHttpControllerTypeResolver with | |
/// <summary> | |
/// Returns a list of controllers available for the application. | |
/// </summary> | |
/// <returns>An <see cref="ICollection{Type}"/> of controllers.</returns> | |
[<System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Catching all exceptions in this case is the right to do.")>] | |
member x.GetControllerTypes (assembliesResolver: IAssembliesResolver) = | |
if assembliesResolver = null then | |
raise <| new ArgumentNullException("assembliesResolver") | |
let result = new List<Type>() | |
// Go through all assemblies referenced by the application and search for types matching a predicate | |
let assemblies = assembliesResolver.GetAssemblies() | |
for assembly in assemblies |> Seq.filter (fun a -> a <> null && not a.IsDynamic) do | |
let mutable exportedTypes : Type[] = null | |
try | |
exportedTypes <- assembly.GetExportedTypes() | |
with | |
| :? System.Reflection.ReflectionTypeLoadException as ex -> exportedTypes <- ex.Types | |
| _ -> () | |
// We deliberately ignore all exceptions when building the cache. If | |
// a controller type is not found then we will respond later with a 404. | |
// However, until then we don't know whether an exception at all will | |
// have an impact on finding a controller. | |
if exportedTypes <> null then | |
result.AddRange(exportedTypes |> Array.filter _isControllerTypePredicate) | |
result :> ICollection<_> | |
module Sandbox = | |
type HttpRouteDefaults = { id : RouteParameter } | |
type ValuesController() = | |
inherit ApiController() | |
member x.GetAll() = [|"value1";"value2"|] | |
member x.Get(id: int) = "value" | |
member x.Post([<FromBody>] value: string) = x.Request.CreateResponse(HttpStatusCode.Created, value) | |
member x.Put(id: int, [<FromBody>] value: string) = () | |
member x.Delete(id: int) = () | |
let run() = | |
let cts = new System.Threading.CancellationTokenSource() | |
use config = new HttpConfiguration() | |
config.Services.Replace(typeof<IAssembliesResolver>, new AssembliesResolver()) | |
config.Services.Replace(typeof<IHttpControllerTypeResolver>, new HttpControllerTypeResolver()) | |
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", { id = RouteParameter.Optional }) |> ignore | |
use server = new HttpServer(config) | |
use client = new HttpMessageInvoker(server) | |
use request = new HttpRequestMessage(HttpMethod.Get, "http://sandbox/api/values") | |
async { | |
use! response = Async.AwaitTask <| client.SendAsync(request, cts.Token) | |
printfn "Response: %A" response | |
if response.Content <> null then | |
let! content = Async.AwaitTask <| response.Content.ReadAsStringAsync() | |
printfn "Content: %A" content | |
} |> Async.RunSynchronously | |
Sandbox.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment