►
From YouTube: Elsa Workflows Community Meeting 32
Description
- Refactored JSON serialization
- Workflow Contexts
- Tooltips fixed by @Daxton (#3845 Tooltip Fixed Positioning by Daxton47 · Pull Request #3920 · elsa-workflows/elsa-core (github.com))
- Tests
- Installed features
- Roadmap to RC
A
A
B
A
B
Good
good
busy
I've
been
quite
busy,
actually
yeah,
it's
good,
so
yeah.
So
let's
Jump,
Right,
In
good,
starting
with
the
agenda
I
already
added
a
couple
of
items,
some
stuff
that
I
did
over
the
past
week
some
demos
to
to
show
some
topics
to
talk
about.
B
So
it's
just
a
name
could
have
could
as
well
have
been
just
value
but
an
island.
It's
it's
like
a
bit
of
Json
embedded
in
the
overall
Json
documents.
So
but
it's
it's
not
part
of
the
same
structure.
It's
it's
considered
to
be
opaque
data.
So
I
called
it
like
the
data
Islands,
but
I,
don't
know
if
the
term
is
accurate,
but
I
thought
it
was.
B
It
sounds
so
cool,
so
I
used
the
island,
but
if
you
think
it's
odd
I'm,
I'm,
okay
with
changing
it,
but
today
I've
worked
on
an
issue
that
was
reported
by
a
customer
and
they
it
turned
out.
So
so
let
me
explain
the
issue
just
briefly:
if
they
are
testing
elsa3,
they
are
using
it
in
their
own
environments
and
with
with
integrating
with
their
own
application,
and
they
have
activities
that
perform
Transformations.
So
they
map
Json
from
one
format
to
another
or
one
shape
to
another
shape,
but
they
were
complaining
about
serialization
issues.
B
So
whenever
a
fault
would
occur
in
their
workflow
and
they
try
to
open
the
instance,
it
would
fail
to
open
because
serialization
error
occurred
with
with-
and
this
is
to
do
with
this
refactoring
here,
which
introduces
a
custom
Json
converter
that
supports
polymorphism.
So
we'll
talk
about
that
in
a
second,
so
I
started
to
look
into
this
issue
and
it
turned
out.
B
They
are
using
Newton
soft
J
objects
to
serialize
and
deserise
or
store
Dynamic
data
in
the
in
the
context
of
their
own
custom
activities
or
custom
activity
can
have
custom
data
stored
in
a
dictionary
called
custom
property.
So
it's
just
a
property
back
really
it's
a
dictionary
bit
of
string
object
pairs
and
they
were
storing
A
J
object
in
that,
but
this
custom
converter
that
I
mentioned
this
polymorphic.
Obviously
converter
was
trying
to
serialize
it,
but
J
object
isn't
serializable
to
a
certain
extent.
B
But
then,
when
you
try
to
deserialize
it,
just
it
just
fails
with
some
exception:
I,
don't
recall,
which
one
exactly
so
it
it's
not
very
suitable.
So
so
then
I
made
an
update
to
specifically
handle
J
object
instances
and,
if
I
encounter,
if
the
converter
encounters
A
J
object,
it
will
just
stringify
it
and
store
that
string
in
this
island
property
that
you
discovered
and
also
the
other
way
around.
B
If
it's
going
to
be
deserialized,
it
will
see
that
it's
a
j
object
and
then
parse,
that's
Json
Island
into
a
j
object
instance
and
the
point
of
this
custom
polymorphic
object.
Converter
is
to
be
able
to
round
trip
objects
to,
and
from
Json
and
and
maybe
you're
thinking.
Well,
that's
not
very
exciting.
I
mean
that's
what
we
do
on
a
daily
basis
right,
but
this
is
about
having
object.
Graphs.
That,
for
example,
have
properties
of
type
object
which
could
contain
arbitrary
items
or
an
objects.
B
Point
is
if
you
serialize
that
without
any
custom
converters,
and
then
they
serialize
it,
it
will
not
deserialize
it
into
the
original.net
type,
but
it
will
deserialize
it
into
a
Json
objects
or
Json
elements
and
which
is
not
what
what
we
want.
We
want
to
be
able
to
reconstruct
the
original
object
instance
of
the
actual
type.
So
you
need
to
to
also
serialize
the
type
information
about
the
objects
being
serialized.
So
that's
this.
That's
a
one
part
of
the
refactoring
of
Jason
serialization,
but
the
reason
I
started
this
process
is
is
before
this
change.
B
If
you
would,
in
a
serialize
a
workflow
instance
that
contains
variables
and
activity
inputs-
and
let's
say
they,
there's
two
ref
two
object
references
pointing
to
the
same
object
and
serialize
it.
Then
this
object
will
be
serialized
twice
or
how
many
number
of
references
you
would
have
that
number
would
the
object
would
be
serialized
that
number
of
times
in
the
Json
output,
so
that
could
be
very
inefficient.
If
you
have
a
you
know,
large
dtos
and
they're
referenced
multiple
times
it
could
blow
up
your
Json
output
significantly.
B
So
this
fixes
that
by
using
references,
so
if
the
Json
serialized
encounters
the
same
object
already
being
serialized
or
that
was
already
serialized
instead
of
serializing
it
again,
it
will
now
output
a
reference
ID
like
in
Newton
soft
Json
there.
It's
it's
a
simple
option
that
you
can
enable
system
text
Json
you
can
enable
it
as
well,
but
in
combination
with
the
polymorphic
converter,
I
had
to
do
a
bit
of
extra
work
yeah.
B
So
it's
it's
a
big
refactoring,
but
now
it's
it's
quite
nice
if
I
do
say
so
myself
and
I'm
particularly
pleased
with
the
ability
to
just
be
able
to
Output
arbitrary
objects
that
are
typed
as
objects
in
in
the
workflow
state,
for
example,
and
then
it's
deserialized
and
plus
the
fact
that
it
now
renders
the
refs
instead
of
the
full
object.
So
so
yeah,
it's
pretty
good,
but
you
know
there
may
be
a
few
bugs
I
encountered
a
few
bucks
during
past
week
discovered
by
this
user
and
well
it's
looking
good
now.
B
Maybe
we
can
take
a
quick
look
at
at
an
example.
So
here
maybe
we
have
some
data,
so
this
is
the
island
thing
that
that
this
this
customer
encountered.
So
let
me
open
it
in
a
scratch
file
here.
So
what
do
we
have
here?
We
have
IDs,
so
these
are
object,
reference
IDs,
so
that
whenever
this
object
will
be
referenced
elsewhere,
it
would
have
ref
to
this
this
one.
So
that's
why
we
know
cids
in
word,
for
it
states
only
it's
not
included
with
other
objects.
B
Like
word
for
definitions,
because
there
it's
not
necessary
and
also
for
the
designer-
it's
not
very
convenient
to
have
this
format.
So
it's
that's
another
part
of
the
refactoring,
where
the
implementation
of
serialization
it's
more
focused
and
instead
of
having
one
shared,
serialization
object
options:
provider.
There's
there
are
now
specialized
abstractions.
B
So
there's
a
workflow
State
serializer,
there's
a
payload
serializer,
there's
a
word
for
definition,
serializer,
so
that
it's
also
less
confusing
to
understand
which,
when
to
use
what,
because
before
this
chains,
there
were
various
methods
on
the
serialization
options,
provided
that
were
kind
of
vague.
So
it's
it
was
always
a
little
bit
of
a
puzzle.
B
It's
one
to
use,
and
it's
good
and
more
seriously,
that
that's
also
more
prone
to
error
when
you,
when
you
use
those
methods-
and
maybe
at
some
point
you
change,
because
you
run
into
some
some
serialization
issue
and
then,
if
you
could
then
make
a
change,
then
you
don't
know
what
else
you
may
be
affecting
so
in
any
ways
that
that's
better.
This
also
ties
a
little
bit
into
automated
tests,
there's
more
test
coverage
now,
which
we'll
take
a
look
at
later
on
as
well.
B
So
here,
let's
see
so
here
here
we
see
the
the
error.
That
is
this.
This
customer
encountered,
which
is
and
I
simulated
by
just
return,
throwing
an
error
from
from
a
JavaScript
activity
just
to
to
see
what
happens
with
the
serialization.
But
this
is
all
looking
good
and
then
oh,
this
is
not
the
right
example.
It
seems.
Oh,
this
is
not
the
customer
scenario.
B
This
is
a
different
test
case,
but
let's
see
if
I
can
find
it
so
here
this
is
a
Json
string
that
they
are
embedding
in
their
own
custom
activity,
so
they
have
a
workflow
and
then
they
have
a
custom
activity
that
has
an
output
called
Trends,
which
is
short
for
transformation
so
then,
and
that
is
of
type
J
object.
So
whenever
now
the
serialized
encounters
A
J
object.
B
It
will
serialize
that
Json
string
in
this
field
and
the
type
which
is
J
object,
and
then
it's
able
to
round
trip
as
well,
but
but
instead
of
just
deserializing
using
this
type,
as
you
would
normally
do
using
system
text-
Json
Json
converter
here
it.
It
specifically
looks
for
this
type
and
if
it
Encounters
this
type,
it
will
just
do
J
object.parse
and
then
the
parsing,
the
string
so
yeah.
That's
that's
everything.
I
have
to
say
about
Islands
next
topic,
workflow
context.
This
is
not
a
new
feature
in
elsa3
it.
B
It
was
added
some
time
ago,
but
it
wasn't
really
finished
and
there
were
there
was
for
a
brief
moment.
There
was
a
sample
application,
but
it
wasn't
really
complete.
So
at
some
point,
I
removed
that
and
then
a
user
in
the
community
asked
about
do
we
still
have
it
in
Elsa
3
and
is
there
any
documentation
or
something
like
that
which
there
wasn't
so
I
created
an
issue
as
I
started?
B
Reconstructing
the
sample
application
I
encountered
a
couple
of
missing
fun
features
of
workflow
context,
so
I
added
those
and
I
would
like
to
to
show
you
what
it's
about
out
and
how
it
works
and
just
just
to
summarize
what
is
a
workflow
context
in
this
context?
Imagine
you
have
a
a
workflow
that
deals
with
customers.
So
what
would
you
normally
do
out
of
the
box?
You
would
probably
have
an
activity
that
loads,
a
customer
by
some
identifier
which
could
be
a
correlation,
ID
or
some
other
value
doesn't
matter.
B
Maybe
you
perform
some
operations
so
the
workflow
executes.
Maybe
you
read
some
information
from
the
customer
or
update
some
settings
on
the
customer?
Maybe
the
workflow
goes
to
sleep.
Maybe
you
have
a
timer
and
then
at
some
point
you
want
to
resume
the
workflow
and
at
that
point
either
you
know
you
could
store
this.
The
user
object
or
the
customer
object
in
workflow
state
or
some
other
source
provider
which
at
that
point
it
would
automatically
be
loaded,
but
maybe
you
don't
want
this
stale
object?
B
Maybe
you
just
want
to
have
a
fresh
copy,
always
from
the
database
whenever
the
workflow
executes
or
resumes
and
that's
where
workflow
context
providers
come
in.
It's
like
just
provided
that
executes
before
your
workflow
execute,
so
it
provides
context
to
your
workflow
in
the
background
or
aim.
You
know
like
ambient
values.
That's
just
available
to
your
workflow
without
having
to
have
workflow
variables,
declared
in
your
in
your
workflow
definition.
So
a
context
provider
is
it's
very
it's
a
very
simple
API.
If
you
implement
one,
you
have
just
two
methods
to
implement.
B
One
is
to
load
your
context,
which
could
be
any
domain
object
you
like,
so
it
could
be
a
customer.
It
could
be
a
document
or
whatever
makes
sense
in
your
scenarios
and
then
it
also
provides
a
safe
method.
So
if
your
workflow
makes
changes
to
your
domain
object,
you
don't
have
to
manually
persist
in
your
database.
That
would
be
the
responsibility
of
this
context.
Provider
that
you
do
have
to
implement,
but
it's
automatically
invoked
by
the
the
runtime.
That's
the
point.
B
So
what
does
that
look
like
here?
There's
here,
I,
have
an
example:
implementation,
it's
a
class
that
ultimately
implements
I,
workflow
context
provider,
which
is
a
very
simple
interface,
as
I
mentioned.
Just
you
have
a
Lotus
Inc
and
a
safe
async,
and
you
get
access
to
workflow
execution
context.
For
you
know,
in
order
to
to
know
what
customer
you
want
to
load,
how
do
you
determine
this
one?
Probably
some
information
you
associate
with
your
workflow
instance
through
a
correlation
ID
or
maybe
even
through
a
custom
property
and
that's
the
default.
That
looks,
looks
like
this.
B
Actually
so
so
here,
I
have
a
sample
context
provider
that
loads
customers
from
some
custom
store
that
I
have
here
and
then
in
the
load,
I
think
what
I
do
I
I
call
get
customer
ID
on
workflow
context,
a
word
for
execution
context,
but
Elsa,
of
course,
doesn't
know
anything
about
customers.
So
this
is
just
an
extension
method
in
the
same
sample
project.
So
it's
an
extension
on
workflow
execution
context
that
internally
calls
a
new
method
called
get
workflow
context
parameter,
and
this
is
provided
by
the
workflow
context.
Module
so
to
be
clear.
B
Workflow
context
is
an
add-on
module
that
you
can
opt
into
which
you
can
enable.
So
it's
not
available.
If
you
don't
enable
it
when
you
ins,
when
you
use
the
workflow
context
module,
then
you
get
this
extension
method.
That
internally
looks
like
this.
Yes,
so
so
the
the
it
just
reuses
the
workflow
context,
execution,
custom
properties
dictionary.
So
if
I
do,
if
I
dig
into
the
get
property,
then
what
it's
doing
it's
it's
just
trying
to
get
a
value
from
the
properties
dictionary,
so
any
activity
or
your
custom
modules
and
activities.
B
They
all
have
access
to
this
property
back
and
you
can
store
application,
specific
values
and
the
workflow
context
module
takes
advantage
of
that
extensibility
points.
But
anyway,
let's
let's
get
back
to
to
this,
get
customer
ID.
So
here
it
uses
this
get
wordflow
context
parameter
just
to
explain
what
is
a
workflow
context
parameter.
This
will
be
your
customer
ID,
for
example,
or
document
ID
or
whatever
ID
you.
B
Don't
have
to
use
this,
you
could
use
correlation
ID
if,
if
you
want
to
correlate
your
workflow
against
the
customer
ID,
but
if
you
don't,
maybe
your
workflow
is
associated
with
more
than
one
context
provider
like
maybe
there's
a
customer
provider
and
a
order
provider
and
a
shipping
provider.
You
can
associate
them
with
different
parameters
if
you,
if
you
want
so
for
now,
just
suffice
it
to
say
it
Returns,
the
customer
ID
that
we
want
to
use
in
the
context
provider.
Sorry,
that's
not
the
right
one,
this
one!
B
So
here
we
get
the
customer
ID
and
then
we
use
this
customer
ID.
If
it's
provided,
we
use
it
to
get
the
customer
from
the
database,
and
this
is
invoked
before
your
workflow
executes
and
then
by
default.
It
will
not
be
executed
again
during
each
activity
in
your
workflow,
but
you
can
have
it
executed.
If
you
want
to
by
setting
up
property
on
your
activity,
that's
it's
called
something
like
loads
or
I.
Don't
know
the
exact
name,
but
it
has
something
to
do
with
load.
B
So
you
can
configure
to
invoke
your
provider
during
each
activity
if
you
want
to,
but
normally
you
you
don't
want
to
do
that,
and
it
would
cost
a
lot
of
database
calls
potentially
or
API
calls,
depending
on
what
your
provider
is
invoking.
So
this
will
be
involved
automatically
before
workflow
executes.
Also
when
it
results,
it
will
be
invoked
once
and
the
same
goes
for
save
async.
So
so
this
will
cause
your
customer
to
be
loaded
into
the
into
the
workflows
context
and
then
it's
available
to
your
workflow.
So
let's
say
we
have
a
sample
workflow.
B
Here
it's
called
customer
Communications
workflow.
This
is
a
programmatic
workflow.
Just
for
the
demo.
I
also
have
a
version
in
the
designer
that
will
take
another
look
at
after
this
one.
It's
a
very
simple
workflow.
It's
just
basically
every
five
seconds,
spams
the
the
customer
with
an
email
to
try
and
get
them
to
buy
something.
So
the
the
first
one
is
simple
message:
declare
your
customers
welcomed.
Then
there
encouraged
to
get
their
credit
card
ready
and
they
are
stressed.
B
You
know
the
system
is
trying
to
stress
them
into
buying
something
and
really
motivating
them
to
to
buy
this
awesome
new
product.
The
workflow
will
work
I'm,
not
sure
the
customer
will
actually
buy
anything.
But
that's
that's
not
our
concern
here.
Our
concern
is
how
do
we
get
this
customer
ID
so
here
this
is
an
activity
called
set
workflow
context
parameter
in
elsa2.
That
is
called
set,
workflow
context,
but
here
it's
it's
there's
a
clear
distinction
between
the
parameter.
B
B
Each
of
them
will
provide
this
ambient
value
to
your
workflow,
but
you
need
to
provide
the
some
parameters,
so
that
is
that
it
can
use
used
to
get
the
data
from
the
from
whatever
data
source.
So
that's
that's
being
passed
here
and
it's
just
using
the
type
name
to
associate
this.
This
parameter
with
this
provider
internally
in
the
dictionary
of
the
workflow
state.
So
once
this
is
set,
and
then
here
we
are
waiting
for
five
seconds
and
then
we're
going
to
send
an
email-
and
this
is
the
interesting
part.
B
So
this
subject
here
is
it's
a
Lambda,
so
it
has
access
to
the
activity
or
the
expression
execution
context,
which
is
which
has
access
to
activity,
execution
context
and,
of
course,
the
workflow
execution
context,
which
means
we
have
access
to
the
workflow
complex
and
that's
being
used
here.
So
here
we're
using
another
aesthetic
method
on
the
expression
execution
context
that
uses
another
static
method
provided
by
the
workflow
context,
module
to
get
the
workflow
context
that
was
loaded
by
the
by
the
provider.
B
So
this
gives
you
access
to
the
actual
customer
out
there
and
it's
not
loading
it.
At
this
moment,
it's
already
available,
you're
just
grabbing
that
object
instance
out
of
the
the
train,
transient
properties
that
is
being
used
internally.
So
here
every
wordful
execution
context
has
transient
properties,
which
is
in
memory,
so
it's
never
persisted
and
just
getting
it
by
provided
type.
So,
there's
an
internal
mapping
between
your
custom,
workflow
context
provider
and
the
object
that
was
loaded.
Also,
it
combo,
combined
with
the
parameter
so
I
didn't
provide
any
parameter.
B
Name,
I
just
specified
the
provider
name,
but
if
you
did
want
to
have
multiple
inputs
for
your
provider,
you
can
use
that
as
well,
but
that's
not
being
used
here,
I'm,
not
showing
it
and
anyway,
okay.
So
here
we
have
the
customer
here
we're
using
it
again,
but
as
I
mentioned
it's
already
in
memory,
so
it's
okay
to
invoke
it
multiple
times.
So
this
goes
on
for
about
a
couple
of
well
four
times.
So
it's
it's
the
same
thing
just
every
five
seconds.
B
It's
going
to
send
another
email,
that's
a
very
silly
workflow,
but
it
it
demonstrates
the
workflow
context.
So
let
me
show
you
that
it
works.
I
will
run
this
one
or
this
project
I
will
invoke
it
from
Postmates.
So
this
is
the
idea
of
the
of
that
workflow
we
just
looked
at
when
I
hit,
send
it
shoots,
start
generating
email
messages,
I'm
doing
that
now
and
now
it
waits
for
five
seconds.
So
we
got
one
here.
So,
as
you
can
see,
it's
using
the
customer
name.
B
I
didn't
show
actually
the
the
customer
store,
but
it's
an
in-memory
collection
of
customers
and
every
five
seconds
a
new
email
comes
in.
So
what
what
would
you
do
without
the
workflow
context
provider?
You
would
have
to
have
another
way
to
load
in
your
customer,
so
it
could
be
custom
activity
and
then
potentially
you
would
have
to
have
to
eat,
send
email.
B
You
would
have
to
do
something
like
new
load
customer,
for
example,
and
then
you
would
have
to
have
it
have
to
have
it
here
as
well
Etc,
but,
as
you
can
see,
that
would
clutter
your
workflow
a
little
bit
more
so
and
it's
it's
repetitive,
but
with
this
workflow
context
provider
you
you
can
make
it
more
dry.
Does
it
make
sense?
Do
you
have
any
any
questions
or
is
there
anything
that
is
maybe
a
little
bit
too
fake?
That's
great.
B
Thing
all
right
so
now
that
we've
taken
a
look
at
this
in
in
the
programmatic
workflow.
Let's
take
a
look
at
the
at
the
designer,
so
first,
let's
clear
this
one
out,
then
let's
open
the
I
already
created
here
so
here
I
use
the
designer
to
create
the
same
workflow.
So
it's
it
starts
with
setting
with
the
workflow
context
parameter
here
or
actually
it
starts
with
context.
B
So
if
the
context
feature
is
enabled
you'll
get
an
extra
tab
here
and
it
shows
you
the
available
context,
providers
that
you
have
so
right
now,
I
have
just
implemented
one
if
I
were
to
create
another
one
which
we
could
do
just
for
fun,
but
let's
say
copy
this
one
and
call
this
one
order.
So
here
I
created
a
new
provider,
then
we
need
to
make
sure
it's
registered
in
our
application
like
this
and
now,
when
I
restart
the
application
we
have,
we
should
should
see
the
the
extra
provider
here.
B
B
So
let
me
refresh
this
one
and,
as
you
can
see
now,
we
also
have
ordered
and
if
we
select
the
the
both
of
them,
that
we
can
choose
here
which
parameter
to
set
for
which
provider,
so
here
I'm
just
using
customer,
but
we
could
also
choose
order
if
I
uncheck
this
one
and
then
refresh
this
UI,
there's
only
one,
this
one
enabled
all
right.
So
what
do
we
set
here
is
the
provided
type.
B
So
we
have
a
custom
provider,
optionally,
a
parameter
parameter
name
which
will
leave
empty
and
and
the
parameter
value
which
is
get
customer
ID.
So
this
comes
from
the
input,
so
I
declared
well
it's
supposed
to
have
one
input
called
customer
ID.
Let
me
add
it
so
here
we
have
input
for
this
workflow
definition
and
that
we
should
be
able
to
invoke
it
using
the
execute
API
endpoints
here
and
then
ask
the
body
we
have
inputs
and
then
the
the
name
of
the
input
we
just
declared,
which
is
customer
ID.
B
All
right
so
when
we
send
it
executes
and-
and
what
will
it
execute-
is
the
next
step,
so
this
executed
by
setting
the
parameter
value
to
the
number
two.
That's
customer
id2
wait
for
five
seconds
and
then
sending
the
email.
So
here-
and
this
is
this-
is
to
use
it
in
the
designer
you
use
JavaScript
and
not
C
sharp,
like
I,
did
in
the
programmatic
workflow
demo,
but
this
get
customer.
This
function
is
dynamically
declared
to
the
system
based
on
the
name
of
your
provider.
B
So
if
your
provider's
name
customer
workflow
context
provider,
it
strips
the
last
part,
the
you
know,
the
workflow
context
provider
is
stripped,
so
that
leaves
you
with
customer,
and
that
name
here
is
then
used
for
this
function.
Name
here.
This
can
cause
some
conflicts
if
you
also
have
variables
called
customers.
So
you
need
to
be
aware
of
that.
B
Maybe
we
need
to
offer
some
some
prefix
or
some
suffix
or
maybe
come
up
with
a
different
naming
convention,
but
we
can
tweak
that
as
we
identified
it
as
issues,
but
for
now
that's
how
it
works,
and
this
will
provide
you
with
the
this-
provides
you
with
a
strongly
typed
intellisense.
Well,
not
today,
then,
but
it's
it
should
have
shown
you
the
the
customer
object.
So
then
it
should
also
show
you
the
the
available
properties.
Let
me
see
if
I
can
refresh.
If
it
works,
then
I
know
there's
one
issue.
B
Sometimes
when
you
load
the
designer
for
the
first
time,
then
it
tries
to
make
some
API
call
to
get
the
type
definitions,
but
that
fails
with
an
internal
server
error,
because
what
the
definition
is
null
and
then
the
entire
designer
breaks
where
the
Monaco
editor.
So
it's
an
easy
fix
to
do,
but
I
I
haven't
done
it
yet
all
right.
So
so
now
we
see
the
the
properties
of
the
customer.
So
that's
cool
all
right,
so
I
did
run
the
workflow
and
you
can
see
here.
B
The
emails
are
being
sent
again,
but
this
time
from
the
workflow
this
this
the
workflow
created
in
the
designer,
which
also
means
we
should
be
able
to
look
at
the
instances
all
right.
Let's
see
some
errors
here,
so
maybe
something
got
broken
anyway.
This
screen
is
too
small
for
me
to
to
do
some
proper
debugging,
so
I'll
I'll
I'll
do
that
later
so
yeah.
So
that's
workflow
context.
So
it's
it's
there.
It
was
the
must-have
for
me
to
to
be
part
of
the
release
candidate
roadmap.
Speaking
of
widths.
B
That
currently
looks
like
this.
So
this
is
the
there's
a
new
tab
here
in
the
elsa3
project
board,
and
this
is
the
this
shows
you
all
of
the
items
that
are
associated
with
the
RC
Milestone,
which
I
created
a
couple
days
ago,
cool
so
we're
getting
very
close.
There's
a
few
issues
reported
recently:
RC
Milestone
is
set
to
May
31.
B
and
from
the
way
it
looks
right
now
is
basically,
if
you
look
at
this
board,
it's
very
close,
of
course,
there's
a
lot
of
work
to
be
done
for
the
documentation,
but
I
suspect
I
can
I
can
start
this
with
this.
Coming
weekend
and
I
work
through
the
month
of
May
yeah,
we
should
we
should
be
able
to
release
the
nougat
or
at
least
they're
an
RC
yeah.
We're.
B
Yeah
yeah
yeah,
so
that's
that
is
that
is
quite
exciting
yeah.
So
that
was
a
brief
note
on
the
RC
here.
So
the
very
cool
fix
it's
it's
it's
small,
maybe,
but
it
was
a
thorn
in
my
eye,
but
it's
fixed
by
by
Daxton,
and
let
me
share
with
the
issue.
B
Well,
I
can't
show
the
issue
anymore
because
it's
fixed,
but
so
now
originally,
maybe
you
remember
from
previous
presentations.
You
see
this
tool
tip
it
now
neatly
has.
Is
it
it's
not
cut
off
anymore?
You
know
it
before
this
fix
it
was.
It
got
cut
off,
which
was
very
ugly,
but
now
it's
it's
nice,
so
I'm
very
happy
with
that.
So
that's
this
one!
Oh
actually,
maybe
we
can
see
it
here.
Still,
no
I
I
didn't
even
bother
to
create
a
screenshot,
never
mind
tests.
B
There's
there's
some
so
there's
additional
tests
being
added
and
I
would
also
like
to
show
you
the
cool
helper
method
that
helps
you
test
drive
workflows.
So
let's
see
what
that
looks,
for
example.
So,
for
example,
here
we
have
two
workflows
to
test
certain
scenarios,
just
to
make
sure
that
certain
constructs
work
so
with
Elsa
you
can
have
implicit
joints.
B
So
let's
say
you
have
a
bunch
of
right
lines
here
and
then
they
are
part
of
a
flowchart,
so
they're
part
of
their
activities,
collection,
and
then
here
we
have
connections
between
them,
and
the
point
here
is:
is
that,
like
maybe
I
should
show
it
visually?
It's
easy
to
talk
about
it
like
that,
so
here,
so
so
at
some
point,
this
kind
of
workflows
didn't
work
in
lsf3
because
the
flowchart
wasn't
built
for
that
recently,
but
that's
changed
and-
and
this
is
now
also
captured
in
a
test.
B
So
so
in
order
to
make
sure
this
remains
working.
You
know
in
case
you
may
change
the
same.
We
inadvertently
break
something
we
want
to
capture
that.
So
here
we
have
a
bunch
of
test
cases
here,
it's
just
implemented
in
code,
but
what
we
have
here
looks
more
or
less
like
this,
although
this
contains
a
few
more
activities,
but
it's
it's
about
this
joining
between.
So
here
we
have
a
fork
implicitly
created
here
and
then
an
implicit
join.
So
that's
what
this
is
modeled
here
to
to
run
this
workflow.
It's
now
very
easy.
B
All
you
need
to
do
is
actually.
This
is
not
a
good
example,
so
this
is
a
workflow
Runner
that
that
was
already
available.
So
this
is
not
what
I
want
to
show
actually,
but
this
one
is
especially
because
this
includes
potentially
also
timer.
So
this
is,
this
is
very,
very
convenient.
So
the
first
thing
you
want
to
do
is:
whenever
you
run
a
workflow
is
make
sure
that
the
activity
descriptors
and
the
expression
providers
are
registered
with
the
system
when
you
start
outside
in
an
asp.net
core
application.
B
This
is
done
through
an
hosted
service,
but
when
you
run
a
test,
the
hosted
services
are
not
executed,
so
you
need
to
do
it
manually
here.
Then
you
import
the
workflow,
so
in
this
case
it's
using
Theory
and
then
one
workflow
at
a
time
so
that
that's
just
these
files
here,
so
it's
gonna
be
loaded
using
this
extension
method,
input,
workflow
definition
async,
which
returns
you
a
password
for
definition,
and
then
this
method
allows
you
to
run
the
workflow
until
the
end
and
it
even
works.
When
you
have
workflows
that
create
bookmarks.
B
That
would
cause
your
workflow
to
be
suspended,
but
what
this
method
here
does
it
will
then
look
at
those
bookmarks
and
resume
them
so
that
it
runs
the
workflow
until
the
end,
and
then
you
can
test
whatever
you
want.
So
this
test
case
is
about
a
bug
where
the
workflow
States
would
not
enter
the
the
finished
State,
even
though
the
the
workflow
was
done
executing.
So
there
was
this
bug
in
the
flowchart
activity,
and
this
this
captures
covers
that
case
and
it's
now
fixed.
A
How
could
it
resume
bookmarks?
How
does
it
know
what
what
values
or
resume
turn
from
these
activities?
Yeah.
B
Very
good
question,
because
some
bookmarks
in
order
for
them
to
be
resumed,
they
require
additional
data.
So
for
those
cases
in
the
the
way
it's
right
now
that
will
fail,
but
this
these
cases
only
handle
delay
activity.
So,
for
example,
we
have
here
an
activity
that
uses
delay
activities
and
they
create
bookmarks,
but
those
bookmarks
don't
require
any
additional
input.
So
in
those
cases
it
can
just
blindly
resume
them,
and
that
looks
like
this.
B
So
here
we
start
the
workflow
using
somewhere
for
definition,
ID
and
then
the
result
will
include
any
bookmarks
that
were
created
so
that
we
have
here
and
then
we
we
turn
those
bookmarks
into
a
stack
which
we
then
Loop
over
up.
One
of
one
Bookmark
at
a
time
and
I
will
resume
them
here.
But
to
your
point
we
are
not,
including
any
addition
any.
C
B
A
B
If
we
look
at
SRC
common,
so
there's
the
packets
called
Elsa
testing
shared,
and
this
has
a
bunch
of
useful
stuff.
So
here
there's
service
provider,
extensions,
and
so
here
we
see
the
populate,
Registries,
I,
think
and
it's
just
extensions
off
of
the
service
provider,
so
you
don't
have
to
first
instantiate
or
resolve
the
services.
It's
just
so
this
this
model,
some
high
level
functionality
that
you
can
invoke
here.
Import
work
definitely
seek.
Maybe
some
of
these
functions
do
too
much.
B
You
know
they're
very
opinionated
in
the
currents
form,
but
we
can
break
them
down
as
as
the
need
arises.
Okay,
cool
installed
features,
oh
yeah
yeah,
so
as
part
of
the
workflow
context,
as
I
mentioned
at
the
beginning,
it's
an
optional
feature,
but
it
also
you
know
in
order
to
provide
this
list
here,
that
we
see
here
the
list
of
providers.
It
requires
an
API
call,
which
means
it
requires
an
endpoint
to
be
made
available.
But
if
you
did
not
enable
this
feature,
those
endpoints
will
not
be
available.
B
Designer
needs
to
know
one
way
or
another
whether
this
feature
is
available.
Otherwise,
it
would
blindly
try
and
invoke
this
API.
It
would
not
exist
because
it
wasn't
enabled
and
then
you
would
get
client-side
errors
or
API
call
errors.
It's
this
isn't
very
clean.
So
in
order
to
to
solve
that,
Elsa
server
now
exposes
an
API
endpoint.
B
That
lists
all
of
the
enabled
features-
and
that
looks
like
this
here-
it
is
so
list
features,
and
it's
just
of
course
it's
a
simple
array
with
feature
descriptors
and
it
doesn't
contain
very
descriptive
information
at
this
point,
but
it
could
be
extensible
in
the
future,
maybe
with
when
we
build
more
tooling,
if
maybe
then
it
becomes
useful.
But
for
now
the
only
thing
the
designer
needs
is
the
name
of
the
feature.
B
So
then
you
can
imagine,
there's
a
workflow
context,
plugin
in
the
in
the
stencil
application,
and
it's
specific
quickly
looks
to
see
if
the
workflow
context
features
part
of
this
list
or
not.
So
when
the
designer
application
starts,
it
makes
a
q
API
calls
to
get
the
descriptor
so
like
what
activities
are
available.
What
are
the
variable
types
and
storage
drivers
and
it
gets
a
list
of
installed
features.
Then
here
we
see
workflow
context
features.
So
if
this
one
is
not
returned,
then
you
will.
The
plugin
will
not
do
anything.
B
It
will
not
initialize
the
UI
here
with
this
context,
tab.
None
of
this
will
be
available
cool,
so
yeah
so
and
this
this
is
also
going
to
be
useful
for
other
plugins
and
modules
that
we're
going
to
build
like
Secrets
management
and
and
whatnot
right.
So
that's
installed,
features
welcome
to
RC.
We
talked
about
yeah,
so
getting
getting
very
close
to
the
RC
candidate
or
release
candidate.
Workflow
context
is
new.
Let's
see
what
else
will.
A
It
still
be
possible
to
add
activities
on
runtime,
so
it's
a
new
activity,
definitions
at
runtime,
so
in
in
SF
version
2
it
wasn't
possible.
Maybe
it
will
be
possible
and
as
a
three.
B
Yeah
yeah,
it
should
be
possible
and
also
three
so
next
also
three,
we
have
a
thing
called
activity
registry.
No,
let's
see,
there's
a
service
that
that
represents
the
registry
of
of
registered
activities,
but
that
can
be
updated
at
runtime.
So
the
way
that
works
is
what
we
have
here.
So
here
we
have
the
registry,
so
it's
an
activity
registry,
and
so
it
has
ADD
functions.
So
this
function
allows
you
to
add
a
descriptor
associated
with
the
with
the
provider
that
provided
this
thing.
B
So
an
activity
is
always
associated
with
a
provider
which
is
convenient
because,
let's
say
you
have
this
Source
from
which
you
want
to
provide
activities
to
the
system.
Let's
say
the
source
gets
updated,
then
you
want
to
refresh,
but
now
you
can
refresh
it
just
for
your
provider
so
that
all
of
the
other
provided
activities
from
other
providers
will
not
have
to
be
re-queer
it.
If
you
will
so
that
it's
like
an
optimization,
really
yeah.
B
Yeah
well,
there's
well,
there's
a
you
can
add
all
of
the
activities
associated
before
Friday
using
clear
provider,
but
if
there's
a
scenario
where
you
need
to
delete
just
one
activity
for
whatever
reason,
we
can
of
course
add
it,
but
I
didn't
find
a
use
case
for
it.
So
I
didn't
add
it
yet,
but
we
can
always
add
it
later
if
necessary.
Right
now,
it's
not
using
any
caching
either.
So
so,
but
but
this
activity
register
is
a
Singleton,
so
it's
it's
it's
already
casted
fuel.
So
so
it's
also
easy
to.
A
We're
building
a
system
where
we
we're
spreading
the
activities
over
multiple
microservices.
Each
of
these
microservices
are
providing
some
activities,
for
example,
getting
orders
from
Amazon
getting
orders
from
webshop
systems
and
so
on
and
every
time
microservice
is
coming
up.
Maybe
a
new
one,
his
publishing
or
he's
sending
his
activities
he
is
providing
to
to
the
workflow
engine.
A
Also
and
as
saying
hey,
I
I've
got
some
new
activities
and
I
want
to
register
them,
and
the
workflow
engine
has
to
show
that
and
the
UI
someone
configures
a
workflow
and
the
workflow
is
being
executed.
Maybe
by
an
HTTP
request.
Asynchronously
as
the
the
activity
is
being
executed
is
paused
and
asynchronously.
A
the
the
request
is,
is
being
sent
to
the
microservice.
The
activity
is
being
executed
and
this
response
is
being
sent
back
to
the
workflow
engine
asynchronously
and
is
resuming
the
activity
so
possibility
possible.
B
A
I,
don't
know,
maybe
we
registered
at
the
activities
before
the
the
built
method
in
in
asp.net.
I
haven't
tested
it,
maybe
if
it's
possible
to
edit
later,
but
but
we
we
registered
in
in
the
startup
method
of
outside
version,
2
on
Startup
of
the
project,
yeah.
B
I
gotcha,
so
I
think
somebody
else
asked
this
question
later
and
I
had
to
look
it
up
because
I
wasn't
sure
if
it
was
possible,
I
think
I,
remember
realizing
that
it
should
be
possible
and
answer
too
I
haven't
tried
it,
so
it
could
be
wrong.
A
similar
setup
exists
there,
but
you
also
have
a
activity
registry
also
based
by
providers,
but
there's
a
a
casting
layer
at
play
there.
So
if
you,
if
your
activity
type
provider
requires
to
be
refreshed,
you
have
to
just
trigger
some
some
cast
key.
A
A
B
So
here
we
have
type
based
this,
so
this
is
just
one
of
the
writers
and
then
so
it's
similar
in
in
the
construction
yeah,
okay.
So
here
we
get
all
of
the
activity
types
for
each
provider
and
then
that's
being
used.
So
here
we're
building
a
dictionary
of
it.
But
as
you
can
see,
it's
it's
stored
in
a
memory
case,
but
it's
and
and
we're
monitoring
some
some
token
using
some
Cask
keys
so
using
this
Cascade,
which
is
a
public
constant.
You
should
be
able
to
whenever
you
need
to
refresh
your
thing.
B
C
But
we
don't
have
any
any
any
method
to
unload.
B
The
library
right
yeah,
so
this
this
is
this-
is
through
with
dynamically
loading
DLS
into
your
application
domain,
but
I
I.
If,
if
I'm
not
wrong,
when
aspin
at
core
was
first
launched,
it
did
it
didn't
have
support
for
dynamic,
reloading
assemblies
or
very
poor
loading
I
could
be
wrong,
but
this
is
what
I
remember,
but
at
some
point
they
they
added,
really
good
support
for
being
able
to
load
assembly
set
runtime
and
including
unloading
them.
B
I
want
to
do
for
Elsa
too,
not
elsa2,
but
I
want
to
use
it
for
Elsa
as
well
to
be
able
to
have
a
nougat
packet
somewhere
or
some
deals,
maybe
even
that
you
can
just
point
to
and
then
load
it
in
memory
or
into
your
application
at
runtime
and
and
basically
have
modules
dynamically
installed
into
your
system
without
having
to
redeploy
whether
that's
a
good
idea
for
your
case
that
you
know
that
depends
on
the
case
by
case
basis,
because
it's
also
a
little
bit
as
as,
if
you
are
adding
code
in
production
at
runtime,
which
is
probably
not
a
good
idea,
but
it's
I
think
at
least
it
should
be
an
option
for
maybe
those
use
cases
where
you
do
want
to
be
able
to
do
so.
B
C
And
as
I
understand,
in.net
course
is
not
the
same
notion
as
abdomen,
and
but
there
is
different
library
and
come
up
that
allow
us
to
create
a
plug-in
architecture,
be
able
to
load
and
unload
specific
library
and
then
let
the
garbage
protecting
everything
when
the
library
are
not
used.
Yes,
but
I
think
this
just
asks
us
to
to
define
a
correct
interface
between
the
the
in
the
architecture.
Yeah.
B
A
B
Not
here,
let
me
so
I
want
to
focus
on
multi-tenancy.
Oh
great,
let's
get
yeah
it's
it's
a
long
ask
for
feature
and
I
I
never
took
the
time
to
to
just
dig
into
it,
but
but
I
really
want
to,
because
it's
going
to
enable
a
lot
of
you.
Cool
use
cases
for
hosting
at
least
but
one
thing
I'm
wondering
is
it's
about
this
Library.
There
was
one
library
that
was
Sprint.
A
A
B
Yeah,
so
my
only
hesitation
with
using
this
library
is,
it
depends
on
on
How
Deeply.
It
has
to
integrate
with
it
with
LSAT
core
right,
so
I
don't
want
else
a
workflow
core
to
be
to
have
a
dependency
on
on
on
something
like
that.
If
I
can
help
it
because
it's
you
know
it,
then
everyone
would
automatically
have
to
inherit
that
dependency.
It's
like!
B
Maybe
it's
a
little
bit
like
you
know,
depending
on
something
like
Auto
mapper,
which
without
it's,
what
I've
seen
in
elsa2
causes
a
lot
of
pain
for
many
users
that
are
using,
for
example,
ABP,
which
also
uses
Auto
map
mapper,
so
yeah.
It
requires
some
investigation,
some
research
on
on
what
how
to
best
tackle
this
one
but
I
I,
do
hope.
B
C
B
That's
on
my
wishlist
and
another
one
is
bpmn2,
which
is
one
of
the
first
questions.
I
was
asked
when
I
released
Elsa
one
was
what
about
bpmn
and
I
was
like
yeah
yeah.
That
sounds
cool.
Let's,
let's
see,
but
I
never
got
gotten
around
to
to
digging
into
it.
I
did
I
think
a
couple
months
back,
look
at
komunda
and
and
then
delft
a
little
bit
into
BPM
and
two
specification
and
yeah.
B
It
looks
really
doable
with
the
Elsa
3
engine,
where
you
can
now
have
actually
just
a
BP
man
activity
that
then
internally
interprets
PPM
annotation,
of
course,
and
then
it
has
to
implement
the
protocol
to
to
schedule
the
the
activities
and
and
stuff
like
that.
You.
B
Yeah,
that's
a
good
point,
so
we
can
do
it
in
multiple
iterations
and
we
start
simple
and
then
build
on
that
yeah.
Those
Milestones
actually
created
them
just
to
be
clear.
I
I,
don't
necessarily
commit
to
those
dates.
It's
the
best
effort.
So
is
always
the
case
with
these
sort
of
projects,
but
it's
good
to
have
to
try
and
set
a
goal.
At
least
here
is
the
Milestones,
so
first
rc
May
31,
then
one
month
later
or
actually,
this
is
this-
is
one
month
later.
B
B
So
it's,
let
me
correct
you:
it's
got
to
be
multi-tenancy,
hopefully
for
3.1
and
then
VP
man,
it's
it's
possible,
but
I
I.
It's
hard
to
tell
at
this
point
how
complicated
it
will
be,
because
I
also
want
to
include
a
designer.
You
know
just
a
reusable
BPM
and
designer
Library
that's
out
there,
but
it's
going
to
require
some
work
to
get
it
integrated
currently
in
stencil
speaking
of
stencil.
B
B
You
yeah
same
here:
yeah,
that's
all
I
got
if
you
guys
have
anything
else,
let
me
know
otherwise.
I'll
catch
you
later
yeah.