Escrever um plug-in

Você pode criar plug-ins usando um dos seguintes métodos:

  • As ferramentas de desenvolvimento do Power Platform fornecem uma maneira moderna de criar plug-ins. As ferramentas que estão sendo referenciadas aqui são As Ferramentas do Power Platform para Visual Studio e a CLI do Power Platform. Essas duas ferramentas do Power Platform geram um código de plug-in semelhante, portanto, mover de um método de ferramentas para o outro é bastante fácil e compreensível.

    • Use Power Platform Tools for Visual Studio para criar rapidamente código de modelo de plug-in e registrar (implantar) um plug-in. Um artigo de início rápido está disponível para mostrar como. Use essa ferramenta se você quiser trabalhar em Visual Studio.

    • Use a CLI do Power Platform para criar um projeto básico de plug-in (compatível com o Visual Studio) com código de plug-in de modelo usando um único comando pac plugin. Posteriormente, usando o comando prt da ferramenta pac, você usa interativamente a ferramenta Registro de Plug-in para registrar sua criação com Microsoft Dataverse. Use este conjunto de ferramentas da CLI se você quiser trabalhar em uma janela de terminal ou Visual Studio Code.

  • Escreva manualmente o código usando Visual Studio ou seu editor favorito. Este artigo se concentra na escrita de código usando APIs do Dataverse, no entanto, os conceitos introduzidos também se aplicam ao desenvolvimento de plug-in usando nossas ferramentas mencionadas anteriormente.

Interface IPlugin

Um plug-in é uma classe compilada em um assembly destinado ao .NET Framework. Cada classe em um projeto de plug-in que esteja registrada em uma etapa do pipeline de eventos deve implementar a interface IPlugin, que define um único método IPlugin.Execute.

public class MyPlugin : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        throw new NotImplementedException();
    }
}

O Execute método aceita um único IServiceProvider parâmetro. O IServiceProvider tem um único método: GetService. Use esse método para obter vários tipos diferentes de serviços que você pode usar em seu código.

Mais informações: serviços que você pode usar em seu código

Importante

Ao derivar de IPlugin, a classe deve ser escrita sem estado. Isso ocorre porque a plataforma armazena em cache uma instância de classe e a reutiliza por motivos de desempenho. Uma maneira simples de pensar sobre isso é que você não deve adicionar nenhuma propriedade ou método à classe e tudo deve ser incluído no Execute método.

Ao usar a extensão ferramentas do Power Platform ou a CLI do Power Platform para criação de plug-in, a classe gerada PluginBase implementa a IPlugin interface.

Há algumas exceções à instrução sobre como adicionar propriedades ou métodos na observação acima. Por exemplo, você pode ter uma propriedade que representa uma constante e pode ter métodos que são chamados pelo método Execute. O importante é que você nunca armazena dados de instância de serviço ou contexto como uma propriedade em sua classe. Esses valores mudam a cada invocação e você não deseja que esses dados sejam armazenados em cache e aplicados às invocações subsequentes.

Mais informações: Desenvolva implementações de IPlugin sem estado, Personalizações com suporte para o Dataverse

Passar dados de configuração para o plug-in

Ao registrar um plug-in, você pode, opcionalmente, especificar dados de configuração a serem passados ao plug-in em tempo de execução. Os dados de configuração permitem definir como uma instância específica de um plug-in registrado deve se comportar. Essas informações são passadas como dados de cadeia de caracteres para parâmetros no construtor de sua classe. Há dois parâmetros nomeados unsecure e secure. Use o primeiro unsecure parâmetro para dados que você não se importa se outra pessoa pode ver. Use o segundo secure parâmetro para dados confidenciais.

O código a seguir mostra as três assinaturas de construtor possíveis para uma classe de plug-in chamada MyPlugin.

public MyPlugin() {}
public MyPlugin(string unsecure) {}  
public MyPlugin(string unsecure, string secure) {}

Os dados de configuração segura são armazenados em uma tabela separada que somente os administradores do sistema têm privilégios para ler.

Mais informações: Registrar etapa do plug-in > Definir dados de configuração

Classe abstrata PluginBase

