UiPath Documentation
marketplace
latest
false
重要 :
请注意,此内容已使用机器翻译进行了本地化。 新发布内容的本地化可能需要 1-2 周的时间才能完成。
UiPath logo, featuring letters U and I in white

Marketplace 用户指南

上次更新日期 2026年4月1日

许可实施

本文档部分将指导您完成将许可 SDK 库嵌入到活动包中的过程。

请根据您的包是使用还是未使用 UiPath Activity Creator 开发的,请按照以下步骤操作:

重要提示:

您的 VS 解决方案需要与 .Net 4.6.1 兼容。

备注:

.NET 6 或 Windows 兼容自定义活动的许可实施责任由供应商承担。 Marketplace 不提供 .NET6 兼容许可库。 它提供与 Windows 旧版兼容的许可库。

In case your package was developed using the UiPath Activity Creator

  1. 除非您有作用域活动场景,否则在每个活动的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) => {
                };
            }
    
    备注:
    • The context object can be passed only once and used only in the method it was passed into. For example, after the Validator.ValidateAsync call, it can not be used anymore in the ExecuteAsync method.
    • 考虑到上述要求,这也意味着在将上下文传递给许可方法/库之前,必须读取输入变量。
  2. Reference the Licensing.dll library into your .Activities project and add the using statement:

    文档图像

    using UiPath.Marketplace.License.Validations;

  3. The setup is complete - build your package, and make sure that the Licensing.dll library is present inside the package contents (within the lib folder). Afterward, you can submit it on the Marketplace.

如果您的包并非使用 UiPath Activity Creator 开发

如果您的初始活动如下所示:

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);
        }
    }
}

The most important change that you need to make is to the execute method, which needs to be an ExecuteAsync.

The proposed solution is to create AsyncTaskCodeActivity.cs class that should look like this:

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 行用于设置输出参数。

One last thing - when creating your .nupkg package, please make sure that the Licensing.dll library is present inside the package contents (within the lib folder).

常见问题

实施这些更改后会发生什么?

实施更改并构建 .nupkg 后,您需要将其提交到 Marketplace 进行发布。

我可以获得用于测试目的的许可证文件吗?

否,为了测试活动,您可以使用 C# 预处理器指令进行调试 (#if !DEBUG)

客户将如何获取许可证文件?

有人购买后,许可证.lic系统将生成该文件,并将其在 UiPath Marketplace 上提供给他们。客户将能够下载文件,然后按照必要步骤使用活动。

此页面有帮助吗?

连接

需要帮助? 支持

想要了解详细内容? UiPath Academy

有问题? UiPath 论坛

保持更新