Pass User-defined parameter in Elsa WorkFlow - elsa-workflows

I want to pass project_Cost (input parameter) in this Elsa WorkFlow Builder APi
public void Build(IWorkflowBuilder builder , int project_Cost)
{
}
Currently, it's giving an error because Build method doesn't have a second user-defined input parameter
how to pass this parameter, is there any other method there in Elsa WokFlow to pass custom user-defined input parameter
?
So, if I invoke https://localhost:44302/ProjectStatus?project_Cost=15000
then Elsa WorkFlow activates and passes 15000 as an input parameter value

The builder API is designed to define workflow blueprints, and it doesn't make sense to pass parameters to it.
For your use case you can take advantage of Http endpoints activity and there's a sample on the repo that I guess is close to what you need.
Something like the following:
public void Build(IWorkflowBuilder builder)
{
builder
// Configure a Receive HTTP Request trigger that executes on incoming HTTP GET requests.
.HttpEndpoint(activity => activity.WithPath("/ProjectStatus").WithMethod(HttpMethods.Get))
// Store the parameter as a workflow variable
.SetVariable(context => ((HttpRequestModel)(context.Input))?.QueryString["project_Cost"]))
// Then whatever you need to do with the parameter
}

Related

async Lambda invocation from Api Gatway with parameters

I have an Api Gateway GET method called /tasks/{tasktype}
It's pointed to a Lambda function with the X-Amz-Invocation-Type set to 'Event'
Then in my Lambda I have this
public void FunctionHandler(Object input, ILambdaContext context)
{
LambdaLogger.Log($"GOT: {input.ToString()}");
}
This all works fine, except input is null.
Is there any way I can pass through and access the value of {tasktype} from the Api Gateway?
Thanks
You need to pass them in using either a mapping template or check the box for "Use Lambda Proxy integration".
Mapping Template reference:
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
Proxy Integration reference:
https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html

Yii's CController::forward() can specify parameters to pass to the action?

