I currently do not know what else to tinker to make this work. Please help.
I followed this section from the online docs: Overview | DotVVM Documentation
Context:
The validation takes place server-side in a method that is part of the PopupModal SVM (sub view model) that is direct child of a MarkupControl VM (the root VM). This method is called from a custom event handler of the PopupModal, the event is triggered by a ModalDialog SVM that is child of PopupModal (called mdConfirmationStep1).
Now, step by step:
The markup of the OperationFinalizationSection that holds the validated fields including SelectedFinalizationDate that is also validated server-side:
I made sure that the DotvvmInterruptRequestExecutionException exception that is thrown by the FailOnInvalidModelState() method, is nowhere caught or handled. Not in the code-behind, not in OnCommandExceptionAsync and not in OnPageExceptionAsync. I think it is free to manifest itself.
But the problem has the same behaviour regardless of anything I’ve tried so far (including removal of those yellow underlined things in the markup up above).
Also tried calling DoServerValidationBeforeAnyOperation() directly in the OnClick_ConfirmationStep1Yes()(sync version of OnClick_ConfirmationStep1YesAsync) command of the mdConfirmationStep1, eliminating the AsyncEventHandler custom event. This complete with test property inside ConfirmationStep1 SVM, so for the adding of error to be simple like this:
And having the markup of mdConfirmationStep1 like this:
It is true that the _parent.DoStuff() approach resolves the issue.
The problem is that doing this for all current and future cases, messes up with separation of concerns that I try to keep as tight as possible (because large volume of code and complex forms & business processes).
If I have a grandchild ModalDialog inside ConfirmStep2 modal that is inside PopupModal, this means that I’ll have to use _parent2.DoStuff2() and inside DoStuff2() to call al sorts of methods from _parent and from _this, public methods that do not need to be public and that are of no concern for the outside code, complicating the flow cases of the PopupModal which got big and is steadily enlarging.
I tried to find reference to _parent inside Context in code-behind, no luck.
I also tried to use a PopupModal (VM) reference property but again (as stated in an older post), it is parsed by DotVVM and added to the control tree, causing multiple runs of the event handlers Load() etc. and it quickly hinders & complicates a lot of context and risking call stack overflow.
I thought about using a public field instead of a property for the PopupModal reference inside the mdConfirmationStep1 but it is not ideal 'cause I lose CodeLens on which I rely. LE: plus, it triggers DotVVM03 warning.
Cutting it short, what I want to achieve and would ease my mind with all this existing structure already in place, is:
with OnClick_ConfirmationStep1YesAsync() being inside the mdConfirmationStep1 where it belongs and in code-behind to reach to its parent, grandparent, grandgrandparent etc. as needed.
(this approach forces me to use AsyncEventHandler (and I suspect this causes the internal DotVVM errors) as to be able to reach the async PreExecuteOperationAsync() from the PopupModal (the parent VM). I cannot make PreExecuteOperationAsync() sync unfortunately )
Sorry, I’m getting in this a bit. The error looks like the one which occurs when you catch the InterruptRequest exception. You should see something like “cannot change headers, request body is already started” in the logs. It’s not possible to get this error to the client, because the request has already started… Asp.Net Core just resets the TCP connection to let the browser know that something is wrong.
In this case, the exception is probably caught by an unawaited Task (or async void method or something like this), but I can’t tell where is the problem here, the code on screenshots looks fine.
I think that’s what [Bind(Direction.None)] (or JsonIgnore) does, or I don’t understand this request
[Bind(Direction.None)] does not avoid DotVVM creating a duplicate of the VM of the property and does not avoid double execution of its Load() etc. handlers.
Does not work and my PopupModal Load() causes stack overflow as a result (by endlessly executing ConfirmStep1Modal.popupModalReference = this.
Also tried with
Not working.
I reverted back to the field approach. And I continue to be of the opinion that a [DoNotConsiderForTheDotvvmControlTree] attr would nicely resolve all this.
I sorry, I didn’t understand the problem. JsonIgnore will not do anything either. I’d suggest overriding the GetChildViewModels() method. You can either
explicitly list the viewmodels where you want to call the method
Well, that definitely shouldn’t fail like this unless the DotvvmInterruptRequestExecutionException is caught somewhere else. Normally, the request body is written after the Render phase, not before OnCommandExceptionAsync.
If I understood you correctly: Sure, it was just intermediary code prior to fully implemented proper server validation. But I thought the exception details could help us find a solution to the 3 errors phenomenon.
The error handler is fine. It shouldn’t fail on the “StatusCode cannot be set because the response has already started.” exception (sorry, it wasn’t comprehensible)
I don’t know, I’m glad I do not have to deal with that case anymore. If thrown DotvvmInterruptRequestExecutionException on failed server validation is normal and expected behaviour, then I just catch it, log it as warning and set context.IsCommandExceptionHandled / context.IsPageExceptionHandled accordingly.
It is expected, it’s how we skip the rest of command processing and return the result right away.
Most methods like Redirect and FailOnInvalidModelState write out the response body and then throw the DotvvmInterruptRequestExecutionException. You don’t want to catch this exception - If you catch it, you get into this state where you cannot change the response anymore.