private static async Task ActivityChanged(ProcessActivityChangedEventArgs args, WorkflowRuntime runtime) { if (!args.TransitionalProcessWasCompleted) { return; } var historyModel = await MetadataToModelConverter.GetEntityModelByModelAsync("DocumentTransitionHistory"); var emptyHistory = (await historyModel.GetAsync(Filter.And.Equal(Null.Value, "EmployeeId").Equal(args.ProcessId, "DocumentId") .Equal(Null.Value, "TransitionTime"))).Select(h => h.GetId()).ToList(); await historyModel.DeleteAsync(emptyHistory); await runtime.PreExecuteFromCurrentActivityAsync(args.ProcessId); var nextState = WorkflowInit.Runtime.GetLocalizedStateName(args.ProcessId, args.ProcessInstance.CurrentState); var documentModel = await MetadataToModelConverter.GetEntityModelByModelAsync("Document"); var document = (await documentModel.GetAsync(Filter.And.Equal(args.ProcessId, "Id"))).FirstOrDefault() as dynamic; if (document == null) { return; } document.StateName = nextState; document.State = args.ProcessInstance.CurrentState; await documentModel.UpdateSingleAsync(document as DynamicEntity); var newActors = await Runtime.GetAllActorsForDirectCommandTransitionsAsync(args.ProcessId); var newInboxes = new List <dynamic>(); foreach (var newActor in newActors) { var newInboxItem = new DynamicEntity() as dynamic; newInboxItem.Id = Guid.NewGuid(); newInboxItem.IdentityId = newActor; newInboxItem.ProcessId = args.ProcessId; newInboxes.Add(newInboxItem); } var userIdsForNotification = new List <string>(); userIdsForNotification.AddRange(newInboxes.Select(a => (string)(a as dynamic).IdentityId)); var inboxModel = await MetadataToModelConverter.GetEntityModelByModelAsync("WorkflowInbox"); using (var shared = new SharedTransaction()) { await shared.BeginTransactionAsync(); var existingInbox = (await inboxModel.GetAsync(Filter.And.Equal(args.ProcessId, "ProcessId"))); userIdsForNotification.AddRange(existingInbox.Select(a => (string)(a as dynamic).IdentityId)); var existingInboxIds = existingInbox.Select(i => i.GetId()).ToList(); await inboxModel.DeleteAsync(existingInboxIds); await inboxModel.InsertAsync(newInboxes); await shared.CommitAsync(); } userIdsForNotification = userIdsForNotification.Distinct().ToList(); Func <Task> task = async() => { await ClientNotifiers.NotifyClientsAboutInboxStatus(userIdsForNotification); }; task.FireAndForgetWithDefaultExceptionLogger(); }
public static void Configure(IHttpContextAccessor httpContextAccessor, IConfigurationRoot configuration, string connectionstringName = "default") { #region License var licensefile = "license.key"; if (File.Exists(licensefile)) { try { var licenseText = File.ReadAllText(licensefile); DWKitRuntime.RegisterLicense(licenseText); } catch { //TODO add write to log } } #endregion #if (DEBUG) DWKitRuntime.UseMetadataCache = false; //CodeActionsCompiller.DebugMode = true; #elif (RELEASE) DWKitRuntime.UseMetadataCache = true; #endif DWKitRuntime.ConnectionStringData = configuration[$"ConnectionStrings:{connectionstringName}"]; DWKitRuntime.DbProvider = AutoDetectProvider(); DWKitRuntime.Security = new SecurityProvider(httpContextAccessor); DWKitRuntime.Metadata = new DefaultMetadataProvider("Metadata/metadata.json", "Metadata/Forms", "Metadata/Localization"); if (configuration["DWKit:BlockMetadataChanges"] == "True") { DWKitRuntime.Metadata.BlockMetadataChanges = true; } CodeActionsCompiller.RegisterAssembly(typeof(WorkflowRuntime).Assembly); DWKitRuntime.CompileAllCodeActionsAsync().Wait(); //It is necessery to have this assembly for compile code with dynamic CodeActionsCompiller.RegisterAssembly(typeof(Microsoft.CSharp.RuntimeBinder.Binder).Assembly); DWKitRuntime.ServerActions.RegisterUsersProvider("filters", new Filters()); DWKitRuntime.ServerActions.RegisterUsersProvider("triggers", new Triggers()); //Initial inbox/outbox notifiers DWKitRuntime.AddClientNotifier(typeof(ClientNotificationHub), ClientNotifiers.NotifyClientsAboutInboxStatus); //Initial document count notifier DWKitRuntime.AddClientNotifier(typeof(ClientNotificationHub), SideMenuInitialNotifier); //User group classifier for notifications DWKitRuntime.SignalRGroupClassifier = SignalRGroupClassifier; //Documents count change on Insert new document or update document DynamicEntityOperationNotifier.SubscribeToInsertByTableName("Document", "SideMenuNotification", (m, c) => { Func <Task> func = async() => { await NotifyDocumentCountChange(m, c, false); }; func.FireAndForgetWithDefaultExceptionLogger(); }); DynamicEntityOperationNotifier.SubscribeToUpdateByTableName("Document", "SideMenuNotification", (m, c) => { Func <Task> func = async() => { await NotifyDocumentCountChange(m, c, true); }; func.FireAndForgetWithDefaultExceptionLogger(); }); //Documents count change and inbox outbox change on document deletions DynamicEntityOperationNotifier.SubscribeToDeleteByTableName("Document", "SideMenuNotification", (m, c) => { Func <Task> func = async() => { await ClientNotifiers.DeleteWokflowAndNotifyClients(m, c); await NotifyDocumentCountChange(m, c, false); }; func.FireAndForgetWithDefaultExceptionLogger(); }); var runtime = WorkflowInit.Runtime; }
public static void Configure(IHttpContextAccessor httpContextAccessor, IConfigurationRoot configuration, string connectionstringName = "default") { #region License var licensefile = "license.key"; if (File.Exists(licensefile)) { try { var licenseText = File.ReadAllText(licensefile); DWKitRuntime.RegisterLicense(licenseText); } catch { //TODO add write to log } } #endregion #if (DEBUG) DWKitRuntime.UseMetadataCache = false; #elif (RELEASE) DWKitRuntime.UseMetadataCache = true; #endif DWKitRuntime.ConnectionStringData = configuration[$"ConnectionStrings:{connectionstringName}"]; DWKitRuntime.DbProvider = AutoDetectProvider(); DWKitRuntime.Security = new SecurityProvider(httpContextAccessor); var path = configuration["Metadata:path"]; if (string.IsNullOrEmpty(path)) { path = "Metadata/metadata.json"; } DWKitRuntime.Metadata = new DefaultMetadataProvider(path, "Metadata/Forms", "Metadata/Localization"); if (configuration["DWKit:BlockMetadataChanges"] == "True") { DWKitRuntime.Metadata.BlockMetadataChanges = true; } if (!string.IsNullOrWhiteSpace(configuration["DWKit:CodeActionsDebugMode"])) { DWKitRuntime.CodeActionsDebugMode = bool.Parse(configuration["DWKit:CodeActionsDebugMode"]); } CodeActionsCompiler.RegisterAssembly(typeof(WorkflowRuntime).Assembly); //It is necessary to have this assembly for compile code with dynamic CodeActionsCompiler.RegisterAssembly(typeof(Microsoft.CSharp.RuntimeBinder.Binder).Assembly); DWKitRuntime.CompileAllCodeActionsAsync().Wait(); DWKitRuntime.ServerActions.RegisterUsersProvider("filters", new Filters()); DWKitRuntime.ServerActions.RegisterUsersProvider("triggers", new Triggers()); //Initial inbox/outbox notifiers DWKitRuntime.AddClientNotifier(typeof(ClientNotificationHub), ClientNotifiers.NotifyClientsAboutInboxStatus); //Remove process after the document was removed DynamicEntityOperationNotifier.SubscribeToDeleteByTableName("Document", "WorkflowDelete", (e, c) => { Func <Task> task = async() => { await ClientNotifiers.DeleteWokflowAndNotifyClients(e, c); }; task.FireAndForgetWithDefaultExceptionLogger(); }); //Forcing the creation of a WF runtime to initialize timers and the Flow. try { WorkflowInit.ForceInit(); } catch (Exception e) { if (Debugger.IsAttached) { var info = ExceptionUtils.GetExceptionInfo(e); var errorBuilder = new StringBuilder(); errorBuilder.AppendLine("Workflow engine start failed."); errorBuilder.AppendLine($"Message: {info.Message}"); errorBuilder.AppendLine($"Exceptions: {info.Exeptions}"); errorBuilder.Append($"StackTrace: {info.StackTrace}"); Debug.WriteLine(errorBuilder); } } }