A classe PluginBase implementa a interface IPlugin. Oferecemos essa classe, pois ela implementa um padrão de programação robusto que se provou em soluções comerciais. No entanto, o uso dessa classe no código do plug-in é opcional, mas recomendado.

A classe não está disponível em nenhum assembly do SDK, em vez disso, você deve gerar a classe usando uma de nossas ferramentas. Para gerar a classe, crie um projeto de plug-in na extensão ferramentas do Power Platform para Visual Studio ou execute o comando pac plugin initda CLI do Power Platform. Você encontrará um arquivo PluginBase.cs no projeto gerado.

Mais informações: plug-in pac, Início Rápido: Criar um plug-in usando o Power Platform Tools

Importante

A PluginBase classe gerada pela extensão ferramentas do Power Platform e pela CLI do Power Platform tem assinaturas de membro de classe ligeiramente diferentes. É melhor escolher um ou outro e ficar com ele em todo o desenvolvimento de código do plug-in. Ambas as versões da classe têm a mesma funcionalidade e têm o mesmo desempenho.

Este diagrama de classe fornece um visual nas interfaces de chave e classes relacionadas a PluginBase.

Classe PluginBase e outros tipos relacionados.

A classe de exemplo Plugin1 (no diagrama) deriva de PluginBase. Você renomearia essa Plugin1 classe para seu próprio nome personalizado e adicionaria código para implementar o método e o ExecuteDataversePlugin construtor de classe. A classe LocalPluginContext é inicializada automaticamente com as referências de serviço e os endpoints indicados, disponíveis para o seu plug-in. Se você estivesse implementando a interface IPlugin, teria que escrever código para inicializar todos esses serviços e endpoints antes de usá-los.

Serviços que você pode usar em seu código

Normalmente, em seu plug-in, você irá:

  • Acesse os dados contextuais fornecidos ao seu plug-in para identificar informações sobre a entidade e a requisição de mensagem que causou o evento e acionou o seu plug-in. Esses dados são chamados de contexto de execução.
  • Acesse o serviço Web da organização usando o SDK para chamadas .NET para executar operações de solicitação de mensagem, como consulta, criação, atualização, exclusão e muito mais.
  • Escreva mensagens no serviço de rastreamento para que você possa avaliar como o código do plug-in está sendo executado.

Note

Todos os serviços do Dataverse que seu plug-in normalmente usa e o contexto de execução do plug-in são pré-configurados e ficam disponíveis para o código do plug-in quando você deriva seu plug-in da classe PluginBase.

O método IServiceProvider.GetService oferece uma forma de acessar referências a serviços passadas no contexto de execução quando necessário. Para obter uma instância de um serviço, você invoca o GetService método que passa o tipo de serviço. Leia mais sobre esse método nas próximas seções.

Contexto de execução

O contexto de execução contém uma grande quantidade de informações que um plug-in pode precisar. O contexto é obtido usando o código a seguir.

IPluginExecutionContext context = (IPluginExecutionContext)
    serviceProvider.GetService(typeof(IPluginExecutionContext));

Mais informações: IPluginExecutionContext, entenda o contexto de execução

Serviço Web da organização

Além dos dados passados no contexto de execução, os dados da linha de tabela do Dataverse podem ser lidos ou gravados no código do plug-in usando chamadas do SDK para o serviço Web da organização. Não tente usar a API Web, pois ela não tem suporte em plug-ins. Além disso, não autentique o usuário antes de acessar os serviços Web, pois o usuário é pré-autenticado antes da execução do plug-in.

Mais informações: Operações da tabela, Usar mensagens

Para obter uma referência de objeto ao serviço Web da organização, use o seguinte código:

