Signature#
Session.CurrentUser // your [Principal] entity — the signed-in person. Null when nobody is.
Session.CurrentUser.Email // any SCALAR of theirs — resolved in place, no round tripAvailable in every component, with no using. Requires the app to declare a [Principal] entity.
Summary#
Session.CurrentUser is the signed-in principal — a row of whatever entity your app marked [Principal], with the
fields you declared on it. It is null when nobody is signed in, which is the honest answer and the reason a page
that needs a user should say so with routing rather than by checking here.
You can read it in any of the three places a component holds a value, and you do not have to know which:
- as a member —
var me = Session.CurrentUser;— the whole row, fetched when the page loads; - in a render expression —
Text(Session.CurrentUser.Email); - inside an action —
new Order { Reference = reference, Owner = Session.CurrentUser };
The third one is the one that used to need a workaround. It does not any more: the compiler hoists the read onto the component and the action closes over it, which is precisely what you would have written by hand.
Description#
Reading a single field costs nothing#
A scalar of the principal — Session.CurrentUser.Email, .Id, or any column you declared — resolves in place, on
whichever side is asking, with no round trip. The browser reads it from the bag the server sent at boot, built
server-side, so a field your security rules mask reads null in the browser exactly as it does on the server. Use it
freely in a render expression, a filter, or a field default:
Text($"Signed in as {Session.CurrentUser.Email}");
live var mine = Order.Where(o => o.Owner.Id == Session.CurrentUser.Id);Reaching through a reference (Session.CurrentUser.Manager.Name) is a different question — the browser holds the
manager as an id, not as a row — so that stays a server read and belongs on a member.
The whole row, in an action#
An action runs in the browser, and the browser cannot run a database read in the middle of one. So when an action
mentions Session.CurrentUser, the compiler lifts the read onto the component as an ordinary fetched member and the
action reads that. Several actions on one page share one fetch.
[Principal] entity User {
[Required, MaxLength(200)] string Email;
security { allow read when IsAuthenticated; }
}
entity Order {
[Required, MaxLength(50)] string Reference;
User Owner;
security { allow read, create when IsAuthenticated; }
}
[Page("/orders/new")]
[Render(CSR)]
component NewOrder() {
string reference = "";
action Save() {
new Order { Reference = reference, Owner = Session.CurrentUser };
UnitOfWork.Commit();
}
render {
Stack {
Input(value: reference, placeholder: "Reference");
Pressable(onClick: Save) { Text("Save"); }
}
}
}⚠ Other reads behave differently inside an action, and it is worth knowing which. An ordinary read —
Order.Where(…) — is not yet available inside an action: bind it to a member and read the member instead. The
browser has no database, so a read in the middle of an action means a round trip at that moment; the compiler does not
yet arrange one. Session.CurrentUser needs no such arrangement — its value is fixed for as long as the page is open
(signing in or out reloads the app), so it is fetched with the page and simply read.
It is who is being SHOWN the page, not who wrote the row#
Every entity is audited automatically, and CreatedBy on a saved row is stamped by the server from the request's
principal. Your own field (Owner above) is the app's view; the audit column is the platform's, and no app code can
write it. When you want proof of who did something, read the audit column. When you want a relationship you control —
who a task is assigned to, whose basket this is — declare your own reference and set it.
Nobody is signed in#
Session.CurrentUser is null for an anonymous visitor. Do not use that null as a gate: a page that requires a user
should require one at the route (routed components are protected unless they say [AllowAnonymous]), so the page is
never rendered for someone who is not there. If you want a name for work done before sign-in, that is
Visitor.
See also#
- Visitor — the anonymous twin, for work that begins before there is a user
- component — members, actions, and where each kind of value lives
- principal predicates (IsAuthenticated / IsAnonymous) and open reads — the predicates that read the same principal in a
security { }block