OrchardCore: Importing workflows with starting HttpRequestEvent does not register URL

Describe the bug

If you “Export all Workflows” in a deployment plan, save the recipe json file, go to your deployment target site, and use Packages Import to load up the recipe file, it will successfully port the workflows over. However, I noticed that I would get 404 Not Found errors when attempting to post to my workflows after loading the recipe. I cross-referenced the URL/token between sites in my javascript $.ajax(...) call and the URL displayed in the edit page for the HttpRequestEvent activity, but they were identical. It was stored properly in the Document table of the database as well. It was only after regenerating the URL and copy-pasting the new URL into my javascript that the event started triggering properly.

So, something about the process of saving an HttpRequestEvent actually generates a route with the token, and while the recipe step is properly reproducing all serialized information, it is not updating the in-memory information of that route. Haven’t yet traced what/how that is happening though.

To Reproduce

Steps to reproduce the behavior:

  1. Create a workflow with a starting HttpRequestEvent activity.
    • In my case I did POST with antiforgery and had a form that submitted to it, but I suspect a GET request with no antiforgery would work too, for easier testing.
  2. Create a deployment plan to export workflows. Run it to save a local file of the recipe.
  3. Go to another tenant. Import the Package to run the recipe and it should be recreated perfectly in the database/UI.
  4. Test the workflow and notice that it DOES NOT handle the request properly, returning a 404 instead.

Expected behavior

HTTP-related events that generate routes should preserve said routes to make them immediately available during recipe import.

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 1
  • Comments: 18 (8 by maintainers)

Most upvoted comments

Suggest looking in the database to be sure that the url value has actually changed.

I confirmed that the database does indeed update. My local Sqlite instance shows the updated data and if I go to the edit page of the activity, it also displays the updated URL. So the data is definitely getting updated within the database correctly.

What IS strange though (cause I was sure I had checked it), is that the LiquidFilter is putting out the same value that is in the database, but the value is still not counted as valid on POST. So despite the fact that I’m generating the token based on the same parameters the HttpWorkflowController is, it doesn’t decrypt properly. I can only think that I must just not be building the token correctly somehow.

The use of the .Wait() and .GetAwaiter() in both methods will cause you problems. Suggest just using await

Mk. Done (though no difference of course).

I’m not 100% confident that activity.Properties[“Url”] = newUrl will update the entity correctly. Normally we use .As() and .Put() extensions

The As and Put extensions don’t appear to work when I am trying to extract a string or JValue. I get a compiler error about those types not having a parameterless constructor and therefore not being valid generic parameters (which…is weird).

a http request event does not necesarily need to be the starting event, it can come later from a resumed workflow

Ah! Didn’t think about that (and haven’t had a chance to read the other PR yet). Will have to take a look at that and also revise my stuff to not make that assumption. Still, yes, unrelated to my current issue.


Ahhhh, I found it! I just wasn’t plugging in the right value for the token lifespan. HttpWorkflowController slips in a large number if the value is 0 (which my activities’ are), so I have to do the same thing when extracting any 0 values from the activity entities in the recipe step. Now the liquid filter’s generated URL is working properly.

Edit: Updated code example…

// recipe step
var newToken = _securityTokenService.CreateToken(new WorkflowPayload(w.WorkflowTypeId, activity.ActivityId), TimeSpan.FromDays(tokenLifeSpan == 0 ? HttpWorkflowController.NoExpiryTokenLifespan : tokenLifeSpan));

Personally, I’m using the WorkflowManager to retrieve these workflow url’s

Same. I wrote a ILiquidFilter that lets me pass in the name and get the workflow URL (although, geez, your solution was a lot simpler than mine. Steals <_<). I could probably open a pull request to add it at some point.

var servicePath = "{{ Request.Scheme }}://{{ Request.Host }}{{ "My Starting Event Name" | workflow_url }}";

Something like that anyway. I’ll probably switch to your workflow name approach though (would’ve preferred that, but couldn’t figure it out at first).

Just a heads up, this only updates the token. If you wish to update the full URL, e.g.for cases where you change the app name, you will need to generate it using LinkGenerator.GetPathByAction, and the area parameter set to OrchardCore.Workflows.

Yeah just {{ "Your Workflow Name" | workflow_url }} and 🚀

So, yeah maybe we should have a step or, it should self test itself and regenerate a url as soon as it see it’s faulty.

I think the token is generated by using the current DataProtection key. So, if you are exporting it to a different tenant that doesn’t use the same DataProtection key ; the url won’t work.

So, it is “by design”. Though, everyone would expect that their workflow works instantly, I reported the same issue a while ago and I think @sfmskywalker said that this was definitely an issue that could be fixed. Right now, the issue is that if you pasted the url in your form directly, if you regenerate the url, you need to update it also everywhere you want to use it.

Personally, I’m using the WorkflowManager to retrieve these workflow url’s

    var workflowType = await session.Query<WorkflowType, WorkflowTypeIndex>(w => w.Name == "Your Workflow Name").FirstOrDefaultAsync();
    var formActivityRecord = workflowType.Activities.Single(x => x.IsStart);

    <form method="post" action="@formActivityRecord.Properties["Url"]">