IOrganizationServiceFactory serviceFactory =
    (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService orgService = serviceFactory.CreateOrganizationService(context.UserId);

Serviço de rastreamento

Use o serviço de rastreamento para gravar mensagens na Tabela PluginTraceLog para que você possa examinar os logs para entender o que ocorreu quando o plug-in foi executado.

Importante

Primeiro, você deve habilitar o log de rastreamento em seu ambiente antes de poder gravar ou exibir os logs. Mais informações: Rastreamento e registro em log

Para gravar no Tracelog, você precisa obter uma instância do serviço de rastreamento. O código a seguir mostra como obter uma instância do serviço de Rastreamento usando o IServiceProvidermétodo .GetService

ITracingService tracingService =
    (ITracingService)serviceProvider.GetService(typeof(ITracingService));

Para gravar no rastreamento, use o método ITracingService.Trace.

tracingService.Trace("Write {0} {1}.", "your", "message");

Mais informações: Usar rastreamento, Rastreamento e registro em log.

Outros serviços

Quando você escreve um plug-in que usa Barramento de Serviço do Azure integração, use o serviço de notificação que implementa a IServiceEndpointNotificationService interface, mas essa interface não será descrita aqui.

Mais informações: Azure Integration

Integrando tudo

A aplicação dos conceitos de plug-in detalhados anteriormente resulta em um código de plug-in semelhante ao seguinte.

public class MyPlugin : PluginBase
{
  // Constructor
  public MyPlugin(string unsecureConfiguration, string secureConfiguration)
       : base(typeof(MyPlugin))
  { }

  protected override void ExecuteDataversePlugin(ILocalPluginContext localPluginContext)
  {
    if (localPluginContext == null)
    {
      throw new ArgumentNullException(nameof(localPluginContext));
    }

    var context        = localPluginContext.PluginExecutionContext;
    var serviceFactory = localPluginContext.OrgSvcFactory;
    var tracingService = localPluginContext.TracingService;

    try
    {
      // TODO Plug-in business logic goes here. You can access data in the context,
      // and make calls to the Organization web service using the Dataverse SDK.
    }
    catch (FaultException<OrganizationServiceFault> ex)
    {
      throw new InvalidPluginExecutionException("The following error occurred in MyPlugin.", ex);
    }
    catch (Exception ex)
    {
        tracingService.Trace("MyPlugin: error: {0}", ex.ToString());
        throw;
    }
  }
}

Você pode examinar esses dois métodos de implementações de plug-in em nosso exemplo de código FollowupPlugin . Para obter mais informações sobre como lidar com exceções em plug-ins, consulte Tratar exceções em plug-ins.

O design do plug-in afeta o desempenho

Ao escrever seu plug-in, é fundamental que ele seja executado de forma eficiente e rápida. Quanto mais tempo o plug-in levar para ser executado, mais tempo o usuário final que chamou a operação de mensagem (que disparou o plug-in) terá de esperar. Além de processar a operação da mensagem, o Dataverse executa todos os plug-ins síncronos registrados no pipeline, incluindo o seu plug-in. Quando os plug-ins demoram muito para serem executados ou se muitos plug-ins são registrados em um pipeline, esse impacto no desempenho pode resultar em uma interface do usuário de aplicativo não responsiva ou, na pior das hipóteses, um erro de tempo limite com a reversão do pipeline.

Importante

Os plug-ins devem seguir um limite de tempo de execução e restrições de recurso. Mais informações: Analisar o desempenho do plug-in

Usando tipos associados antecipadamente no código de plug-in

Opcionalmente, você pode usar tipos associados antecipadamente no código do plug-in. Inclua o arquivo de tipos gerados em seu projeto de plug-in. Todos os tipos de tabela fornecidos na coleção InputParameters do contexto de execução são tipos vinculados tardiamente. Seria necessário converter esses tipos de vinculação tardia em tipos de vinculação antecipada.

Por exemplo, você pode fazer o seguinte quando souber que o Target parâmetro representa uma tabela de conta. Neste exemplo, "Account" é um tipo de vinculação antecipada.

Account acct = context.InputParameters["Target"].ToEntity<Account>();

Mas você nunca deve tentar definir o valor usando um tipo de vinculação antecipada. Fazer isso faz com que ocorra uma SerializationException ocorrência.

context.InputParameters["Target"] = new Account() { Name = "MyAccount" }; // WRONG: Do not do this. 

Consulte também

Manipular exceções
Registrar um plug-in
Depuração de plug-ins
Tutorial: Escrever e registrar um plug-in
Práticas recomendadas e diretrizes sobre o desenvolvimento de plug-in e fluxo de trabalho