File download is not going to work with an RPC request as you cannot set the appropriate headers. You should instead define a Sitelet endpoint and send a request using a form. Here's a minimal example of how you would do this in WebSharper. (Note that instead of using the HttpContext directly we instead use Content.File and use the WebSharper combinators to set the Content-Disposition header)

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
namespace FileDownloadSample

open WebSharper
open WebSharper.Sitelets

type EndPoint =
    | [<EndPoint "/">] Home
    | [<EndPoint "/download">] Download of fileName : string

[<JavaScript>]
module Client =
    open WebSharper.Html.Client

    // You have to use a form here.
    // It's possible to retrieve files from JavaScript with HTML5 but
    // that's more complicated and is not really needed here.
    let FileDownload fileLink =
        Form [
            Attr.Action fileLink
            Attr.Method "GET"
            Attr.Target "_blank"
        ] -< [
            Input [Type "submit"; Value "Download file"]
        ]

module Site =
    open WebSharper.Html.Server

    let [<Literal>] FileName = "database/file.txt"

    let DownloadPage (ctx: Context<_>) fileName =
        let file = System.IO.FileInfo(System.IO.Path.Combine(ctx.RootFolder, fileName))
        if file.Exists then
            Content.File(file.FullName, true, "text/plain")
            |> Content.MapResponse (fun resp ->
                { resp with
                    Headers = Seq.append resp.Headers 
                        [Http.Header.Custom "Content-Disposition" ("attachment; filename=" + file.Name)]
                }
            )
        else Content.NotFound

    let HomePage (ctx: Context<_>) =
        let fileLink = ctx.Link (EndPoint.Download FileName)
        Content.Page(
            Title = "File download", 
            Body = [ClientSide <@ Client.FileDownload fileLink @>]
        )

    [<Website>]
    let Main =
        Application.MultiPage (fun ctx endpoint ->
            match endpoint with
            | EndPoint.Home -> HomePage ctx
            | EndPoint.Download fileName -> DownloadPage ctx fileName
        )
By on 3/29/2016 3:12 AM ()

Rewriting it this way solved it! Appreciate it.

By on 3/29/2016 8:40 AM ()

Here you are writing client-side code but mixing in server-side code without making a call to the server. Given that you intend to serve a PDF file, I'd add another endpoint to my sitelet and request it from the button's event handler.

By on 3/27/2016 4:46 PM ()

Thank you for your reply - I tried to move the some of the code to remoting.fs, but now I get this error:

1
>WebSharper: Failed to translate property access: file [UploadPage.Server].

alt text

By on 3/27/2016 5:30 PM ()

Can you post the Server module (the file function) too? (BTW, feel free to post as code instead of a picture.)

By on 3/27/2016 5:36 PM ()

Sure, this is what i have in remoting.fs under the module server:

1
2
3
4
5
6
7
8
9
10
11
12
module Server =
    [<Rpc>]
    let file = new System.IO.FileInfo(System.Web.HttpContext.Current.Server.MapPath(""))
    if file.Exists
    then 
        System.Web.HttpContext.Current.Response.Clear()
        System.Web.HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name)
        System.Web.HttpContext.Current.Response.AddHeader("Content-Length", file.Length.ToString())
        System.Web.HttpContext.Current.Response.ContentType = "application/pdf"
        System.Web.HttpContext.Current.Response.WriteFile(file.FullName)
        System.Web.HttpContext.Current.Response.End()
        System.Web.HttpContext.Current.Response.Close()
By on 3/27/2016 10:43 PM ()

Here, file is not a function, so this code executes on loading the DLL, which is probably not what you intended. Have a read here, which also has a section on serving files (under Custom Responses).

By on 3/28/2016 8:59 AM ()

Thanks! I didn't know that.

By on 3/29/2016 8:39 AM ()

In the meantime, just remember that whatever you call down the chain from client-side code must either be more client-side code (functions marked with [<JavaScript>]) or RPC functions (e.g. functions marked with [<Rpc>]). Otherwise, you get the error about failing to translate a call.

By on 3/27/2016 6:04 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper