Usando contadores de desempenho do SignalR em uma Função Web do Azure

Por Luke Latham

Aviso

Esta documentação não é para a versão mais recente do SignalR. Dê uma olhada em ASP.NET Core SignalR.

Os contadores de desempenho do SignalR são usados para monitorar o desempenho do aplicativo em uma Função Web do Azure. Os contadores são capturados pelo Microsoft Diagnóstico do Azure. Instale contadores de desempenho do SignalR no Azure com signalr.exe, a mesma ferramenta usada para aplicativos autônomos ou locais. Como as funções do Azure são transitórias, você configura um aplicativo para instalar e registrar contadores de desempenho do SignalR na inicialização.

Pré-requisitos

Criar um aplicativo de Função Web do Azure que expõe contadores de desempenho do SignalR

  1. Abra o Visual Studio.

  2. No Visual Studio, selecione Arquivo>Novo>Projeto.

  3. Na caixa de diálogo Novo Projeto , selecione a categoria Visual C#>Cloud à esquerda e, em seguida, selecione o modelo serviço de nuvem do Azure . Nomeie o aplicativo SignalRPerfCounters e selecione OK.

    Novo aplicativo de nuvem

    Observação

    Se você não vir a categoria de modelo de nuvem ou o modelo do Serviço de Nuvem do Azure , será necessário instalar a carga de trabalho de desenvolvimento do Azure para Visual Studio 2017. Escolha o link Abrir Instalador do Visual Studio no lado inferior esquerdo da caixa de diálogo Novo Projeto para abrir Instalador do Visual Studio. Selecione a carga de trabalho de desenvolvimento do Azure e escolha Modificar para começar a instalar a carga de trabalho.

    Carga de trabalho de desenvolvimento do Azure no Instalador do Visual Studio

  4. Na caixa de diálogo Novo Serviço de Nuvem do Microsoft Azure , selecione ASP.NET Função Web e selecione o > botão para adicionar a função ao projeto. Selecione OK.

    Adicionar ASP.NET Função Web

  5. Na caixa de diálogo Novo Aplicativo Web ASP.NET – WebRole1 , selecione o modelo MVC e, em seguida, selecione OK.

    Adicionar MVC e API Web

  6. Em Gerenciador de Soluções, abra o arquivo diagnóstico.wadcfgxem WebRole1.

    Gerenciador de Soluções diagnóstico.wadcfgx

  7. Substitua o conteúdo do arquivo pela seguinte configuração e salve o arquivo:

    <?xml version="1.0" encoding="utf-8"?>
    <DiagnosticsConfiguration xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration">
      <PublicConfig>
        <WadCfg>
          <DiagnosticMonitorConfiguration overallQuotaInMB="4096">
            <DiagnosticInfrastructureLogs scheduledTransferLogLevelFilter="Error" />
            <Logs scheduledTransferPeriod="PT1M" scheduledTransferLogLevelFilter="Error" />
            <Directories scheduledTransferPeriod="PT1M">
              <IISLogs containerName ="wad-iis-logfiles" />
              <FailedRequestLogs containerName ="wad-failedrequestlogs" />
            </Directories>
            <WindowsEventLog scheduledTransferPeriod="PT1M">
              <DataSource name="Application!*[System[(Level=1 or Level=2 or Level=3)]]" />
              <DataSource name="Windows Azure!*[System[(Level=1 or Level=2 or Level=3 or Level=4)]]" />
            </WindowsEventLog>
            <CrashDumps containerName="wad-crashdumps" dumpType="Mini">
              <CrashDumpConfiguration processName="WaIISHost.exe" />
              <CrashDumpConfiguration processName="WaWorkerHost.exe" />
              <CrashDumpConfiguration processName="w3wp.exe" />
            </CrashDumps>
            <PerformanceCounters scheduledTransferPeriod="PT1M">
              <PerformanceCounterConfiguration counterSpecifier="\Memory\Available MBytes" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\Web Service(_Total)\ISAPI Extension Requests/sec" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\Web Service(_Total)\Bytes Total/Sec" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\ASP.NET Applications(__Total__)\Requests/Sec" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\ASP.NET Applications(__Total__)\Errors Total/Sec" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\ASP.NET\Requests Queued" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\ASP.NET\Requests Rejected" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\Processor(_Total)\% Processor Time" sampleRate="PT3M" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Memory(w3wp)\% Time in GC" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Exceptions(w3wp)\# of Exceps Thrown / sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR LocksAndThreads(w3wp)\# of current logical Threads" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR LocksAndThreads(w3wp)\# of current physical Threads" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR LocksAndThreads(w3wp)\Current Queue Length" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR LocksAndThreads(w3wp)\Contention Rate / sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Memory(w3wp)\# Bytes in all Heaps" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Memory(w3wp)\# GC Handles" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Memory(w3wp)\# of Pinned Objects" sampleRate="PT10S" />
    
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connections Connected" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connections Reconnected" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connections Disconnected" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connections Current" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connection Messages Received Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connection Messages Sent Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connection Messages Received/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connection Messages Sent/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Messages Received Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Messages Received/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Message Bus Messages Received/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Messages Published Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Messages Published/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Subscribers Current" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Subscribers Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Subscribers/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Allocated Workers" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Busy Workers" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Topics Current" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: All Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: All/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Hub Resolution Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Hub Resolution/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Hub Invocation Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Hub Invocation/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Tranport Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Transport/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Streams Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Streams Open" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Streams Buffering" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Errors Total" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Errors/Sec" sampleRate="PT10S" />
              <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Send Queue Length" sampleRate="PT10S" />
            </PerformanceCounters>
          </DiagnosticMonitorConfiguration>
        </WadCfg>
        <StorageAccount></StorageAccount>
      </PublicConfig>
      <PrivateConfig>
        <StorageAccount name="" key="" endpoint="" />
      </PrivateConfig>
      <IsEnabled>true</IsEnabled>
    </DiagnosticsConfiguration>
    
  8. Abra o Console do Gerenciador de Pacotes em FerramentasGerenciador de Pacotes> NuGet. Insira os seguintes comandos para instalar a versão mais recente do SignalR e o pacote de utilitários do SignalR:

    install-package microsoft.aspnet.signalr
    install-package microsoft.aspnet.signalr.utils
    
  9. Configure o aplicativo para instalar os contadores de desempenho do SignalR na instância de função quando ele for iniciado ou reciclar. Em Gerenciador de Soluções, clique com o botão direito do mouse no projeto WebRole1 e selecione Adicionar>Nova Pasta. Nomeie a nova pasta como Inicialização.

    Adicionar Pasta de Inicialização

  10. Copie o arquivo designalr.exe (adicionado com o pacote Microsoft.AspNet.SignalR.Utils) da pasta> do <projeto/SignalRPerfCounters/packages/Microsoft.AspNet.SignalR.Utils.<version>/tools para a pasta Inicialização que você criou na etapa anterior.

  11. Em Gerenciador de Soluções, clique com o botão direito do mouse na pasta Inicialização e selecione Adicionar>Item Existente. Na caixa de diálogo exibida, selecione signalr.exe e selecione Adicionar.

    Adicionar signalr.exe ao projeto

  12. Clique com o botão direito do mouse na pasta Inicialização que você criou. Selecione Adicionar>Novo Item. Selecione o nó Geral , selecione Arquivo de Texto e nomeie o novo item SignalRPerfCounterInstall.cmd. Esse arquivo de comando instalará os contadores de desempenho do SignalR na função Web.

    Criar arquivo em lote de instalação do contador de desempenho do SignalR

  13. Quando o Visual Studio cria o arquivo SignalRPerfCounterInstall.cmd, ele é aberto automaticamente na janela main. Substitua o conteúdo do arquivo pelo script a seguir e salve e feche o arquivo. Esse script executa signalr.exe, que adiciona os contadores de desempenho do SignalR à instância de função.

    SET SignalR_LogDir=%~dp0Log\
    MKDIR "%SignalR_LogDir%"
    cd %~dp0
    signalr.exe ipc >> "%SignalR_LogDir%SignalR_Log.txt" 2>&1
    net localgroup "Performance Monitor Users" "Network Service" /ADD >> "%SignalR_LogDir%NetworkAdd.txt" 2>&1
    
  14. Selecione o arquivo designalr.exe no Gerenciador de Soluções. Nas Propriedades do arquivo, defina Copiar para Diretório de Saída como Copiar Sempre.

    Definir Copiar para Diretório de Saída para Copiar Sempre

  15. Repita a etapa anterior para o arquivo SignalRPerfCounterInstall.cmd .

  16. Clique com o botão direito do mouse no arquivo SignalRPerfCounterInstall.cmd e selecione Abrir com. Na caixa de diálogo exibida, selecione Editor Binário e selecione OK.

    Abrir com o Editor Binário

  17. No editor binário, selecione todos os bytes à esquerda no arquivo e exclua-os. Salve e feche o arquivo.

    Excluir bytes à esquerda

  18. Abra ServiceDefinition.csdef e adicione uma tarefa de inicialização que execute o arquivo SignalrPerfCounterInstall.cmd quando o serviço for iniciado:

    <?xml version="1.0" encoding="utf-8"?>
    <ServiceDefinition name="SignalRPerfCounters" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2015-04.2.6">
      <WebRole name="WebRole1" vmsize="Small">
        <Startup>
          <Task commandLine="Startup\SignalRPerfCounterInstall.cmd" executionContext="elevated" taskType="background" />
        </Startup>
        <Sites>
          <Site name="Web">
            <Bindings>
              <Binding name="Endpoint1" endpointName="Endpoint1" />
            </Bindings>
          </Site>
        </Sites>
        <Endpoints>
          <InputEndpoint name="Endpoint1" protocol="http" port="80" />
        </Endpoints>
      </WebRole>
    </ServiceDefinition>
    
  19. Abra Views/Shared/_Layout.cshtml e remova o script de pacote jQuery do final do arquivo.

    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - My ASP.NET Application</p>
        </footer>
    </div>
    
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
    </body>
    </html>
    
  20. Adicione um cliente JavaScript que chama continuamente o increment método no servidor. Abra Views/Home/Index.cshtml e substitua o conteúdo pelo seguinte código:

    @{
        ViewBag.Title = "Home Page";
    }
    
    <script src="~/Scripts/jquery-1.10.2.min.js"></script>
    <script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script>
    <script src="~/signalr/hubs" type="text/javascript"></script>
    
    <div id="body">
        <section class="featured">
            <div class="content-wrapper">
                <p>
                    Hello World!
                </p>
                <div style="font-size:large;">
                    My Counter: <span id="counter"></span>
                </div>
            </div>
        </section>
        <section class="content-wrapper main-content clear-fix"></section>
    </div>
    
    <script type="text/javascript">
      $(document).ready(function () {
        var hub = $.connection.myHub;
    
        hub.client.sendResult = function (x) {
          console.log('sendResult(' + x + ')');
          $("#counter").text(x);
          window.setTimeout(function () {
            hub.server.increment(x);
          }, 1000);
        };
    
        $.connection.hub.connected = function () {};
        $.connection.hub.disconnected = function () {};
    
        $.connection.hub.stateChanged(function (change) {
          console.log('new State' + change.newState);
          if (change.newState === $.signalR.connectionState.disconnected) {
            $.connection.hub.start();
          }
          if (change.newState === $.signalR.connectionState.reconnecting) {
            console.log('Re-connecting');
          } else if (change.newState === $.signalR.connectionState.connected) {
            console.log('The server is online');
          }
        });
    
        $.connection.hub.error(function (error) {
          console.log('error ' + error);
        });
        
        $.connection.hub.logging = true;
        
        $.connection.hub.reconnected(function () {
          console.log('Reconnected');
          hub.server.increment(0);
        });
    
        $.connection.hub.start().done(function () {
          console.log('hub started');
          hub.server.increment(0);
        });
      });
    </script>
    
  21. Crie uma nova pasta no projeto WebRole1 chamada Hubs. Clique com o botão direito do mouse na pasta Hubs no Gerenciador de Soluções e selecione Adicionar>Novo Item. Na caixa de diálogo Adicionar Novo Item , selecione a categoria Web>SignalR e, em seguida, selecione o modelo de item Classe do Hub do SignalR (v2 ). Nomeie o novo hub MyHub.cs e selecione Adicionar.

    Adicionando a Classe do Hub SignalR à pasta Hubs na caixa de diálogo Adicionar Novo Item

  22. O MyHub.cs será aberto automaticamente na janela main. Substitua o conteúdo pelo seguinte código e salve e feche o arquivo:

    using System.Threading.Tasks;
    using Microsoft.AspNet.SignalR;
    
    namespace WebRole1.Hubs
    {
        public class MyHub : Hub
        {
            public async Task Increment(int x)
            {
                await this.Clients.Caller.sendResult(x + 1);
            }
        }
    }
    
  23. Crank.exe é uma ferramenta de teste de densidade de conexão fornecida com a base de código do SignalR. Como o Crank requer uma conexão persistente, você adiciona um ao seu site para uso durante o teste. Adicione uma nova pasta ao projeto WebRole1 chamado PersistentConnections. Clique com o botão direito do mouse nesta pasta e selecione Adicionar>Classe. Nomeie o novo arquivo de classe MyPersistentConnections.cs e selecioneAdicionar.

  24. O Visual Studio abrirá o arquivo MyPersistentConnections.cs na janela main. Substitua o conteúdo pelo seguinte código e salve e feche o arquivo:

    using System.Threading.Tasks;
    using Microsoft.AspNet.SignalR;
    using Microsoft.AspNet.SignalR.Infrastructure;
    
    namespace WebRole1.PersistentConnections
    {
        public class MyPersistentConnection : PersistentConnection
        {
            protected override Task OnReceived(IRequest request, string connectionId, string data)
            {
                //Return data to calling user
                return Connection.Send(connectionId, data);        
            }
        }
    }
    
  25. Usando a Startup classe , os objetos SignalR são iniciados quando o OWIN é iniciado. Abra ou crie Startup.cs e substitua o conteúdo pelo seguinte código:

    using Microsoft.Owin;
    using Owin;
    using WebRole1.PersistentConnections;
    
    // Marks this class for automatic OWIN startup
    [assembly: OwinStartup(typeof(WebRole1.Startup))]
    namespace WebRole1
    {
        public partial class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                ConfigureAuth(app);
                // Only needed if "No Authentication" was not selected for the project
                app.MapSignalR();
                app.MapSignalR<MyPersistentConnection>("/echo");
            }
        }
    }
    

    No código acima, o OwinStartup atributo marca essa classe para iniciar o OWIN. O Configuration método inicia o SignalR.

  26. Teste seu aplicativo no Emulador do Microsoft Azure pressionando F5.

    Observação

    Se você encontrar um FileLoadException em MapSignalR, altere os redirecionamentos de associação em web.config para o seguinte:

    <dependentAssembly>
      <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
      <bindingRedirect oldVersion="0.0.0.0-2.0.2.0" newVersion="2.0.0.0" />
    </dependentAssembly>
    <dependentAssembly>
      <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
      <bindingRedirect oldVersion="0.0.0.0-2.0.2.0" newVersion="2.0.0.0" />
    </dependentAssembly>
    
  27. Espere cerca de um minuto. Abra a janela de ferramentas do Cloud Explorer no Visual Studio (Exibir>Explorer na Nuvem) e expanda o caminho (Local)/Storage Accounts/(Development)/Tables. Clique duas vezes em WADPerformanceCountersTable. Você deve ver os contadores do SignalR nos dados da tabela. Se você não vir a tabela, talvez seja necessário inserir novamente suas credenciais de Armazenamento do Azure. Talvez seja necessário selecionar o botão Atualizar para ver a tabela no Cloud Explorer ou selecionar o botão Atualizar na janela de tabela aberta para ver os dados na tabela.

    Selecionando a tabela contadores de desempenho WAD no Visual Studio Cloud Explorer

    Mostrando os contadores coletados na Tabela de Contadores de Desempenho wad

  28. Para testar seu aplicativo na nuvem, atualize o arquivo ServiceConfiguration.Cloud.cscfg e defina como Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString uma cadeia de conexão válida da conta de Armazenamento do Azure.

    <?xml version="1.0" encoding="utf-8"?>
    <ServiceConfiguration serviceName="SignalRPerfCounters" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="4" osVersion="*" schemaVersion="2015-04.2.6">
      <Role name="WebRole1">
        <Instances count="1" />
        <ConfigurationSettings>
          <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="DefaultEndpointsProtocol=https;AccountName=&lt;account-name&gt;;AccountKey=&lt;account-key&gt;" />
        </ConfigurationSettings>
      </Role>
    </ServiceConfiguration>
    
  29. Implante o aplicativo em sua assinatura do Azure. Para obter detalhes sobre como implantar um aplicativo no Azure, confira Como criar e implantar um serviço de nuvem.

  30. Aguarde alguns minutos. No Cloud Explorer, localize a conta de armazenamento configurada acima e localize a WADPerformanceCountersTable tabela nela. Você deve ver os contadores do SignalR nos dados da tabela. Se você não vir a tabela, talvez seja necessário inserir novamente suas credenciais de Armazenamento do Azure. Talvez seja necessário selecionar o botão Atualizar para ver a tabela no Cloud Explorer ou selecionar o botão Atualizar na janela de tabela aberta para ver os dados na tabela.

Agradecimentos especiais a Martin Richard pelo conteúdo original usado neste tutorial.