BTW, if I did want /somepage to be "the start page" that the user would be auto directed to if they went to www.mysite.com, what would I have to do to FORCE this "redirect"?

You would add an endpoint to the root of the app, and use Content.Redirect to redirect it to your second home page (using the EndPoint value.)

By on 5/12/2018 4:05 AM ()

Great Adam, thanks for that.

Just in case this is helpful for anyone else. I was able to do either :

1
2
3
4
5
6
7
8
9
10
11
12
13
type EndPoint =
    | [<EndPoint "/">] Root
    | [<EndPoint "/home">] Home

...

[<Website>]
let Main =
    Application.MultiPage (fun ctx endpoint ->
        match endpoint with
        | EndPoint.Root -> Content.RedirectPermanent Home
        | EndPoint.Home -> HomePage ctx
...

the above actually redirects to /home

or

1
2
3
4
5
6
[<Website>]
let Main =
    Application.MultiPage (fun ctx endpoint ->
        match endpoint with
        | EndPoint.Root -> HomePage ctx
        | EndPoint.Home -> HomePage ctx

...

in this case, the same page handler is used for "/" as is used for "/home" but there is no redirection

Thanks again Derek

By on 5/13/2018 8:10 PM ()

Here is an option:

1
2
3
type EndPoint =
    // ... your endpoints ...
    | [<EndPoint "/"; Wildcard>] NotFound of string

Wildcard catches the remainder of the URL (so in this case, everything after the /) and passes it as the string parameter to NotFound; for example /not/found will give you NotFound "not/found".

You can also use a string list or a string[] instead of a string, and you'll get the path components split, for example /not/found will give you NotFound ["not"; "found"].

By on 5/7/2018 12:54 AM ()

Hey Loïc, many thanks for that but! When I changed it to this:

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
type EndPoint =
    | [<EndPoint "/">] Home
    | [<EndPoint "/login">] Login
    | [<EndPoint "/about">] About
    | [<EndPoint "/"; Wildcard>] NotFound of string list
...
    let HomePage ctx =
        Templating.Main ctx EndPoint.Home "Home" [
            h1 [] [text "Say Hi to the server!"]
            div [] [client <@ Client.Main() @>]
        ]

    let AboutPage ctx =
        Templating.Main ctx EndPoint.About "About" [
            h1 [] [text "About"]
            p [] [text "This is a template WebSharper client-server application."]
        ]

    let LoginPage ctx =
        Templating.Main ctx EndPoint.Login "Login" [
            h1 [] [text "Login"]
            div [] [client <@ Client.LoginWidget() @>]
        ]
...

    [<Website>]
    let Main =
        Application.MultiPage (fun ctx endpoint ->
            match endpoint with
            | EndPoint.Home -> HomePage ctx
            | EndPoint.About -> AboutPage ctx
            | EndPoint.Login -> LoginPage ctx
            | EndPoint.NotFound _ -> MissingPage ctx
        )

... my other pages stopped working. mysite.com/ gets gives 404, but stranger than that, the home and login pages stop working: neither page displays their content.

I tried changing / to /home in

1
2
3
4
5
type EndPoint =
    | [<EndPoint "/home">] Home
    | [<EndPoint "/login">] Login
    | [<EndPoint "/about">] About
    | [<EndPoint "/"; Wildcard>] NotFound of string list

but that did not help.

BTW, if I did want /somepage to be "the start page" that the user would be auto directed to if they went to www.mysite.com, what would I have to do to FORCE this "redirect"?

Once I get rid of the NotFound handling code, the other pages work again.

By on 5/8/2018 11:37 PM ()

Actually, this is something is specific to WebSharper, I was mistaken before.

By on 5/10/2018 11:46 PM ()

One extra bit of info: I just noticed that when I have the NotFound handling code in place and check dev tools in Chrome, I see lots of JS errors. I get:

1
2
3
4
5
6
7
8
Uncaught SyntaxError: Unexpected token "<"
runtime.js:1
WebSharper.Main.js:1
WebSharper.Collections.js:1
WebSharper.Web.js:1
WebSharper.UI.js:1
WebSharper.UI.Templating.Runtime.js:1
ClientServer1.js:1

The last file is my app's generated JS file.

I know this "error" does not provide much extra info but thought I would send it through in case it sheds any light on things.

By on 5/11/2018 1:26 AM ()

So, first, the issue where NotFound was overriding Home was reported here: https://github.com/dotnet-websharper/core/issues/946 and fixed on master, so it will be corrected in the next release.

Now, this new issue is indeed a problem. The wildcard sitelet on / overrides all URLs, including those that point to files that would otherwise be served by ASP.NET, such as Scripts/*.js. That's not good.

I've experimented a bit, and here is what I've come up with. Essentially, I'm using ASP.NET's error handling to rewrite the URL into one that is handled by our sitelet.

  1. In Web.config, add the following:

    1
    2
    3
    4
    5
    6
    7
    8
    
    <configuration>
      <system.webServer>
        <httpErrors errorMode="Custom">
          <remove statusCode="404"/>
          <error statusCode="404" responseMode="ExecuteURL" path="/error"/>
        </httpErrors>
      </system.webServer>
    </configuration>

    This will rewrite unrecognized requests to http://your.site.com/foo/bar to http://your.site.com/error?=404;http://your.site.com/foo/bar (not redirect, just rewrite).

  2. Recognize the above redirect in the sitelet:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    type EndPoint =
        // your normal endpoints...
        | [<EndPoint "/error"; Wildcard>] Error of string
    
    [<Website>]
    let Main =
        Application.MultiPage (fun ctx endpoint ->
            match endpoint with
            // your normal endpoints...
            | EndPoint.Error _ ->
                // Parse the original URI from ASP.NET's rewrite, in case you need it
                let requestedUri =
                    let q = ctx.RequestUri.Query
                    let q = q.[q.IndexOf(';') + 1 ..]
                    match System.Uri.TryCreate(q, System.UriKind.Absolute) with
                    // The request was to /error/... directly
                    | false, _ -> ctx.RequestUri
                    // The request was to a non-existent path, and rewritten by ASP.NET
                    | true, uri -> uri
    
                Content.Text (sprintf "Unknown URI: %A" requestedUri)
                |> Content.SetStatus Http.Status.NotFound
        )

I hope this helps!

Side note for anyone else reading this: the above applies when you're using ASP.NET 4.x. If you're using ASP.NET Core or OWIN, then there should not be a need for any of the above: file URLs will correctly be handled first as long as you call UseStaticFiles() before UseWebSharper().

By on 5/11/2018 6:50 AM ()

Hi Loïc - many thanks for that, that did the trick. Derek.

By on 5/13/2018 7:57 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