Skip to content

Commit 2852420

Browse files
authored
Merge pull request #50 from plotly/csharp
CSharp Interop
2 parents 96eba15 + cfe3e0d commit 2852420

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+5481
-190
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net5.0</TargetFramework>
5+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<Compile Include="DashAppCSharp.fs" />
10+
</ItemGroup>
11+
12+
<ItemGroup>
13+
<ProjectReference Include="..\Dash.NET.CSharp\Dash.NET.CSharp.fsproj" />
14+
<ProjectReference Include="..\src\Dash.NET.Giraffe\Dash.NET.Giraffe.fsproj" />
15+
</ItemGroup>
16+
17+
</Project>
+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
namespace Dash.NET.CSharp.Giraffe
2+
3+
open Giraffe
4+
open Dash.NET.Giraffe.Views
5+
//open Dash.NET
6+
open Dash.NET.Giraffe
7+
8+
open Microsoft.Extensions.Logging
9+
open System
10+
open Dash.NET.CSharp
11+
12+
//Giraffe, Logging and ASP.NET specific
13+
type DashGiraffeConfig =
14+
{
15+
HostName : string
16+
LogLevel : LogLevel
17+
// NOTE (giraffe HttpHandler) : The F# version takes a function that returns an HttpHandler type (a type from the Giraffe library). For new we decided to keep C# simpler and just return strings on error, since giraffe stuff is awkward to use from C#.
18+
ErrorHandler : System.Func<System.Exception,string>
19+
IpAddress: string
20+
Port : int
21+
}
22+
with static member internal convertConfig (config : DashGiraffeConfig) : Dash.NET.Giraffe.DashGiraffeConfig =
23+
{
24+
Dash.NET.Giraffe.DashGiraffeConfig.HostName = config.HostName
25+
LogLevel = config.LogLevel
26+
ErrorHandler = fun ex -> ex |> FuncConvert.FromFunc(config.ErrorHandler) |> Core.text // See: NOTE (giraffe HttpHandler)
27+
IpAddress = config.IpAddress
28+
Port = config.Port
29+
}
30+
31+
type DashConfig = private DashConfigWrapped of Dash.NET.DashConfig with
32+
static member Wrap (v : Dash.NET.DashConfig) = DashConfigWrapped v
33+
static member Unwrap (v : DashConfig) = match v with | DashConfigWrapped value -> value
34+
35+
type CallbackMap = private CallbackMapWrapped of Dash.NET.CallbackMap with
36+
static member Wrap (v : Dash.NET.CallbackMap) = CallbackMapWrapped v
37+
static member Unwrap (v : CallbackMap) = match v with | CallbackMapWrapped value -> value
38+
39+
type DashApp(Index : IndexView, Layout : DashComponent, Config : DashConfig, Callbacks : CallbackMap) =
40+
let dashApp : Dash.NET.Giraffe.DashApp = {
41+
Index = Index
42+
Layout = Layout |> DashComponent.Unwrap
43+
Config = Config |> DashConfig.Unwrap
44+
Callbacks = Callbacks |> CallbackMap.Unwrap
45+
}
46+
47+
(* Interop helpers *)
48+
49+
static member private fromDashApp (dashApp : Dash.NET.Giraffe.DashApp) = DashApp(dashApp.Index, dashApp.Layout |> DashComponent.Wrap, dashApp.Config |> DashConfig.Wrap, dashApp.Callbacks |> CallbackMap.Wrap)
50+
51+
(* Builder methods *)
52+
53+
static member initDefault() = Dash.NET.Giraffe.DashApp.initDefault() |> DashApp.fromDashApp
54+
55+
static member initDefaultWith (initializer: Dash.NET.Giraffe.DashApp -> Dash.NET.Giraffe.DashApp) = Dash.NET.Giraffe.DashApp.initDefaultWith initializer |> DashApp.fromDashApp
56+
57+
member _.withConfig (config: DashConfig) =
58+
Dash.NET.Giraffe.DashApp.withConfig (config |> DashConfig.Unwrap) dashApp
59+
|> DashApp.fromDashApp
60+
61+
member _.withIndex (index:IndexView) =
62+
Dash.NET.Giraffe.DashApp.withIndex index dashApp
63+
|> DashApp.fromDashApp
64+
65+
member _.mapIndex (mapping: IndexView -> IndexView) =
66+
Dash.NET.Giraffe.DashApp.mapIndex mapping dashApp
67+
|> DashApp.fromDashApp
68+
69+
member _.appendCSSLinks (hrefs:seq<string>) =
70+
Dash.NET.Giraffe.DashApp.appendCSSLinks hrefs dashApp
71+
|> DashApp.fromDashApp
72+
73+
member _.appendScripts (sources:seq<string>) =
74+
Dash.NET.Giraffe.DashApp.appendScripts sources dashApp
75+
|> DashApp.fromDashApp
76+
77+
member _.withLayout (layout:DashComponent) =
78+
Dash.NET.Giraffe.DashApp.withLayout (layout |> DashComponent.Unwrap) dashApp
79+
|> DashApp.fromDashApp
80+
81+
member _.addCallback (callback: Callback) =
82+
let callback = callback |> Callback.Unwrap
83+
Dash.NET.Giraffe.DashApp.addCallback callback dashApp
84+
|> DashApp.fromDashApp
85+
86+
member _.addCallbacks (callbacks: seq<Callback>) =
87+
let callbacks = callbacks |> Seq.map Callback.Unwrap
88+
Dash.NET.Giraffe.DashApp.addCallbacks callbacks dashApp
89+
|> DashApp.fromDashApp
90+
91+
(* Other *)
92+
93+
member _.getIndexHTML () =
94+
Dash.NET.Giraffe.DashApp.getIndexHTML dashApp
95+
96+
member _.toHttpHandler () =
97+
Dash.NET.Giraffe.DashApp.toHttpHandler dashApp
98+
99+
member _.run (args: string []) (config: DashGiraffeConfig) =
100+
let convertedConfig = config |> DashGiraffeConfig.convertConfig
101+
Dash.NET.Giraffe.DashApp.run args convertedConfig dashApp
102+

