-
We have a requirement where we would like to save invalid objects as drafts, we will persist this information to the database and allow you to continue where you left off - we will stop you from submitting if the object is invalid. How we set out to achieve this is to create a new instance of our object, where BusinessRules.SuppressRuleChecking is set to true on the DataPortal.Create. We then clone the in-progress, invalid object to the new object which suppresses rules. When calling .SaveAsync() the object is in a valid state, but a DataPortal exception is then thrown stating the object is invalid. I found the below issue that was worked on, but I cannot see any way to disable this functionality: #2649 @rockfordlhotka @TheCakeMonster I am sure I am missing something to disable this functionality, any ideas? CSLA version: 6.1 |
Beta Was this translation helpful? Give feedback.
Replies: 8 comments
-
Two things. First, I think you can simplify your overall process by overriding SaveAsync in your business class. It is this method that prevents the client-side data portal from saving an object graph because it is invalid. Second, I'll let @TheCakeMonster respond regarding the server-side rerunning the rules. I don't know that this behavior can be suppressed on a per-type basis. |
Beta Was this translation helpful? Give feedback.
-
Thanks for the quick response @rockfordlhotka , just implemented point 1 and it is definitely a much more elegant solution. Couple of lines of code as opposed to hundreds. As for the server-side rerunning, I am comfortable that we can suppress it throughout instead of per type. |
Beta Was this translation helpful? Give feedback.
-
The server-side rules are run in an interceptor. You can add/remove interceptors from the list during server-side configuration. You'll want to remove the existing interceptor that runs the rules. |
Beta Was this translation helpful? Give feedback.
-
I suppose you could also create an interface like |
Beta Was this translation helpful? Give feedback.
-
Thanks @rockfordlhotka , I was thinking the same regarding the interface. I saw the RemoveInterceptorProvider() method but it only accepts an index and not a type in V6.1, and I don't want to just blindly remove. |
Beta Was this translation helpful? Give feedback.
-
There be dragons - but I'll come back to that. No, there is no per-type opt out in the current interceptor. It's about them dragons - again, we'll come back to that. Changing Interceptors I would recommend using an extension method to do these modifications, as that keeps that bit of code self-contained. I must stress that in the vast majority of scenarios, you should not simply remove the revalidating interceptor and not replace it. That would leave your system wide open to people posting invalid data to your data portal endpoint - by bypassing your application completely - and that invalid data being accepted by the server. That's a big, big security risk. Huge. A Better Approach If you don't want to switch rulesets (I mean you do want to, that's exactly what you are doing, but if we ignore that for the moment) then another approach is to build a decorator rule that allows for a boolean test of the object's status before applying whatever nested rule you would normally use. Use this to wrap all of the other rules, so that they pass when the object is not really valid but it's OK to pretend that it is. This Boolean test I am talking about would be based on some status property you set on the object when this is the case. You could perhaps create a rule that accepts a lambda as part of the definition of the rule (a Func<BusinessBase, bool> for example) to make it really flexible and reusable - indeed, I wonder whether we should have that rule within the framework, but that's a thought for another day - perf and multi-threading both need considering. Using multiple rulesets feels like the best approach, to me. This does come with the disadvantage that you have to learn a more in-depth part of the rules engine. However, that knowledge will hold you in good stead in the future - and by applying that newfound knowledge, you would not have to make any other changes. There would be no need to override SaveAsync or change the interceptors that are used. Everything becomes a bit more, well, normal. Dragons, There Be Aplenty! At least try to provide some protection to the system by using a lesser ruleset, rather than an empty ruleset. |
Beta Was this translation helpful? Give feedback.
-
I think though, that the OP is looking to run the rules, but to just not prevent a save operation in the case of a draft object graph. There should be some reasonable way to do this, and I suspect the answer is to swap out the interceptor for one that uses an interface (or something) as I suggest. I do not think this is a great use for a ruleset - at the very least because this isn't the purpose for which rulesets were designed. They are designed around multi-tenant scenarios where a user typically has one active ruleset based on their identity (tenant). |
Beta Was this translation helpful? Give feedback.
-
@rockfordlhotka @TheCakeMonster we went with the solution as suggested by Rocky: We remove the Interceptor, then add our own implementation of the same interceptor, the only difference being our version checks if the object is of type ISavableDraft, if so, it does not revalidate server side if the object is currently in draft mode. Thank you for the help ad the continued support of this amazing framework. |
Beta Was this translation helpful? Give feedback.
@rockfordlhotka @TheCakeMonster we went with the solution as suggested by Rocky:
We remove the Interceptor, then add our own implementation of the same interceptor, the only difference being our version checks if the object is of type ISavableDraft, if so, it does not revalidate server side if the object is currently in draft mode.
Thank you for the help ad the continued support of this amazing framework.