I want to use CController::forward() instead of redirect or instantiating the controller and directly calling the action, because this way Yii::app()->controller->action->id correctly shows the action that ultimately ran.
Although I don't see in the documentation how to specify parameters to pass to the forwarded action, because the $route parameter is a string, not an array.
public function actionIndex() {
$this->forward('/otherCtrl/view'); // how to pass a parameter here?
otherController.php:
public function actionView( $id ) {
//get the id here
Parameters injected into action method comes from $_GET. So if you need to pass $id into forwarded action, you need to set value in $_GET array:
$_GET['id'] = 'some id';
But using forward() is basically always a sign of bad design of application - I suggest to extract shared logic into separate method/component, and avoid using forward() or calling controller actions directly.
You can try:
$this->forward('/otherCtrl/view/id/'.$id);
Query string depends on your URL settings.

Web API - JObject from URI

Web API allows me to capture the body of a POST request in a JObject:
$.post('/api/Query/DoSomething', { Foo: "one", Bar: 4 });
public string Post(JObject data)
{
// data is populated
}
However the same technique does not work with a get request and URI parameters.
$.get('/api/Controller', { Foo : "one", Bar : 4 });
public string Get([FromUri]JObject data)
{
// data is empty
}
Any workaround here?
It doesn't work because a GET request does not have a body, and hence no content type. Therefore, Web API does not know that you have JSON in your URL. You have a few choices:
Pass your data as query string parameters, as is traditionally done in GET requests, and change your method to accept those parameters individually, or in a regular class (POCO).
Change your GET method to accept a string instead of a JObject, then use JSON.Net to deserialize it manually, e.g. JObject obj = JObject.Parse(data);
If you're feeling ambitious, you might be able to implement a custom binder to do this.
My recommendation is option 1. Traditionally, a GET method is just intended to look something up, so you really should only be passing IDs and simple query options anyway. It is unusual to be passing JSON data in a URL. Also the length of URLs can be limited by some browsers. If you find you are needing to pass JSON data, use POST (or PUT) instead.
You can create an object and bind to it using the FromUri.
Check out this solution which I am using https://stackoverflow.com/a/49632564/2463156.

How to enforce Grails command objects have been validated?

We use the following general pattern with Grails controllers and command objects
SomeController {
def someAction() {
SomeCommandObject co = SomeCommandObject.valueOf(params)
if(!co.validate()) {
// return bad request
}
someService.doWork(co)
// return ok
}
SomeService {
def doWork(SomeCommandObject co) {
notTrue(!co.hasErrors(), 'cant have errors') // Commons validation
// do actual work
}
}
Apparently, if co.validate() has not been called, .hasErrors() will always return false. Is there a better way to enforce that .validate() has been called before a command object is passed between application layers? We don't want to pass around invalid command objects but we don't want to force every new method to re-validate the command object either.
Note: We aren't using the default controller/command object creation pattern because we need to do some custom parameter map checking, we use a static valueOf method instead to create the command object. Answers that change that practice are also welcome.
EDIT: A little more info on why we aren't using the 'default' controller/command object creation. Specifically why we aren't doing ..
def someAction(SomeCommandObject co) {
}
We have a requirement to disallow random query parameters, eg. endpoint/object?color=blue. To do that we need access to the parameter map in the command object to verify that it doesn't contain any 'unexpected' parameter keys. As I understand it, the default way would just create a member on the CO named color, and I don't see how to prevent arbitrary members using even custom validators. I'd happily entertain suggestions for doing so, thereby allowing us to use this default means.
Yes; what you can do is pass the command object as a parameter to the controller, and then the command will always be validated automatically.
Also, what you can do, is to make a filter or similar, so that you don't have to check for the hasErrors() each time, but handle all the cases in the same way (for example, by throwing an error, or returning with a specific response).
In an application we created, we had something like:
withValidCommand(cmd) {
// do work
}
Which worked pretty well. But maybe you can come up something even more elegant.
You should be doing this:
def someAction(SomeCommandObject co) {
if (!co.hasErrors()) {
someService.doWork(co)
}
}
By passing SomeCommandObject in as the argument grails will automatically populate it from params and validate. No need to do it manually.

On Asp.net Web Api authorization filters, how can I access to parameters?

I'am starting with Asp.Net Web API and here's my problem :
I implement a custom authorization filter to inspect my message header looking for an API Key. Based on this API Key, I retrieve my user and then I would like to see if he can have access to some resources. The resources ID I want to check is on the parameters of the HTTP request. But when I'am on the AuthorizationFilter method, the actions parameters list is empty.
How can I do that ?
If I used an ActionFilter in replacement of an authorization filter, how can I be sure that this will be the first filter executed ? And globally, how can I specify the executing order of filters ?
Last question, is it possible to add some data "on the pipe" that I could retrieve on any filter ? Something like a session store but limited to the request ?
Thanks for any response
The authorization attributes run before parameter binding has run therefore you cannot (as you have seen) use the ActionArguments collection. Instead you will need to use the request uri for query parameters and route data for uri parameters as demonstrated below.
//request at http://localhost/api/foo/id?MyValue=1
public class MyAuthorizationAttribute : AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{
//will not work as parameter binding has not yet run
object value;
actionContext.ActionArguments.TryGetValue("id", out value);
//Will get you the resource id assuming a default route like /api/foo/{id}
var routeData = actionContext.Request.GetRouteData();
var myId = routeData.Values["id"] as string;
//uri is still accessible so use this to get query params
var queryString = HttpUtility.ParseQueryString(actionContext.Request.RequestUri.Query);
var myQueryParam = queryString["MyValue"];
//and so on
}
}
About the execution order:
There are 3 different ways of specifying the execution order of filters using the FilterScope Enumeration... scope being Global, Controller and Action. The AuthoriseAttribute is "Global" and therefore it
Specifies an action before Controller.
If you needed to specify the execution order within these 3 scopes then you should read this blog article here where you will need to implement a FilterProvider
To add some data to the pipe:
Use the properties collection on the request this collection is available for the duration of the request.
protected override bool IsAuthorized(HttpActionContext actionContext)
{
actionContext.Request.Properties.Add("__MYKEY__","MyValue");
//access this later in the controller or other action filters using
var value = actionContext.Request.Properties["__MYKEY__"];
}
Another alternative to get to the parameters is to Execute the binding for the parameters.
try
{
var binding = actionContext.ActionDescriptor.ActionBinding;
var parameters = binding.ParameterBindings.OfType<ModelBinderParameterBinding>();
var newBinding = new HttpActionBinding(actionContext.ActionDescriptor, parameters.ToArray());
newBinding.ExecuteBindingAsync(actionContext, new CancellationToken());
var id = actionContext.ActionArguments["id"] as string;
}
catch
{
base.HandleUnauthorizedRequest(actionContext);
}
Note: You need to make sure you only filter on the parameters that will come from the Request URI, as I have noticed that executing the binding for any parameters that are expected to come from the Request body will no longer be passed on to the actual action. i.e. those parameters will be null.
This is just to note that you can do this, I'd recommend using GetRouteData()/RouteData as it is not likely to disrupt the further flow of ASP.NET MVC modelbinding.
var routeData = actionContext.ControllerContext.RouteData;
var id = routeData.Values["id"] as string;

Resources