How do I pass a server-side exception back to the client
I use CSLA5.0.1 in.netcore3.1 + WPF, using HttpProxy proxy, want to know how to pass the server-side exception back to the client?
I set the Csla. ApplicationContext. DataPortalReturnObjectOnException = true attribute, don't work
One of the challenges with our current multi-platform world (specifically .NET Framework and .NET Core), but also with server-side dependencies like EF that won't be on many clients, is that the actual exception from the server can't be duplicated on the client.
To overcome this, the DataPortalException includes an ErrorInfo property. This property contains as much information about the exception stack as we can grab.
It is also the case that if you use ToString against a DataPortalException that you should get a pretty useful stack trace, including the exception information from the server (but again, not the actual exception object).
@rockfordlhotka Thanks for your reply. I have solved the problem according to your instructions. Thanks again!
Hi @rockfordlhotka , do you know if the ex.BusinessObject is passed back (or null) in your gRPC protocol?
Thanks! Brian
In CSLA 5 (actually this started in 4.something) the default is that the BusinessObject property is never populated. You have to enable that feature to have it populate, because it can consume a lot of bandwidth and almost nobody used the value, so it was a waste.
This is independent of the data portal channel, and applies to the data portal itself for all channels.
Thanks Rocky. To enable that, I would simply use this: ApplicationContext. DataPortalReturnObjectOnException = true;
If so, that doesn't seem to be working using HttpProxy, whenever I trap the DataPortalException the object is always null. It does return the object when running locally. I've also tried passing the object into the exception within the DataPortal but that didn't work either.
Here's my dataportal code:

And here's the code on the client, note that the BusinessObject is null...

I believe you need to set that on both client and server.
Yes, I've done that. First line of the DataPortal_Insert() is on the server, and also right before the await base.SaveAndMergeAsync(), but you can't see it in the code above.
To us, this is a great feature (getting the BO back with broken rules) as we only need to rebind our object and the UI informs the user what happened.
I know you've mentioned that there's bloat coming back from the server but can you elaborate? To me, it seems the same. If you have to get the object back because of a duplicate key (as an example), is grabbing it via a DataPortalException really that much bigger?
The "bloat" is the serialized object graph.
Most people never use that property, so bringing back the entire serialized object graph (which could be megabytes of data) is very wasteful - bloat.
If you DO use the property, obviously that's not bloat, because you use the value, so passing that data over the network is worth it.
I don't know why setting the property isn't doing the right thing. There could be a bug though, as I'm not kidding when I say that almost nobody uses that return value. You could be the first to try since it became a configurable option.
Thanks for the response Rocky. This has made me think about how we've been doing this over (literally) the last decade or so.
If you can envision a Person object for the discussion here.
- Person has a unique email address.
- The Person table has a index in the database that is unique.
- When the Person object is created there is a property IsEmailUnique that is true.
- There is a business rule for IsEmailUnique = false with the error "This email address is already in use"
When we save a Person and there's already a person in the database with the same email address we get en exception from the database. We trap and detect that the unique index was violated, set a property IsEmailUnique = false, run business rules, and then re-throw the exception.
In the UI, we trap the DataPortalException, grab the BusinessObject and rebind it. Since the object that comes back from the server is no longer valid (and if it's new it is still considered new), this is displayed to the end-user in the form of an error icon to the right of the Email address textbox that says "This email address is already in use".
That's what we've done to date. It works well because we don't have to do anything special in the UI, just rebind it.
It sounds like it's not good to do this since we can no longer get the object (separate issue). Would you recommend creating a command object that checks if the email already exists and (if so) then set the rule, flag the object as still new, and return the object?
Expanding on this. Above describes a unique index violation. We also have cases where a reference constraint is violated when trying to delete. Say the PersonID is referenced on another table. We'd have to remember to use the command object to check all of this, or somehow get these constraints out of the database and check them all (we're using EF though, so not sure how we'd do that).
In my thinking here, it's OK to let the database tell the BO when things are bad...
For the constraint violation we:
- Define the a property IsInUse that is false by default
- Have a rule on IsInUse if true "This item is in use and cannot be deleted"
- Trap the exception in the DataPortal, set IsInUse = true, check rules.
- In the UI the ex.BusinessObject now has a broken rule with IsInUse. We bind this to the OK button.
@brinawebb , I normally use the business rules for this kind of functionality to prevent saving of the object before it even can go to the database.
I will have a business rule that will call a command object that will check if the email address is unique once the email property is changed.
I do the same for other database key violations.
To expand on this, my approach is not to rely on the database to check for any data violations, but to rely on the business rule system to make sure the object is valid before it even hits the database.
You will end up with a bunch of rules, but it does give you the best user experience, since the user can be notified immediately of any broken rules.
In your use case I will not even have a property IsEmailUnique. This will be covered by the business rule on the email property.
Thanks @JacoJordaan . What do you do when attempting to delete an object with many foreign key references?
@brinawebb , for objects like person I normally won't have the option to delete the object from within the object itself within the save.
I will have a separate command object that will do the deletion. You can choose to have an authorised rule in the command object to check if you can invoke the command object (to check if you can delete). The authorisation rule will have its own command object that checks if any relational integrity will be violated when you will try to delete. In this way the user will be prevented to delete.
The other way is to skip the authorisation rule. The delete command object will throw a database error and you can catch the error and report this to user.