If you don’t want to recompile you’ll need to store the #Script
outside of the code-base, e.g in a remote AppSettings configuration source otherwise you’ll need to fetch it yourself in the DataSource your App is using (e.g. a Validation Scripts table).
To execute a script you can either use your App’s SharpPagesFeature
context gives your scripts access to the same functionality as your #Script Pages, otherwise you can execute them in an empty sandboxed context, e.g:
var context = HostContext.GetPlugin<SharpPagesFeature>();
var context = new ScriptContext().Init(); // empty sandboxed context
Then there is a matter for where to execute them, if you execute them in a Request Filter then you’ll be paying for an I/O request to fetch the script for each request, instead I’d add the #Script execution code in a base class OnBeforeExecute() method that is only inherited by Services which use dynamic validation that way the lookup only occurs for Services that have dynamic validation.
In this case I would execute the Script using a PageResult
directly passing in the Request DTO into the PageResult.Model
which will allow properties of the Request DTO to be accessed using just the property name Name
as well as from the model.Name
. Since your not interested in the output of the Service I’d just render it to a null stream as you’ll only be interested if Script throws an Exception:
public class DynamicValidationServices : Service
{
public override void OnBeforeExecute(object requestDto)
{
try
{
// check if there's a script for this service
var script = TryResolve<IAppSettings>().GetString(
$"script.{requestDto.GetType().Name}.validation");
if (script == null)
return;
var context = HostContext.GetPlugin<SharpPagesFeature>();
var pageResult = new PageResult(context.OneTimePage(script)) {
Model = requestDto
};
pageResult.WriteToAsync(Stream.Null);
}
catch (ScriptException e)
{
throw e.InnerException ?? e;
}
}
}
Now you can write some #Script to validate your Request DTO whose properties you can access via Model.Prop
or Prop
, here’s a couple of examples:
```code
['Name','Age'] | to => requiredProps
#each requiredProps
#if !model[it]
it.throwArgumentNullException()
/if
/each
(Age < 13) | ifThrowArgumentException("Must be 13 or over", "Age")
```
You can find different Exceptions you can throw from #Script Error Handling Page, you’ll likely also want your scripts to access some common validation functionality which you can make available in your scripts with:
var pageResult = new PageResult(context.OneTimePage(script)) {
ScriptMethods = { new MyValidationScripts() },
Model = requestDto
};