I tried to create a TaskStep<T1,T2>
with constructor parameters.
[Display(Name = "Some Task", Description = "Task which does something with a product")]
public class SomeTask : TaskStep<SomeActivity, SomeParameters>
{
public TestTask([Display(ResourceType = typeof(Strings), Name = nameof(Strings.SOME_PARAMETER))] string someParameter) { }
}
Importing a workplan with this task works just fine. Also the Moryx.Workplans.Web editor handles a step creation as expected and asks me for the parameter when I drag a step into my workplan.
However, when I try to save or load a workplan with a step in it in the editor I get a 500 Http response and the following exception is in the body:
System.MissingMethodException: Cannot dynamically create an instance of type 'Moryx.Demo.Activities.SomeTask'. Reason: No parameterless constructor defined.
at System.RuntimeType.ActivatorCache..ctor(RuntimeType rt)
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions)
at Moryx.Products.Management.RecipeStorage.LoadSteps(WorkplanEntity workplan, IDictionary`2 connectors)
at Moryx.Products.Management.RecipeStorage.LoadWorkplan(WorkplanEntity workplanEntity)
at Moryx.Products.Management.RecipeStorage.LoadWorkplan(IUnitOfWork uow, Int64 id)
at Moryx.Products.Management.RecipeManagement.LoadWorkplan(Int64 workplanId)
at Moryx.Products.Management.ProductManagementFacade.LoadWorkplan(Int64 workplanId)
at lambda_method1492(Closure, Object, Object[])
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|7_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
MORYX always needs an empty constructor to recreate objects from the database. If you do not define any constructor, than C# defines the default constructor for you. If you create a parameterized constructor however, the default one is no longer available, so you must provide a replacement. This can also be a private constructor, like in the SplitStep
[Display(Name = "Some Task", Description = "Task which does something with a product")]
public class SomeTask : TaskStep<SomeActivity, SomeParameters>
{
private SomeTask(){}
public SomeTask([Display(ResourceType = typeof(Strings), Name = nameof(Strings.SOME_PARAMETER))] string someParameter) { }
}