HandleSpecialURL

I’m trying to build a web service.
I’m using HandleSpecialURL to intercept the URL then make decisions based on the url structure and query parameters.
I started off the project using WebService-HandleSpecialURL sample project.
That sample project uses Request.Print to ‘build’ the web page that is presented to the user.
My question is if I have WebPage objects in my project, how to I respond with a WebPage object?

You cannot serve a webpage directly from HandleURL. But you can redirect the user to your app, eventually with parameters such as http://127.0.0.1:8080?page=3 for it to open at a specific webpage.

Brian, apologies for self advertising but you may appreciate RapidServices: http://www.dev.1701software.com/blog/2016/11/2/introducing-rapid-services-for-xojo-web

It was designed to make this process much easier.

I’m confused.
There must be something different between Handle’Special’URL and HandleURL that I’m not grasping.

So does HandleURL call MyWebPage3.Show based on the parameter?

HandleURL and HandleSpecialURL cannot load a Xojo Webpage under any circumstance.

Xojo Webpages are basically

tags that the Xojo javascript framework loads on demand/as needed. The HandleURL method catches the incoming request earlier in the chain (potentially) before the Xojo framework has been loaded by the client and has no access to any Xojo Web controls.

So there must be a way for the app to communicate with the session objects what it wants to do.

What are you trying to accomplish here? A Session object = a browser running javascript that currently has your app open. HandleURL is only called by some other server/client and not the one in the browser.

Now it’s possible you are doing something like listening for PayPal IPN and you want to inform the user that some external event (like PayPal certifying the transaction) has occurred. In this case the external service needs the Session ID of the client. Then when it hits HandleURL you need to use the App.SessionAtIndex, loop through the Sessions and find the one with the Session ID and then do what you need to do.

The App receives url requests. Those requests must be parsed and passed on to a new session or to an existing session.

This code, for example, was lifted from the Xojo help file for setting an unhandled exception page.

[code] // Loop through all sessions and have them display a new ExceptionPage.
For i As Integer = 0 To App.SessionCount - 1
// Without creating a WebSessionContext here, creating
// the page would fail triggering a SessionNotAvailableException.
Dim context As New WebSessionContext(App.SessionAtIndex(i))

// Because we have a context, we can create a new
// ExceptionPage and assign it to the session.
context.Session.CurrentPage = New ExceptionPage

Next[/code]

context.Session is perhaps the key to my problem.
I’m hoping I can call a method, get/set a property or raise an event with a parameter on this object.

So let’s just say the http server (App) receives this url from a client

http://myserver.com:80/service?Param=Value1

A new session is created to handle the request.
Every session has a unique identifier, called identifier. eg: 123
That session can remain active and at a later date the server can receive another url.

http://myserver.com:80/service?SessionID=123&Param=Value2

By inspecting the URL I see that there is a SessionID in the URL.
I look to see if I have a session with that identifier and if I do, then I pass on new url I just received to context.Session.Update(URL)

What I don’t understand is how the client gets the SessionID from the server so that it can keep it to build the next url which must include it.

Ok, lets back up…

  • WebSessions can only be created and maintained when a browser connects to your app.
  • HandleUrl and HandleSpecialUrl have no idea if they are connected to a session or not. As a matter of fact, you can’t intercept requests to an active session in those event handlers anyway. The best you could do would be to apply the results of a call to an existing session, but you’d still need a browser connection to keep the session going.

If you are truly just creating a web service which has no GUI element to it, just use HandleUrl and maintain the Session info yourself. They’re just an array of classes anyway.

Requests that HandleURL is designed for would not have session identifiers. No session is created when HandleURL fires. HandleURL is an event that the web server raises on each request.

When a web browser hits a web app it gets a session identifier assigned to it after the javascript framework is loaded. All subsequent requests to the server have this server identifier. That’s what you are seeing in HandleURL - the traffic from your web browser.

However HandleURL is not designed for that web browser traffic. That stuff you would not handle and say “Return False”. You only “Return True” on requests outside of a web session like a REST API call that would not have a session identifier.

[quote=315000:@Brian O’Brien]The App receives url requests. Those requests must be parsed and passed on to a new session or to an existing session.

[/quote]

Brian,

I do not know the complete picture of what you want to do, but I feel you are adding a level of complexity that is not necessary.

The phrase above can perfectly well be done without HandleURL or HandleSpecialURL (both do pretty much the same thing, the second responds only to /special and /api).

Sessions cannot be created in handleURL. But they are created when a new user arrives to the app. No need to second guess that mechanism. Each session has an identifiers made by the app.

When a user connects to the app, parse the url parameters and display the appropriate page, or quit.

Is it what you want to do ?

I suspect what I want to do is have the notion of a session that goes beyond one url call to my server. (that’s the big picture)
The little picture is I’m trying to get the url parameters in the open event of my WebPage.
From there I can determine if this is a new request or if I should find the existing WebPage this request goes to using SessionID as the key. Then I know which WebPageObject to pass this request to, pass it, and then redirect the client to that page.

Statelessness? Persistent Object?

What you are describing is already done for you. But it requires that the client be a browser.

