I’m attempting to build an INSERT database Sharp API page. I’m trying to follow along with the blog post example of executing the INSERT statement, but I can’t figure out how to reference a JSON request body from within the script.
Let’s say I POSTED something like:
{
"name":"name1",
"value":"value1"
}
How would I reference each of those fields? I tried @name, @value, but that didn’t seem to work.
In this case the there’s no default script methods for accessing the Request Body InputStream (I’ve added some in this commit), so you’ll need to add your own Script Methods in your Plugin.dll where they’ll automatically get registered when the plugin is loaded, e.g. you can access it with something like:
public class MyScripts : ScriptMethods
{
internal IRequest req(ScriptScopeContext scope) =>
scope.GetValue(ScriptConstants.Request) as IRequest;
public async Task<object> requestBodyAsJson(ScriptScopeContext scope) =>
JSON.parse(await req(scope).GetRawBodyAsync());
}
Which you should be able to access by assigning it to a variable which will let you use the resulting Object Dictionary, e.g:
As you’re going to be developing Sharp Apps you’ll need to familiarize yourself with the Scripts API Reference listing all the built-in Script Methods available.
Alternative Solution use HTML Form POST
Alternative solutions is to use the standard HTTP POST variables as submitted with all HTML Form Posts, you can find the form* script methods by searching the API Reference for form, where the POST’ed Form key/value pairs is available from form, formDictionary, formQuery(field) and formQueryValues(field) APIs. The formQuery* APIs looks for the field in both QueryString & Form.
Use Scripting APIs to inspect objects
Finally the Scripting .NET APIs lets you use reflection to access an objects methods/fields/properties which you could use to inspect the httpRequest object, but it’s typically easier & more reusable to use C# to access them in your own Script Methods.
Learn about existing Script Methods
To learn about what each Script Method does & learn about how to go about creating your own have a look at the source code for the default scripts in ServiceStack.Common/Script/Methods with the scripts around HTTP Request APIs in DefaultScripts.Web.cs and the higher-level ServiceStack Related APIs in ServiceStackScripts.cs.
Did you dump the dto {{ dto |> dump}} or have a look at the SQL string that was generated? Because your string interpolation is wrong (uses JS template literals), something that should’ve been clear after some inspection.
Also to protect yourself from SQL Injection you should be using parameterized values instead, e.g:
`SELECT *, 1 as TestField FROM test_model WHERE name = @value`
|> dbSelect(dto)
|> return
Doesn’t seem to be doing anything. I’m suspecting the requestBodyAsJson in my custom MyScripts isn’t getting triggered. What am I missing? I know the plugin dll itself is working because it contains that ChangeDbFeature we worked on that other day and that IS working.
have a look at the SQL string that was generated
How would I do that?
Also, did I need to update my ServiceStack references? You mentioned you added this to a commit but I’m not sure if that meant it was actually released yet?
This is what my Plugin looks like. Maybe I’m missing some code to wire up the MyScripts?
using ServiceStack;
using ServiceStack.Script;
using ServiceStack.Web;
using System.Threading.Tasks;
namespace MyScriptPlugin2
{
public class ChangeDbFeature : IPlugin
{
public void Register(IAppHost appHost)
{
appHost.PreRequestFilters.Add((req, res) => {
var db = req.QueryString["db"];
if (db == null) return;
req.Items[Keywords.DbInfo] = new ConnectionInfo
{
ConnectionString = $"Server=localhost;User Id=postgres;Password=admin;Database={db};Pooling=true;MinPoolSize=0;MaxPoolSize=200",
//ProviderName = "postgres"
};
});
}
}
public class MyScripts : ScriptMethods
{
internal IRequest req(ScriptScopeContext scope) =>
scope.GetValue(ScriptConstants.Request) as IRequest;
public async Task<object> requestBodyAsJson(ScriptScopeContext scope) =>
JSON.parse(await req(scope).GetRawBodyAsync());
}
}
This isn’t helpful, what exactly is it printing out, what does {{ dto |> typeName }} return? Did you try debugging it in your Test App with your plugin, is your requestBodyAsJson method getting called, are you able to use any of your other custom script methods?
The x tool and MyGet have been updated, dotnet tool -g update x will tell you if it’s updated to a newer version, you can find out what script methods by creating a simple script:
$ x lisp
> (globln "request*" (map .Signature scriptMethods))
If it’s updated in the x tool it’s likely also updated on MyGet, update the MyGet pre-release packages to check in your test app, if the new API exists on sharpscript.net it’s verified that it’s on MyGet.
Still not returning anything. That ?req.GetRawBody() I dumped out earlier was from the ChangeDbFeature code block, not the MyScripts code block. I’m suspecting the MyScripts code block is not running. It also seems that the commit and subsequent update you made to the API with requestBodyAsJson isn’t working.
ok the request body needed buffering, it will be empty after the body has been accessed which I’ve added in this commit.
The x tool has also been updated to 0.0.25 with this change, NuGet takes a while (up to 20mins) to index new packages before dotnet tool update -g x will update to the new package.
Seems the difference may be running the site with x vs web. Works with x, not with web. What’s the difference? I need to run it with web because I will be running a full .net core web app such as with your x new script template.