private void runCommand(string flowRuleCode, MVEntry mventry, CSEntry csentry, string target) { string source = target == "mventry" ? "csentry" : "mventry"; wwScripting wwScript = null; //example of what we will be getting in: //mventry["attrib1"].Value = csentry["attrib1"].Value.Substring(0, 1); //what the code engine will expect: //string param0 = (string)parameter[0]; //return param0.Substring(0,1); //we are importing into a mv attribute, extract the attribute from //the flow rule name string targetAttrib = flowRuleCode.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[0].Trim(); targetAttrib = targetAttrib.ToLower().Replace(target + "[\"", "").Replace("\"].values", "").Replace("\"].value", ""); //now extract the code to execute string code = " " + flowRuleCode.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[1].Trim(); code = code.Replace(" ", " "); //convert any other references to the cs or mv attributes to a //parameter array we can pass on List <string> paramAttribs = new List <string>(); List <object> paramValues = new List <object>(); string[] codeBreaks = code.Split(new string[] { source + "[\"" }, StringSplitOptions.None); for (int i = 1; i < codeBreaks.Length; i++) { string attrib = codeBreaks[i].Substring(0, codeBreaks[i].IndexOf("\"]")); if (!paramAttribs.Contains(attrib)) { //TODO: is this the best way to handle the isPresent check?? paramAttribs.Add(attrib); if (source == "csentry") { paramValues.Add(csentry[attrib].IsPresent ? csentry[attrib].Value : ""); } else { paramValues.Add(mventry[attrib].IsPresent ? mventry[attrib].Value : ""); } } } code = "return " + code; //replace attribute references in code with paramaterized references int j = 0; foreach (string key in paramAttribs) { AttributeType type; bool isMultiValued = false; if (source == "csentry") { type = csentry[key].DataType; isMultiValued = csentry[key].IsMultivalued; } else { type = mventry[key].DataType; isMultiValued = mventry[key].IsMultivalued; } switch (type) { case AttributeType.Binary: if (isMultiValued) { } else { code = "byte[] param" + j.ToString() + " = (byte[])Parameters[" + j.ToString() + "]; " + code; } break; case AttributeType.Boolean: if (isMultiValued) { } else { code = "bool param" + j.ToString() + " = bool.Parse((string)Parameters[" + j.ToString() + "]); " + code; } break; case AttributeType.Integer: if (isMultiValued) { } else { code = "int param" + j.ToString() + " = int.Parse((string)Parameters[" + j.ToString() + "]); " + code; } break; case AttributeType.Reference: if (isMultiValued) { } else { code = "Guid param" + j.ToString() + " = new Guid((string)Parameters[" + j.ToString() + "]); " + code; } break; case AttributeType.String: if (isMultiValued) { } else { code = "string param" + j.ToString() + " = (string)Parameters[" + j.ToString() + "]; " + code; } break; default: break; } code = code.Replace(source + "[\"" + key + "\"].Value", "param" + j.ToString()); j++; } if (!code.EndsWith(";")) { code = code + ";"; } try { wwScript = new wwScripting("CSharp"); wwScript.lSaveSourceCode = false; //TODO: figure out how to add these from the GAC or by relative path //It looks like we have to use a file path: http://www.databaseforum.info/25/860284.aspx //however GAC does have a file path behind it (i.e. C:\Windows\assembly\GAC_MSIL\wwScripting\1.0.4486.26865__e7bb1946e9e55389\wwScripting.dll) wwScript.cSupportAssemblyPath = "C:\\Installs\\"; Environment.CurrentDirectory = System.IO.Path.GetTempPath(); // force into AppDomain wwScript.CreateAppDomain("Insight.FIM.CodlessSync"); //use flow rule name as code to run var retVal = wwScript.ExecuteCode(code, paramValues.ToArray()); if (wwScript.bError) { throw new Exception("Error from wwScript - " + wwScript.cErrorMsg); } AttributeType type; bool isMultiValued = false; if (target == "mventry") { type = mventry[targetAttrib].DataType; isMultiValued = mventry[targetAttrib].IsMultivalued; } else { type = csentry[targetAttrib].DataType; isMultiValued = csentry[targetAttrib].IsMultivalued; } //set value on target attribute switch (type) { case AttributeType.Binary: if (target == "mventry") { if (isMultiValued) { mventry[targetAttrib].Values = (Microsoft.MetadirectoryServices.ValueCollection)retVal; } else { mventry[targetAttrib].BinaryValue = (byte[])retVal; } } else { if (isMultiValued) { csentry[targetAttrib].Values = (Microsoft.MetadirectoryServices.ValueCollection)retVal; } else { csentry[targetAttrib].BinaryValue = (byte[])retVal; } } break; case AttributeType.Boolean: if (target == "mventry") { if (isMultiValued) { mventry[targetAttrib].Values = (Microsoft.MetadirectoryServices.ValueCollection)retVal; } else { mventry[targetAttrib].BooleanValue = (bool)retVal; } } else { if (isMultiValued) { csentry[targetAttrib].Values = (Microsoft.MetadirectoryServices.ValueCollection)retVal; } else { csentry[targetAttrib].BooleanValue = (bool)retVal; } } break; case AttributeType.Integer: if (target == "mventry") { if (isMultiValued) { mventry[targetAttrib].Values = (Microsoft.MetadirectoryServices.ValueCollection)retVal; } else { mventry[targetAttrib].IntegerValue = (int)retVal; } } else { if (isMultiValued) { csentry[targetAttrib].Values = (Microsoft.MetadirectoryServices.ValueCollection)retVal; } else { csentry[targetAttrib].IntegerValue = (int)retVal; } } break; case AttributeType.Reference: if (target == "mventry") { if (isMultiValued) { mventry[targetAttrib].Values = (Microsoft.MetadirectoryServices.ValueCollection)retVal; } else { mventry[targetAttrib].ReferenceValue = (ReferenceValue)retVal; } } else { if (isMultiValued) { csentry[targetAttrib].Values = (Microsoft.MetadirectoryServices.ValueCollection)retVal; } else { csentry[targetAttrib].ReferenceValue = (ReferenceValue)retVal; } } break; case AttributeType.String: if (target == "mventry") { if (isMultiValued) { mventry[targetAttrib].Values = (Microsoft.MetadirectoryServices.ValueCollection)retVal; } else { mventry[targetAttrib].StringValue = (string)retVal; } } else { if (isMultiValued) { csentry[targetAttrib].Values = (Microsoft.MetadirectoryServices.ValueCollection)retVal; } else { csentry[targetAttrib].StringValue = (string)retVal; } } break; default: break; } //log.Debug("Custom code execution complete. Return value: " + CodeReturnValue); } catch (Exception ex) { //log.Error("An exception occured while executing the custom code. Details: " + ex.ToString()); if (ex.InnerException != null) { //log.Error("InnerException: " + ex.InnerException.ToString()); } throw; } finally { if (wwScript != null) { wwScript.Dispose(); } } }
private void _buildAndExecuteCode(object sender, EventArgs e) { wwScripting wwScript = null; try { //log.Info("User Context Code is running under: " + System.Security.Principal.WindowsIdentity.GetCurrent().Name); wwScript = new wwScripting(Language); wwScript.lSaveSourceCode = false; //TODO: figure out how to add these from the GAC or by relative path //It looks like we have to use a file path: http://www.databaseforum.info/25/860284.aspx //however GAC does have a file path behind it (i.e. C:\Windows\assembly\GAC_MSIL\wwScripting\1.0.4486.26865__e7bb1946e9e55389\wwScripting.dll) wwScript.cSupportAssemblyPath = "C:\\Installs\\"; Environment.CurrentDirectory = System.IO.Path.GetTempPath(); //TODO: fix wwScript.dll to get AppDomains working: currently fails on 371 of the //CreateInstance method because the RemoteLoader dll cant be found, will need to //change reference to use full assembly name, ie. RemoteLoader, Version=1.0.4406.26870, Culture=neutral, PublicKeyToken=739e02ea3855a61b //to pull it from the GAC. I have already signed them for a strong name and put them there wwScript.CreateAppDomain("Insight.FIM.Workflow.CustomCode"); // force into AppDomain //loScript.AddAssembly("system.windows.forms.dll", "System.Windows.Forms"); //loScript.AddAssembly("system.web.dll","System.Web"); //wwScript.AddNamespace("System.Net"); foreach (string ns in Includes.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries)) { //log.Info("Adding namespace: " + ns); if (!string.IsNullOrEmpty(ns.Trim())) { wwScript.AddNamespace(ns.Trim()); } } foreach (string a in Assemblies.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries)) { //log.Info("Adding assembly: " + a); if (!string.IsNullOrEmpty(a.Trim())) { wwScript.AddAssembly(a.Trim()); } } //user is passing in a return type, do we need to perform //some conversion here - No, we dont. we just need to pass the //type on to the ChangeAttributeCodeActivity //what if we want to return a multi-value/array? CodeReturnValue = (string)wwScript.ExecuteCode(Code, paramArrayResolved); if (wwScript.bError) { throw new Exception("Error from wwScript - " + wwScript.cErrorMsg); } log.Debug("Custom code execution complete. Return value: " + CodeReturnValue); } catch (Exception ex) { log.Error("An exception occured while executing the custom code. Details: " + ex.ToString()); if (ex.InnerException != null) { log.Error("InnerException: " + ex.InnerException.ToString()); } throw; } finally { if (wwScript != null) { wwScript.Dispose(); } } }