Other non-browser clients (lets say curl for this discussion) don’t have the facilities necessary to maintain one of our sessions, that is, HTML, JavaScript, CSS and a full DOM.

In our system you can’t mix these two.

What you are describing is the equivalent of using a simple socket. Even if you were to trick something like curl into sending a valid user agent string, all of pull get back is an HTML page with links to the assets necessary to run the page which will require the JavaScript, CSS and DOM parts to function properly, something that simple sockets do not have.

Now, if you’ll stop thinking about the use of the classes whose names begin with Web*, we can help you get to a functional API server.

[quote=315185:@Brian O’Brien]I suspect what I want to do is have the notion of a session that goes beyond one url call to my server. (that’s the big picture)
The little picture is I’m trying to get the url parameters in the open event of my WebPage.[/quote]

Getting the URL parameters is easy :
http://documentation.xojo.com/index.php/Websession
URLParameter
URLParameterCount
URLParameterExists
URLParameterName

From your example of URL parameter I suspected you wanted to resume a session somehow. Since a session is destroyed after 3 minutes of inactivity, that would imply you save the state of the session yourself, maybe in session.close, probably using the sessionID plus a time stamp. Then upon resume, you must reinstate all properties and variables as well as place the user on the WebPage he was at with controls in the same state.

It is not impossible to save all that in a database, and fetch it upon URL parameter.

Sharing data between sessions so users see the same thing would be feasible I think with the notion of “master session”, which all properties and state would be duplicated among other sessions, and likewise, all actions in child sessions be repercuted in the master session. It seems easy on the surface, but you will also have to manage collisions, when two users try to do something at the same time.

It is probably way easier in simple reading mode than interactive.

Any session has access to other sessions via SessionCount and SessionAtIndex
http://documentation.xojo.com/index.php/WebApplication

You may be interested by that discussion :
https://forum.xojo.com/15427-display-dialog-on-all-sessions/0

Hi @Brian O’Brien,

To start a NEW session from the HandleSpecialURL, do something like this:


        ' Create a Unique identifier for this request. I'm using MonkeyBread's GUID generator but this can be  anything
	GUID = UUIDMBS.UUID.ValueFormattedString()
	
        ' POSTData is a Dictionary property on the App object. Save the POST data into the dictionary
	App.POSTData.Value(GUID) = Request.Entity
						
	' Build the URL to your app with your GUID in the request string 
	URL = PathwaysApplicationAddress + "?loginsso=" + GUID
						
	' Create a Redirect HTML which refreshes to your application i.e. starts a new session
        Dim Redirect As String
	Redirect = "<HTML> <HEAD><META HTTP-EQUIV='REFRESH' CONTENT='0;URL=" + URL + "'></HEAD><BODY></BODY></HTML>"

       ' Send this back to the browser 
       Request.Print Redirect

	' Return true to indicate that you have handled the request
	Return True

Then, in the Session.Open event do something like this:


        ' Check for your request string
	If Session.URLParameterExists("LoginSSO") Then
			
		' Get the GUID from the request string
                Dim GUID As String
		GUID = Session.URLParameter("LoginSSO")
						
		
                ' Check if this is a valid GUID
		If App.POSTData.HasKey(GUID) Then
			
                        ' Get the post data from the dictionary					
      		        Dim ThisPostData As String
			ThisPostData = App.POSTData.Value(Session.GUID)
			
                        ' Remove this GUID from the dictionary so it can't be used again
			App.POSTData.Remove(Session.GUID)
								
                        ' Navigate to your page
			Dim newForm as New frmPage3
			newForm.Show

                Else ... Navigate to your login page or whatever

To take control of an EXISTING session, in the HandleSpecialURL, do something like this:

						
	' Get the parameters from the Request string which includes the SessionId
	Dim Params() As String
	Params = Split(Request.Entity, "&")
						
	' Get the SessionId
	Dim SessionId As String
	SessionId = Params(0).Replace("SessionId=", "")
						
	' Get any other parameters you want
	UserName = Params(1).Replace("UserName=", "")
						
	' Use a Weak Reference to the Session
	Dim ThisSession As New WeakRef(SessionWithIdentifier(sSessionID))
		
	' Make sure the session still exists
	If ThisSession.Value <> Nil Then
				
		'  We are using a specific form called frmVisit which we want to react to these requests
		If frmVisit(WebSession(ThisSession.Value).PageWithName("frmVisit", False)) <> nil Then
						
			' Set off a timer on the page to react to the request
			frmVisit(WebSession(ThisSession.Value).PageWithName("frmVisit", False)).tmrNavigator.Mode = Timer.ModeSingle
						
		End If
				
	End If						

	' Nothing to print to the calling routine
        Dim Redirect As String
	Redirect = ""
						
       ' Send this back to the browser 
       Request.Print Redirect

	' Return true to indicate that you have handled the request
	Return True

In frmVisit.tmrNavigator.Action event which is on an existing session:


        ' We show a dialog box to the user and then navigate to another page in the Dialog.Dismissed event
	Dim D As New dlgErrorAndWarning
	D.lblMessage.Text = "You have received a Message from:" + Username
	D.Show
1 Like

Wow!!! Many thanks everyone…
Let me go try it all out.
Thanks again… I’ll be back.