Dash.NET.CSharp/Callback.fs

+248
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
namespace Dash.NET.CSharp
2+
3+
open System.Runtime.InteropServices
4+
5+
6+
type Dependency = System.ValueTuple<string, ComponentProperty>
7+
8+
type internal Helpers =
9+
static member internal ConvertDependency ((id, prop) : System.ValueTuple<string, ComponentProperty>) = Dash.NET.Dependency.create (id, prop |> ComponentProperty.Unwrap)
10+
11+
type CallbackResult = internal WrappedCallbackResult of Dash.NET.CallbackResultBinding with
12+
static member Create<'a>(target : Dependency, result : 'a) =
13+
{
14+
Dash.NET.CallbackResultBinding.Target = target |> Helpers.ConvertDependency
15+
Dash.NET.CallbackResultBinding.BoxedResult = box result
16+
}
17+
|> WrappedCallbackResult
18+
19+
static member internal Unwrap (value : CallbackResult) : Dash.NET.CallbackResultBinding = match value with | WrappedCallbackResult v -> v
20+
21+
type ClientSideFunction = internal WrappedClientSideFunction of Dash.NET.ClientSideFunction with
22+
static member Create(Namespace : string, FunctionName : string) =
23+
{
24+
Dash.NET.ClientSideFunction.Namespace = Namespace
25+
Dash.NET.ClientSideFunction.FunctionName = FunctionName
26+
}
27+
|> WrappedClientSideFunction
28+
29+
static member internal Unwrap (value : ClientSideFunction) : Dash.NET.ClientSideFunction = match value with | WrappedClientSideFunction v -> v
30+
31+
32+
type Callback = private WrappedCallback of Dash.NET.Callback<obj> with
33+
34+
static member Unwrap (v) = match v with | WrappedCallback v -> v // Can't be internal because accessed by Dash.NET.CSharp.Giraffe
35+
36+
/// <summary>returns a callback that binds a handler function mapping from multiple input components to a single output component (n -> 1)</summary>
37+
/// <param name="input"> A sequence of `CallbackInput` that represents the input components of this callback. Changes to any of these components signalled by the client will trigger the callback. </param>
38+
/// <param name="output"> A `CallbackOutput` that represents the output component of this callback </param>
39+
/// <param name="handler"> The handler function that maps the callback input components to the callback output components </param>
40+
/// <param name="state"> A sequence of `CallbackState` that represents additional input components of this callback. In contrast to the other input componenst, these will not trigger the handler function when changed on the client.</param>
41+
/// <param name="preventInitialCall"> Wether to prevent the app to call this callback on initialization </param>
42+
/// <param name="clientSideFunction"> A client side function to execute with the callback </param>
43+
static member Create
44+
(
45+
input : Dependency array,
46+
output : Dependency array,
47+
handler: System.Func<'a, CallbackResult array>,
48+
[<Optional>] state : Dependency array,
49+
[<Optional>] preventInitialCall : System.Nullable<bool>,
50+
[<Optional>] clientSideFunction : ClientSideFunction
51+
) : Callback =
52+
53+
let state, preventInitialCall, clientSideFunction = Callback.HandleInput input output (box handler) state preventInitialCall clientSideFunction
54+
55+
let handlerFunction = (fun a -> (FuncConvert.FromFunc handler) a |> List.ofArray |> List.map CallbackResult.Unwrap) |> box
56+
57+
Callback.CreateCallback input output state preventInitialCall clientSideFunction handlerFunction
58+
59+
static member Create
60+
(
61+
input : Dependency array,
62+
output : Dependency array,
63+
handler: System.Func<'a, 'b, CallbackResult array>,
64+
[<Optional>] state : Dependency array,
65+
[<Optional>] preventInitialCall : System.Nullable<bool>,
66+
[<Optional>] clientSideFunction : ClientSideFunction
67+
) : Callback =
68+
let state, preventInitialCall, clientSideFunction = Callback.HandleInput input output (box handler) state preventInitialCall clientSideFunction
69+
70+
let handlerFunction = (fun a b -> (FuncConvert.FromFunc handler) a b |> List.ofArray |> List.map CallbackResult.Unwrap) |> box
71+
72+
Callback.CreateCallback input output state preventInitialCall clientSideFunction handlerFunction
73+
74+
static member Create
75+
(
76+
input : Dependency array,
77+
output : Dependency array,
78+
handler: System.Func<'a, 'b, 'c, CallbackResult array>,
79+
[<Optional>] state : Dependency array,
80+
[<Optional>] preventInitialCall : System.Nullable<bool>,
81+
[<Optional>] clientSideFunction : ClientSideFunction
82+
) : Callback =
83+
let state, preventInitialCall, clientSideFunction = Callback.HandleInput input output (box handler) state preventInitialCall clientSideFunction
84+
85+
let handlerFunction = (fun a b c -> (FuncConvert.FromFunc handler) a b c |> List.ofArray |> List.map CallbackResult.Unwrap) |> box
86+
87+
Callback.CreateCallback input output state preventInitialCall clientSideFunction handlerFunction
88+
89+
static member Create
90+
(
91+
input : Dependency array,
92+
output : Dependency array,
93+
handler: System.Func<'a, 'b, 'c, 'd, CallbackResult array>,
94+
[<Optional>] state : Dependency array,
95+
[<Optional>] preventInitialCall : System.Nullable<bool>,
96+
[<Optional>] clientSideFunction : ClientSideFunction
97+
) : Callback =
98+
let state, preventInitialCall, clientSideFunction = Callback.HandleInput input output (box handler) state preventInitialCall clientSideFunction
99+
100+
let handlerFunction = (fun a b c d -> (FuncConvert.FromFunc handler) a b c d |> List.ofArray |> List.map CallbackResult.Unwrap) |> box
101+
102+
Callback.CreateCallback input output state preventInitialCall clientSideFunction handlerFunction
103+
104+
static member Create
105+
(
106+
input : Dependency array,
107+
output : Dependency array,
108+
handler: System.Func<'a, 'b, 'c, 'd, 'e, CallbackResult array>,
109+
[<Optional>] state : Dependency array,
110+
[<Optional>] preventInitialCall : System.Nullable<bool>,
111+
[<Optional>] clientSideFunction : ClientSideFunction
112+
) : Callback =
113+
let state, preventInitialCall, clientSideFunction = Callback.HandleInput input output (box handler) state preventInitialCall clientSideFunction
114+
115+
let handlerFunction = (fun a b c d e -> (FuncConvert.FromFunc handler) a b c d e |> List.ofArray |> List.map CallbackResult.Unwrap) |> box
116+
117+
Callback.CreateCallback input output state preventInitialCall clientSideFunction handlerFunction
118+
119+
static member Create
120+
(
121+
input : Dependency array,
122+
output : Dependency array,
123+
handler: System.Func<'a, 'b, 'c, 'd, 'e, 'f, CallbackResult array>,
124+
[<Optional>] state : Dependency array,
125+
[<Optional>] preventInitialCall : System.Nullable<bool>,
126+
[<Optional>] clientSideFunction : ClientSideFunction
127+
) : Callback =
128+
let state, preventInitialCall, clientSideFunction = Callback.HandleInput input output (box handler) state preventInitialCall clientSideFunction
129+
130+
let handlerFunction = (fun a b c d e f -> handler.Invoke(a, b, c, d, e, f) |> List.ofArray |> List.map CallbackResult.Unwrap) |> box
131+
132+
Callback.CreateCallback input output state preventInitialCall clientSideFunction handlerFunction
133+
134+
static member Create
135+
(
136+
input : Dependency array,
137+
output : Dependency array,
138+
handler: System.Func<'a, 'b, 'c, 'd, 'e, 'f, 'g, CallbackResult array>,
139+
[<Optional>] state : Dependency array,
140+
[<Optional>] preventInitialCall : System.Nullable<bool>,
141+
[<Optional>] clientSideFunction : ClientSideFunction
142+
) : Callback =
143+
let state, preventInitialCall, clientSideFunction = Callback.HandleInput input output (box handler) state preventInitialCall clientSideFunction
144+
145+
let handlerFunction = (fun a b c d e f g -> handler.Invoke(a, b, c, d, e, f, g) |> List.ofArray |> List.map CallbackResult.Unwrap) |> box
146+
147+
Callback.CreateCallback input output state preventInitialCall clientSideFunction handlerFunction
148+
149+
static member Create
150+
(
151+
input : Dependency array,
152+
output : Dependency array,
153+
handler: System.Func<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, CallbackResult array>,
154+
[<Optional>] state : Dependency array,
155+
[<Optional>] preventInitialCall : System.Nullable<bool>,
156+
[<Optional>] clientSideFunction : ClientSideFunction
157+
) : Callback =
158+
let state, preventInitialCall, clientSideFunction = Callback.HandleInput input output (box handler) state preventInitialCall clientSideFunction
159+
160+
let handlerFunction = (fun a b c d e f g h -> handler.Invoke(a, b, c, d, e, f, g, h) |> List.ofArray |> List.map CallbackResult.Unwrap) |> box
161+
162+
Callback.CreateCallback input output state preventInitialCall clientSideFunction handlerFunction
163+
164+
165+
static member Create
166+
(
167+
input : Dependency array,
168+
output : Dependency array,
169+
handler: System.Func<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, CallbackResult array>,
170+
[<Optional>] state : Dependency array,
171+
[<Optional>] preventInitialCall : System.Nullable<bool>,
172+
[<Optional>] clientSideFunction : ClientSideFunction
173+
) : Callback =
174+
let state, preventInitialCall, clientSideFunction = Callback.HandleInput input output (box handler) state preventInitialCall clientSideFunction
175+
176+
let handlerFunction = (fun a b c d e f g h i -> handler.Invoke(a, b, c, d, e, f, g, h, i) |> List.ofArray |> List.map CallbackResult.Unwrap) |> box
177+
178+
Callback.CreateCallback input output state preventInitialCall clientSideFunction handlerFunction
179+
180+
static member Create
181+
(
182+
input : Dependency array,
183+
output : Dependency array,
184+
handler: System.Func<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, CallbackResult array>,
185+
[<Optional>] state : Dependency array,
186+
[<Optional>] preventInitialCall : System.Nullable<bool>,
187+
[<Optional>] clientSideFunction : ClientSideFunction
188+
) : Callback =
189+
let state, preventInitialCall, clientSideFunction = Callback.HandleInput input output (box handler) state preventInitialCall clientSideFunction
190+
191+
let handlerFunction = (fun a b c d e f g h i j -> handler.Invoke(a, b, c, d, e, f, g, h, i, j) |> List.ofArray |> List.map CallbackResult.Unwrap) |> box
192+
193+
Callback.CreateCallback input output state preventInitialCall clientSideFunction handlerFunction
194+
195+
static member Create
196+
(
197+
input : Dependency array,
198+
output : Dependency array,
199+
handler: System.Func<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, CallbackResult array>,
200+
[<Optional>] state : Dependency array,
201+
[<Optional>] preventInitialCall : System.Nullable<bool>,
202+
[<Optional>] clientSideFunction : ClientSideFunction
203+
) : Callback =
204+
let state, preventInitialCall, clientSideFunction = Callback.HandleInput input output (box handler) state preventInitialCall clientSideFunction
205+
206+
let handlerFunction = (fun a b c d e f g h i j k -> handler.Invoke(a, b, c, d, e, f, g, h, i, j, k) |> List.ofArray |> List.map CallbackResult.Unwrap) |> box
207+
208+
Callback.CreateCallback input output state preventInitialCall clientSideFunction handlerFunction
209+
210+
static member Create
211+
(
212+
input : Dependency array,
213+
output : Dependency array,
214+
handler: System.Func<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, CallbackResult array>,
215+
[<Optional>] state : Dependency array,
216+
[<Optional>] preventInitialCall : System.Nullable<bool>,
217+
[<Optional>] clientSideFunction : ClientSideFunction
218+
) : Callback =
219+
let state, preventInitialCall, clientSideFunction = Callback.HandleInput input output (box handler) state preventInitialCall clientSideFunction
220+
221+
let handlerFunction = (fun a b c d e f g h i j k l -> handler.Invoke(a, b, c, d, e, f, g, h, i, j, k, l) |> List.ofArray |> List.map CallbackResult.Unwrap) |> box
222+
223+
Callback.CreateCallback input output state preventInitialCall clientSideFunction handlerFunction
224+
225+
// Private helpers
226+
227+
static member private HandleInput input output handler state preventInitialCall clientSideFunction =
228+
guardAgainstNull "input" input
229+
guardAgainstNull "output" output
230+
guardAgainstNull "handlerFunction" handler
231+
232+
let state = Option.ofObj state |> Option.map (Array.map Helpers.ConvertDependency >> Seq.ofArray)
233+
let preventInitialCall = Option.ofNullable preventInitialCall
234+
let clientSideFunction : Dash.NET.ClientSideFunction option = Option.ofObj (box clientSideFunction) |> unbox |> Option.map ClientSideFunction.Unwrap
235+
236+
state, preventInitialCall, clientSideFunction
237+
238+
static member private CreateCallback input output state preventInitialCall clientSideFunction (handlerFunction : obj) =
239+
Dash.NET.Callback.multiOut(
240+
input |> Array.map Helpers.ConvertDependency,
241+
output |> Array.map Helpers.ConvertDependency,
242+
handlerFunction,
243+
?State = state,
244+
?PreventInitialCall = preventInitialCall,
245+
?ClientSideFunction = clientSideFunction
246+
)
247+
|> WrappedCallback
248+

0 commit comments

Comments
 (0)