For UiPath version 18.2.3 I successfully created a new logging activity. The idea is, while logging everything in Orchestrator, the new activity would in addition log in a file as well. Coming up our organization will upgrade to UiPath 2019.4.3 and my activity did not work, so I needed to upgrade the UiPath references to current dlls. Doing that gives me a compilable code, but the activity causes a null-pointer exception. Why?
This is my code:
using System; using System.Activities; using System.Activities.Presentation.Metadata; using System.ComponentModel; using System.IO; using System.Text; using UiPath.Core.Activities; namespace CustomCode.Log { /// <summary> /// Designer attribute gives a look & feel like UiPaths own LogMessage activity /// </summary> [Designer(typeof(UiPath.Core.Activities.Design.LogDesigner))] public class LogMessage : CodeActivity, IRegisterMetadata { [Category("Input")] public CurentLogLevel Level { get; set; } [Category("Input")] public InArgument<System.String> Message { get; set; } [Category("Input")] public InArgument<System.String> LogFilePath { get; set; } /// <summary> /// UiPath Log Message object reference /// </summary> private UiPath.Core.Activities.LogMessage _LogMessage { get; set; } /// <summary> /// Constructor /// </summary> public LogMessage() { DisplayName = "Extended Log Message"; Level = CurentLogLevel.Trace; // default setting } /// <summary> /// declare dummy register metadata class to force UiPath to load this assembly /// </summary> public void Register() { // intentionally empty } /// <summary> /// First log as if done by native UiPath then log to the file specified /// </summary> /// <param name="context"></param> protected override void Execute(CodeActivityContext context) { // first do the usual UiPath logging... string message = Message.Get(context); //bool isNew = false; #region log as UiPath standard // it is necessary to create new objects every time. // reassigning property values causes errors when logging is frequent... _LogMessage = new UiPath.Core.Activities.LogMessage { Level = this.Level, Message = new InArgument<string>(message), }; // do UiPath log try { WorkflowInvoker.Invoke(_LogMessage); // NULL POINTER EXCEPTION HERE } catch (Exception ex) { throw new Exception("Internal UiPath Invoke Exception ", ex); } #endregion string logFilePath = LogFilePath.Get(context); // log to file if path is specified... if (logFilePath != null) { LogToFile(logFilePath, message, Level.ToString()); } } /// <summary> /// Method to write a line in the log file /// </summary> /// <param name="filename">the file to which to log</param> /// <param name="message">the log message</param> /// <param name="level">the log level</param> private void LogToFile(string filename, string message, string level) { StringBuilder LogLine = new StringBuilder(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); LogLine.Append("\t"); LogLine.Append(level); LogLine.Append("\t"); LogLine.Append("\t - "); LogLine.Append(message); LogLine.Append(Environment.NewLine); try { // append the log line File.AppendAllText(filename, LogLine.ToString()); } catch (Exception ex) { // try to log the exception in UiPath _LogMessage.Message = new InArgument<string>(ex.Message + Environment.NewLine + ex.StackTrace); throw new Exception("Internal append to log file exception", ex); } } } }