ASP .NET - Criando uma conexão Assíncrona com o SQL Server
Neste artigo vou explicar como criar uma conexão assíncrona com o SQL Server em uma aplicação ASP .NET Web Forms. |
Revisão de Conceitos - Teoria
Como você faria se precisasse executar uma consulta ou comando contra um banco de dados SQL Server, de forma assíncrona, ou seja, em segundo plano, enquanto sua aplicação continuasse a realizar outros processamentos ?
Para este serviço você pode usar os métodos BeginExecuteNonQuery, BeginExecuteReader, ou BeginExecuteXmlReader da classe SqlCommand do namespace System.Data.SqlClient para iniciar a operação com o banco de dados como uma tarefa em segundo plano.
Estes métodos retornam um objeto System.IAsyncResult que você pode usar para determinar o estado da operação ou usar uma sincronização via thread para aguardar que a tarefa seja completada.
Para obter o resultado da operação podemos usar o objeto IAsyncResult e os métodos EndExecuteNonQuery, EndExecuteReader, ou EndExecuteXmlReader correspondentes.
Obs: Somente a classe SqlCommand suporte as operações assíncronas que iremos descrever neste artigo. O mesmo não se aplica aos provedores de dados Oracle, SQL Server CE, ODBC, e OLE DB.
Você normalmente irá executar operações em bancos de dados de forma síncrona, pois o seu código vai precisar do resultado da operação antes de continuar. No entanto, às vezes é útil executar uma operação de banco de dados de forma assíncrona, o que significa que você iniciar o método em um segmento separado e depois continuar com outras operações.
Para executar operações assíncronas através de uma conexão System.Data.SqlClient.SqlConnection, você deve especificar o valor de Asynchronous Processing como sendo igual a true na string de conexão.
A classe SqlCommand implementa o padrão de execução assíncrono onde os argumentos dos métodos de execução assíncronos (BeginExecuteNonQuery, BeginExecuteReader e BeginExecuteXmlReader) são os mesmos que os usados no modo síncrono.
A diferença básica é que eles usam dois argumentos adicionais para suporta a operação assíncrona. Os quais são:
Os métodos EndExecuteNonQuery, EndExecuteReader e EndExecuteXmlReader permitem a você recuperar o valor de retorno de uma operação que foi executada de forma assíncrona, mas primeiro você deve determinar quando ela terminou.
Temos quatro técnicas para determinar se um método assíncrono terminou:
Blocking : Este método pára a execução da thread atual até que a operação assíncrona concluir sua execução. Este é o mesmo que o usado na execução síncrona. No entanto, neste caso, você tem a flexibilidade para decidir exatamente quando seu código entra no estado bloqueado, dando-lhe a oportunidade de realizar algum processamento adicional antes de bloquear;
Polling: Este método envolve testar repetidamente o estado de uma operação assíncrona para determinar se ela está completa. Esta é uma técnica muito simples e não é particularmente eficiente do ponto de vista de processamento. Você deve evitar vincular loops que consomem tempo do processador. É melhor colocar a thread pooling para dormir por um período entre os testes usando Thread.Sleep.
Waiting : Este método usa um objeto derivado da classe System.Threading.WaitHandle para sinalizar quando o método assíncrono for concluído. Waiting é uma versão mais eficiente de pesquisa e, além disso permite a você esperar por múltiplas operações assíncronas serem concluídas. Você também pode especificar valores de tempo limite para permitir que a sua thread waiting falhe se operação assíncrona demorar muito tempo ou se você deseja periodicamente atualizar o estado do indicador;
CallBack : Esse é um método que o runtime chama quando uma operação assíncrona é concluída. O código Calling não precisa tomar todas as medidas para determinar quando a operação assíncrona está completa e é livre para continuar com outros processamento. Usar Callbacks proporciona a maior flexibilidade, mas também introduz uma maior complexidade, especialmente se você tiver muitos operações assíncronas que usam o mesmo callback. Nesses casos, você deve usar objetos de estado apropriado para combinar com métodos completados contra aqueles que iniciado.
Ufa ! Agora vamos à prática.
Recursos usados:
ASP .NET 4.5
SQL Server 2012 Express Edition
Banco de dados Northwind.mdf
Criando uma conexão assíncrona no SQL Server
Para atingir o nosso objetivo vamos realizar as seguintes tarefas:
1- Definindo o banco de dados SQL Server
Neste exemplo eu vou acessar a tabela Customers do banco de dados Northwind.mdf do SQL Server. A estrutura da tabela é vista abaixo:
A string de conexão definida no meu ambiente para este banco de dados é vista abaixo:
"Data Source=.\sqlexpress;Initial Catalog=Northwind;Integrated Security=True"
Atenção ! Para o seu ambiente esse valor pode ser diferente.
2- Criando o projeto ASP .NET e definir a página assíncrona
Abra o VS Community 2013 clique em New Project;
Selecione Visual Basic (ou Visual C#) -> web e o template ASP .NET Web Application e informe o nome ASPNET_ConexaoAssincrona e clique no botão OK;
A seguir selecione o template Empty e marque a opção Web Forms e clique no botão OK;
No menu PROJECT clique em Add New Item e a seguir selecione o template Web Form e informe o nome Default.aspx;
Abra a página Default.aspx no modo Source e inclua o atributo Async="true" na diretiva Page da página. Ao fazer isso estamos dizendo à ASP .NET para implementar IHttpAsyncHandler na página.
Vamos definir também ou timeout para a página concluir a tarefa assíncrona incluindo o atributo AsyncTimeout="20" na diretiva Page:
<%@ Page Language="vb" Async="true" AsyncTimeout="20" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="ASPNET_ConexaoAssincrona._Default" %>
<!DOCTYPE html>
....
|
Agora abra o arquivo Web.Config do projeto e defina a string de conexão entre as tagas <connectionstrings> com o banco de dados Northwind.mdf conforme abaixo:
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<system.web>
<compilation debug="true" strict="false" explicit="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<connectionStrings>
<add name="ConexaoNorthwind" connectionString="Data Source=.\sqlexpress;Initial Catalog=Northwind;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
|
Ainda no arquivo Web.Config vamos incluir na seção <appSettings> o elemento UseTaskFriendlySynchronizationContext que especifica como o código do path assíncrono se comporta. Se este valor de chave for definido como false [default], os caminhos de código assíncrono em ASP.NET 4.5 se comportam como em ASP.NET 4.0.
....
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="false" />
</appSettings>
....
|
Agora vamos incluir na página Default.aspx um controle GridView (name=gdvDados) , a partir da guia Data da ToolBox, e selecionando o recurso Auto Format..., defina uma formatação conforme mostrado abaixo:
Finalmente inclua um controle Button (name=btnAcessarSQLServer) logo abaixo do controle GridView.
Definindo o código no arquivo code-behind Default.aspx.vb
Vamos começar definindo os namespaces usados na página :
Imports
System.DataA seguir no início da página vamos definir a variável conexão conn do tipo SqlConnection que iremos usar no projeto e a variável _progressoTarefa para armazenar informações da tarefa.
'define a string de conexão obtida a partir do arquivo Web.Config (conexaoNorthwind)
'variável string para armzenar
o texto referente ao progresso da tarefa (inicio, encerramento, falha)
Private
_progressoTarefa As
String
Agora vamos incluir no evento Click do botão de comando, no arquivo
code-behind Default.aspx.vb o código onde fazermos o seguinte:
Definimos a tarefa assíncrona que iremos executar
Registramos a tarefa
Executamos o registro
Exibimos o resultado das mensagens
O código pode ser visto abaixo:
Protected Sub btnAcessarSQLServer_Click(sender As Object, e As EventArgs) Handles btnAcessarSQLServer.Click
'Define uma tarefa assincrona
Dim tarefaAssincrona As New PageAsyncTask(AddressOf BeginAsync, AddressOf EndAsync, AddressOf ExcedeuTempo, Nothing, True)
'registra a tarefa assincrona
Me.RegisterAsyncTask(tarefaAssincrona)
' Executa o registro da tarefa assincrona
Page.ExecuteRegisteredAsyncTasks()
'exibe as mensagens na Label
lblmsg.Text = _progressoTarefa
End Sub
|
Usamos a classe PageAsyncTask que contém informações sobre uma tarefa assíncrona registrada para uma página e definimos os métodos:
BeginAsync - este método inicia a tarefa assíncrona ;
EndAsyng - encerra a tarefa assíncrona;
ExcedeuTempo - se ocorreu um timeout, este método registra a mensagem;
O código para estes métodos pode ser visto abaixo:
'define o método que será chamado para iniciar a tarefa
Private Function BeginAsync(sender As Object, e As EventArgs, cb As AsyncCallback, state As Object) As IAsyncResult
_progressoTarefa = "Tarefa assíncrona iniciada em : " + DateTime.Now.ToString + ". " + vbCrLf + vbCrLf
conn.Open()
Dim cmd As New SqlCommand("Select * from Customers WAITFOR DELAY '00:00:02'", conn)
Dim adp As New SqlDataAdapter(cmd)
Dim ds As New DataSet()
adp.Fill(ds)
dgvDados.DataSource = ds
dgvDados.DataBind()
Dim ar As IAsyncResult = cmd.BeginExecuteNonQuery(cb, cmd)
Return ar
End Function
'define o método que será chamado para encerrar a tarefa
Private Sub EndAsync(ar As IAsyncResult)
'define a mensagem para o encerramento
_progressoTarefa += "Tarefa Assíncrona completada em : " + DateTime.Now.ToString
Using cmd As SqlCommand = DirectCast(ar.AsyncState, SqlCommand)
Using cmd.Connection
Dim rows As Integer = cmd.EndExecuteNonQuery(ar)
End Using
End Using
End Sub
' Define o método que será chamado se a tarefa não for completada dentro do intervalo de tempo
Private Sub ExcedeuTempo(ByVal ar As IAsyncResult)
_progressoTarefa += "Tarefa Assíncrona falhou ao completar porque o parâmetro AsyncTimeout foi excedido."
End Sub
|
No método BenginAsync temos a instrução SQL SELECT utiliza WAITFOR DELAY que bloqueia a execução de um lote, procedimento armazenado ou transação até que uma hora ou intervalo de tempo especificado seja alcançado ou que uma instrução especificada modifique ou retorne pelo menos uma linha. No exemplo DELAY refere-se ao tempo que deve ser esperado e vale 00:00:02.
A seguir usamos a instrução BeginExecuteNonQuery() que inicia a execução assíncrona da instrução ou procedimento armazenado de Transact-SQL que é descrito por esse SqlCommand.
No método EndAsync encerramos a execução assíncrona usando a instrução EndExecuteNonQuery().
Executando o projeto iremos obter o seguinte resultado:
Pegue o projeto completo aqui : ASPNET_ConexaoAssincrona.zip
Disse-lhes Jesus: Em verdade, em verdade vos digo que antes que Abraão
existisse, Eu Sou.
João 8:58
Veja os
Destaques e novidades do SUPER DVD Visual Basic
(sempre atualizado) : clique e confira !
Quer migrar para o VB .NET ?
Quer aprender C# ??
Quer aprender os conceitos da Programação Orientada a objetos ? Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ? |
Gostou ? Compartilhe no Facebook Compartilhe no Twitter
Referências: