Hi everyone! đ
Today, I want to explore a powerful pattern in Uniface: building Distributed Applications using postmessage.
If you're coming from a modern stack like .NET (C#) or Java, Uniface might look a bit different. But don't worry! The concepts are surprisingly similar to what you already know. Think of Uniface's URouter as a built-in Message Broker (like RabbitMQ light) and postmessage as a way to fire events across different applications.
âšī¸ Note: This tutorial uses Uniface 10.4. If you are using an older version, the concepts are the same, but some configuration details (like URouter paths) might differ slightly.
I've adapted a great example by Peter Beugel to help us understand how this works. Let's break it down step-by-step! đ§
The Concept: Controller & Receiver đī¸
Imagine two separate console apps running on your PC:
- The Controller (
CONTROLAPP): This is our Server or Monitor. It waits for tasks. - The Receiver (
TEST): This is our Client or Worker. It does the heavy lifting (like fetching data).
They don't talk directly. Instead, they shout messages to a "middleman" called the URouter (Uniface Router), which delivers them to the right place.
1. Configuration (The "App.Config") âī¸
In Uniface 10.4, we use .asn (Assignment) files to configure the environment. It's just like appsettings.json or web.config.
We need to tell Uniface two things:
- Where is the Router? (The Connection String)
- Who am I? (The Identity)
controlapp.asn (Server Config):
[PATHS]
; $dnp = Default Network Path
; Connect to Router on localhost port 13001, identify as "THEADMIN"
$dnp=tcp:localhost+13001|||THEADMIN
userA.asn (Client Config):
[PATHS]
; Identify as "userA"
$dnp=tcp:localhost+13001|||userA
Addressing the Controller:
To send a message, we need an address. In Uniface, we use a Logical Name (like a DNS alias) in the config files so the code doesn't need hardcoded IPs.
[LOGICALS]
; "controller" points to: TCP, localhost:13001, OS User "MyUser", Router-ID "THEADMIN", Instance "CONTROLLER"
controller=TCP:localhost+13001|MyOsUser|||THEADMIN:CONTROLLER
2. The Code (The "Business Logic") đģ
The Client (Receiver)
When this app starts, it wants to ask the Controller to do something. In C#, you might use HttpClient.PostAsync. In Uniface, we use postmessage.
operation exec
; Get the address from our config
$control$ = $logical("controller")
; Send a message: Target, MessageID, Data
; "Hey Controller, please trigger a 'RETRIEVE' for 'Andorra'!"
postmessage $control$ , "RETRIEVE" , "Andorra"
edit ; Keeps the window open
The Client also needs to listen for the answer. This is done in a Trigger (think of it as an Event Handler).
trigger receiveMessage
; Check the Command ID ($msgid)
selectcase $uppercase($msgid)
case "RETRIEVE"
; -- Database Logic starts here --
; "Entity" = Table. "Occurrence" = Row.
; If the table container is empty, fetch data.
if ($empty(COUNTRY)=1)
retrieve/e "COUNTRY"
endif
; Send "OK" back to whoever sent this message ($msginfo("SRC"))
postmessage $msginfo("SRC") , "OK", "Done!"
endselectcase
The Server (Controller)
The Controller in this example is a manual tester. It receives a message but waits for YOU (the human) to approve it by clicking a button.
Button Script:
; 'msrc', 'mid', 'mdata' are fields on the screen showing the last message.
; We just echo the exact same message back to the sender.
postmessage msrc , mid , mdata
3. The Flow: How it actually runs đ
- Start Controller: It connects to the Router and waits. đ§
- Start Receiver: It sends a "RETRIEVE" request to the Controller. đ¨
- Controller Updates: The Controller screen shows: "Receiver wants 'RETRIEVE' for 'Andorra'".
- Human Action: You click the button on the Controller. "Okay, approved!" đąī¸
- Echo Back: The Controller sends the command back to the Receiver.
- Execution: The Receiver gets its own command back, fetches the data from the DB, and reports "OK". â
Why use this? đ¤
This "Async Messaging" pattern is crucial for decoupled systems.
- Scalability: You can have 1 Controller and 50 Receivers.
- Responsiveness: The UI doesn't freeze while waiting for a long database query (because it's async!).
- Resilience: If the Receiver crashes, the Controller is still alive.
This is a classic pattern to learn the basics of Uniface's powerful middleware. Special thanks to Peter Beugel for the original code!
đ Original PostMessage Example on Rocket Community
Happy Coding! đ
Top comments (0)