- 发行说明
- 概述
- 入门指南
- UiPath 市场供应商
- UiPath Marketplace 客户
- 发布准则
- 即用型自动化发布准则
- 解决方案加速器发布准则
- Integration Service 连接器的发布准则
- 安全性与 IP 保护
- 其他 UiPath 列表
- 连接器
- 如何创建活动
- 构建集成
UiPath Marketplace 用户指南
许可实施
本文档部分将指导您完成将许可 SDK 库嵌入到活动包中的过程。
请根据您的包是使用还是未使用 UiPath Activity Creator 开发的,请按照以下步骤操作:
.NET 6 或 Windows 兼容自定义活动的许可实施责任由供应商承担。 Marketplace 不提供 .NET6 兼容许可库。 它提供与 Windows 旧版兼容的许可库。
-
在每个活动的 ExecuteAsync 方法中,添加验证检查,除非您有“作用域活动”场景。
如果您确实有“作用域活动”场景,则只有在所有活动都需要获得许可的情况下,才能将验证检查添加到该活动中。
protected override async Task<Action<AsyncCodeActivityContext>> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken) { // Inputs var firstNumber = FirstNumber.Get(context); var secondNumber = SecondNumber.Get(context); // License validation #if !DEBUG //if your package is MyCompany.MyPackageName.Activities.1.0.0.nupkg await Validator.ValidateAsync(context, "MyCompany.MyPackageName.Activities"); #endif /////////////////////////// // Add execution logic HERE /////////////////////////// // Outputs return (ctx) => { }; }
protected override async Task<Action<AsyncCodeActivityContext>> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken) { // Inputs var firstNumber = FirstNumber.Get(context); var secondNumber = SecondNumber.Get(context); // License validation #if !DEBUG //if your package is MyCompany.MyPackageName.Activities.1.0.0.nupkg await Validator.ValidateAsync(context, "MyCompany.MyPackageName.Activities"); #endif /////////////////////////// // Add execution logic HERE /////////////////////////// // Outputs return (ctx) => { }; }备注:- 上下文 对象 只能传递一次 ,并且只能在将其传递到的方法中使用。 例如,在调用 Validator.ValidateAsync 之后,不能再在 ExecuteAsync 方法中使用它。
- 考虑到上述要求,这也意味着在将上下文传递给许可方法/库之前,必须读取输入变量。
-
将 .Activities 项目引用到 .Activities 库中,并添加 using 语句:
using UiPath.Marketplace.License.Validations;
- 安装已完成 - 构建您的包,并确保包内容中(位于 lib 文件夹中)中存在 许可.dll 库。 之后,您可以在 UiPath Marketplace 上提交。
如果您的初始活动如下所示:
using System;
using System.Activities;
using System.ComponentModel;
namespace ClassMathCustomActivity
{
public class SimpleFormula : CodeActivity
{
[Category("Input")]
[RequiredArgument]
public InArgument<double> FirstNumber { get; set; }
[Category("Input")]
public InArgument<double> SecondNumber { get; set; }
[Category("Output")]
public OutArgument<double> ResultNumber { get; set; }
protected override void Execute(CodeActivityContext context)
{
var firstNumber = FirstNumber.Get(context);
var secondNumber = SecondNumber.Get(context);
var result = System.Math.Pow(firstNumber + secondNumber, 2);
ResultNumber.Set(context, result);
}
}
}
using System;
using System.Activities;
using System.ComponentModel;
namespace ClassMathCustomActivity
{
public class SimpleFormula : CodeActivity
{
[Category("Input")]
[RequiredArgument]
public InArgument<double> FirstNumber { get; set; }
[Category("Input")]
public InArgument<double> SecondNumber { get; set; }
[Category("Output")]
public OutArgument<double> ResultNumber { get; set; }
protected override void Execute(CodeActivityContext context)
{
var firstNumber = FirstNumber.Get(context);
var secondNumber = SecondNumber.Get(context);
var result = System.Math.Pow(firstNumber + secondNumber, 2);
ResultNumber.Set(context, result);
}
}
}
您需要做的最重要的更改是执行方法,该方法必须是 ExecuteAsync 。
建议的解决方案是创建 AsyncTaskCodeActivity.cs 类 ,该类应如下所示:
using System;
using System.Activities;
using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;
namespace ClassMathCustomActivity
{
internal struct AsyncTaskCodeActivityImplementation : IDisposable
{
private CancellationTokenSource _cancellationTokenSource;
private bool _tokenDisposed;
public void Cancel()
{
if (!_tokenDisposed)
{
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
_tokenDisposed = true;
}
}
public IAsyncResult BeginExecute(AsyncCodeActivityContext context
, Func<AsyncCodeActivityContext, CancellationToken, Task<Action<AsyncCodeActivityContext>>> onExecute
, AsyncCallback callback, object state)
{
if (!_tokenDisposed)
{
_cancellationTokenSource?.Dispose();
}
_cancellationTokenSource = new CancellationTokenSource();
_tokenDisposed = false;
TaskCompletionSource<Action<AsyncCodeActivityContext>> taskCompletionSource = new TaskCompletionSource<Action<AsyncCodeActivityContext>>(state);
Task<Action<AsyncCodeActivityContext>> task = onExecute(context, _cancellationTokenSource.Token);
var cancellationTokenSource = _cancellationTokenSource;
task.ContinueWith(t =>
{
if (t.IsFaulted)
{
taskCompletionSource.TrySetException(t.Exception.InnerException);
}
else if (t.IsCanceled || cancellationTokenSource.IsCancellationRequested)
{
taskCompletionSource.TrySetCanceled();
}
else
{
taskCompletionSource.TrySetResult(t.Result);
}
callback?.Invoke(taskCompletionSource.Task);
});
return taskCompletionSource.Task;
}
public void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
Task<Action<AsyncCodeActivityContext>> task = (Task<Action<AsyncCodeActivityContext>>)result;
if (task.IsFaulted)
{
ExceptionDispatchInfo.Capture(task.Exception.InnerException).Throw();
}
if (task.IsCanceled)
{
context.MarkCanceled();
}
task.Result?.Invoke(context);
if (!_tokenDisposed)
{
_cancellationTokenSource?.Dispose();
_tokenDisposed = true;
}
}
private bool _disposed; // To detect redundant calls
public void Dispose()
{
if (!_disposed)
{
if (!_tokenDisposed)
{
if (_cancellationTokenSource != null)
_cancellationTokenSource.Dispose();
_tokenDisposed = true;
}
_disposed = true;
}
}
}
public abstract class AsyncTaskCodeActivity : AsyncCodeActivity, IDisposable
{
private AsyncTaskCodeActivityImplementation _impl = new AsyncTaskCodeActivityImplementation();
protected override void Cancel(AsyncCodeActivityContext context)
{
_impl.Cancel();
base.Cancel(context);
}
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
return _impl.BeginExecute(context, ExecuteAsync, callback, state);
}
protected override void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
_impl.EndExecute(context, result);
}
protected abstract Task<Action<AsyncCodeActivityContext>> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken);
#region IDisposable Support
private bool _disposed = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
}
_impl.Dispose(); //structs are not garbage collected so they fit in the unmanaged bucket
_disposed = true;
}
}
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
public abstract class AsyncTaskCodeActivity<T> : AsyncCodeActivity<T>, IDisposable
{
private AsyncTaskCodeActivityImplementation _impl = new AsyncTaskCodeActivityImplementation();
protected override void Cancel(AsyncCodeActivityContext context)
{
_impl.Cancel();
base.Cancel(context);
}
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
return _impl.BeginExecute(context, ExecuteAsync, callback, state);
}
protected override T EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
_impl.EndExecute(context, result);
return Result.Get(context);
}
protected abstract Task<Action<AsyncCodeActivityContext>> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken);
#region IDisposable Support
private bool _disposed = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
}
_impl.Dispose(); //structs are not garbage collected so they fit in the unmanaged bucket
_disposed = true;
}
}
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}
using System;
using System.Activities;
using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;
namespace ClassMathCustomActivity
{
internal struct AsyncTaskCodeActivityImplementation : IDisposable
{
private CancellationTokenSource _cancellationTokenSource;
private bool _tokenDisposed;
public void Cancel()
{
if (!_tokenDisposed)
{
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
_tokenDisposed = true;
}
}
public IAsyncResult BeginExecute(AsyncCodeActivityContext context
, Func<AsyncCodeActivityContext, CancellationToken, Task<Action<AsyncCodeActivityContext>>> onExecute
, AsyncCallback callback, object state)
{
if (!_tokenDisposed)
{
_cancellationTokenSource?.Dispose();
}
_cancellationTokenSource = new CancellationTokenSource();
_tokenDisposed = false;
TaskCompletionSource<Action<AsyncCodeActivityContext>> taskCompletionSource = new TaskCompletionSource<Action<AsyncCodeActivityContext>>(state);
Task<Action<AsyncCodeActivityContext>> task = onExecute(context, _cancellationTokenSource.Token);
var cancellationTokenSource = _cancellationTokenSource;
task.ContinueWith(t =>
{
if (t.IsFaulted)
{
taskCompletionSource.TrySetException(t.Exception.InnerException);
}
else if (t.IsCanceled || cancellationTokenSource.IsCancellationRequested)
{
taskCompletionSource.TrySetCanceled();
}
else
{
taskCompletionSource.TrySetResult(t.Result);
}
callback?.Invoke(taskCompletionSource.Task);
});
return taskCompletionSource.Task;
}
public void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
Task<Action<AsyncCodeActivityContext>> task = (Task<Action<AsyncCodeActivityContext>>)result;
if (task.IsFaulted)
{
ExceptionDispatchInfo.Capture(task.Exception.InnerException).Throw();
}
if (task.IsCanceled)
{
context.MarkCanceled();
}
task.Result?.Invoke(context);
if (!_tokenDisposed)
{
_cancellationTokenSource?.Dispose();
_tokenDisposed = true;
}
}
private bool _disposed; // To detect redundant calls
public void Dispose()
{
if (!_disposed)
{
if (!_tokenDisposed)
{
if (_cancellationTokenSource != null)
_cancellationTokenSource.Dispose();
_tokenDisposed = true;
}
_disposed = true;
}
}
}
public abstract class AsyncTaskCodeActivity : AsyncCodeActivity, IDisposable
{
private AsyncTaskCodeActivityImplementation _impl = new AsyncTaskCodeActivityImplementation();
protected override void Cancel(AsyncCodeActivityContext context)
{
_impl.Cancel();
base.Cancel(context);
}
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
return _impl.BeginExecute(context, ExecuteAsync, callback, state);
}
protected override void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
_impl.EndExecute(context, result);
}
protected abstract Task<Action<AsyncCodeActivityContext>> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken);
#region IDisposable Support
private bool _disposed = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
}
_impl.Dispose(); //structs are not garbage collected so they fit in the unmanaged bucket
_disposed = true;
}
}
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
public abstract class AsyncTaskCodeActivity<T> : AsyncCodeActivity<T>, IDisposable
{
private AsyncTaskCodeActivityImplementation _impl = new AsyncTaskCodeActivityImplementation();
protected override void Cancel(AsyncCodeActivityContext context)
{
_impl.Cancel();
base.Cancel(context);
}
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
return _impl.BeginExecute(context, ExecuteAsync, callback, state);
}
protected override T EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
_impl.EndExecute(context, result);
return Result.Get(context);
}
protected abstract Task<Action<AsyncCodeActivityContext>> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken);
#region IDisposable Support
private bool _disposed = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
}
_impl.Dispose(); //structs are not garbage collected so they fit in the unmanaged bucket
_disposed = true;
}
}
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}
更改后的活动应如下所示:
using System;
using System.Threading.Tasks;
using UiPath.Marketplace.License.Validations;
using System.ComponentModel;
using System.Activities;
using System.Threading;
namespace ClassMathCustomActivity
{
public class SimpleFormula : AsyncTaskCodeActivity
{
[Category("Input")]
[RequiredArgument]
public InArgument<double> FirstNumber { get; set; }
[Category("Input")]
public InArgument<double> SecondNumber { get; set; }
[Category("Output")]
public OutArgument<double> ResultNumber { get; set; }
protected override async Task<Action<AsyncCodeActivityContext>> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken)
{
var firstNumber = FirstNumber.Get(context);
var secondNumber = SecondNumber.Get(context);
// check for license after reading input arguments
#if !DEBUG
//if your package is MyCompany.MyPackageName.Activities.1.0.0.nupkg
await Validator.ValidateAsync(context, "MyCompany.MyPackageName.Activities");
#endif
return (ctx) =>
{
var result = System.Math.Pow(firstNumber + secondNumber, 2);
ResultNumber.Set(ctx, result);
};
}
}
}
using System;
using System.Threading.Tasks;
using UiPath.Marketplace.License.Validations;
using System.ComponentModel;
using System.Activities;
using System.Threading;
namespace ClassMathCustomActivity
{
public class SimpleFormula : AsyncTaskCodeActivity
{
[Category("Input")]
[RequiredArgument]
public InArgument<double> FirstNumber { get; set; }
[Category("Input")]
public InArgument<double> SecondNumber { get; set; }
[Category("Output")]
public OutArgument<double> ResultNumber { get; set; }
protected override async Task<Action<AsyncCodeActivityContext>> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken)
{
var firstNumber = FirstNumber.Get(context);
var secondNumber = SecondNumber.Get(context);
// check for license after reading input arguments
#if !DEBUG
//if your package is MyCompany.MyPackageName.Activities.1.0.0.nupkg
await Validator.ValidateAsync(context, "MyCompany.MyPackageName.Activities");
#endif
return (ctx) =>
{
var result = System.Math.Pow(firstNumber + secondNumber, 2);
ResultNumber.Set(ctx, result);
};
}
}
}
请务必在读取所有输入参数后立即执行第 24 行。 在上面的示例中,第 20 和 21 行用于读取输入参数,第 26 到 30 行用于设置输出参数。
最后一件事 - 创建 .nupkg 包,请确保包内容(位于 lib 文件夹中)中存在 许可证 .dll 库。