Personalized push notification with SignalR and SqlDependency - asp.net

We are working adding real time push notification to Asp.net web application.
I'm able to broadcast one message to all the users who is logged in to website.
but I'm not able to send notification to only one particular user based on the value inserted in the database table.
when i try to do this it's updating all the clients whoever is logged currently.
My code sample below:
SqlDependency Component:
Public Sub RegisterNotification(ByVal currentTime As DateTime)
Try
Dim conStr = ConfigurationManager.ConnectionStrings("constr").ConnectionString
Dim sqlCommand = "SELECT [seq_id],[user_id],[create_timestamp],[alert_read] FROM [dbo].[tblAlerts] WHERE [alert_read]=0 AND [create_timestamp] > #AddedOn"
Using con As New SqlConnection(conStr)
Dim cmd As New SqlCommand(sqlCommand, con)
cmd.Parameters.AddWithValue("#AddedOn", currentTime)
If con.State <> Data.ConnectionState.Open Then
con.Open()
End If
cmd.Notification = Nothing
Dim dependency As New SqlDependency(cmd)
AddHandler dependency.OnChange, AddressOf sqlDep_OnChange
Using reader As SqlDataReader = cmd.ExecuteReader()
Do nothing here
End Using
End Using
Catch ex As Exception
Throw ex
End Try
End Sub
Sub sqlDep_OnChange(ByVal sender As Object, ByVal e As SqlNotificationEventArgs)
Try
If e.Info = SqlNotificationInfo.Insert Then
Dim notificationHub = GlobalHost.ConnectionManager.GetHubContext(Of NotificationHub)
Dim userid = Membership.GetUser.ProviderUserKey
notificationHub.Clients.All.notify(userid)
End If
Dim depend = DirectCast(sender, SqlDependency)
RemoveHandler depend.OnChange, AddressOf sqlDep_OnChange
RegisterNotification(DateTime.UtcNow)
Catch ex As Exception
End Try
End Sub
Notification Hub Code
Public Class NotificationHub
Inherits Hub
Public Sub showdata(ByVal obj As Object)
Try
Dim userobj = obj
Dim notificationHub = GlobalHost.ConnectionManager.GetHubContext(Of NotificationHub)
Dim count = 0
take count from database for userid in the object
notificationHub.Clients.All.setcount(count)
Catch ex As Exception
End Try
End Sub
End Class
SignalR Js code
$(function () {
// signalr js code for start hub and send receive notification
var notificationHub = $.connection.notificationHub;
notificationHub.client.setCount = function (data) {
$('span.count').html(data);
}
$.connection.hub.start().done(function () {
console.log('Notification hub started');
});
//signalr method for push server message to client
notificationHub.client.notify = function (message) {
if (message) {
notificationHub.server.showdata(message);
}
}
})
I have also noticed one more thing here is , sqlDep_OnChange event is called more than once if i have opened applicaiton in more than one browser.

I have managed to do the same with following link:
https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/mapping-users-to-connections
Using SignalR v2 you can use the connectionID to find the corresponding user.

Related

Send mail on session_start

I want to invoke method (to sending a mail) in session_start.
This is my task function:
Public Shared Async Function SendEmailMessage(ByVal MailFrom As String, ByVal MailTo As String, ByVal Subject As String, ByVal HtmlMessage As String) As Task
Dim mail As MailMessage = New MailMessage
mail.From = New MailAddress(MailFrom)
mail.To.Add(MailTo)
mail.Subject = Subject
mail.Body = HtmlMessage
Dim smtp As SmtpClient = New SmtpClient("smtpclient")
smtp.Port = 587
smtp.DeliveryMethod = SmtpDeliveryMethod.Network
smtp.UseDefaultCredentials = True
Await Task.Run(Function() smtp.SendMailAsync(mail))
'Await result
End Function
In global.asax i have this code:
Public Overrides Sub Init()
MyBase.Init()
Dim wrapper = New EventHandlerTaskAsyncHelper(AsyncSessionStart)
Me.AddOnAcquireRequestStateAsync(wrapper.BeginEventHandler, wrapper.EndEventHandler)
End Sub
Private Async Function AsyncSessionStart() As Task
If Not Session.IsNewSession Then Return
Await funzioni.SendEmailMessage("***#***.**", "*****#***", "Object text",
String.Format("E' stato effettuato un tentativo di accesso da {0} del {1} alla WebApp.",
Session("name"), Session("office")))
End Function
this is the reference text that I have read and followed asp-net-async-global-asax
visual studio, however, gives me the following error in this part of the code:
Dim wrapper = New EventHandlerTaskAsyncHelper(AsyncSessionStart)
Value of type Task cannot be converted to TaskEventHandler.
where am i wrong?
Without having tested, I believe that this:
Private Async Function AsyncSessionStart() As Task
should be this:
Private Async Sub AsyncSessionStart(sender As Object, e As EventArgs)
The method you specify to the EventHandlerTaskAsyncHelper constructor should be an asynchronous event handler, which means using the standard event handler parameters (which the link you posted does but you ignored) and declaring it an Async Sub.
You also have to use the AddressOf operator to create a delegate in VB. You may also have to specify the delegate type explicitly:
Dim wrapper = New EventHandlerTaskAsyncHelper(AddressOf AsyncSessionStart)
or:
Dim wrapper = New EventHandlerTaskAsyncHelper(New TaskEventHandler(AddressOf AsyncSessionStart))

SqlDependency OnChange event not firing for SignalR

I know there are multiple questions on SO with a near identical subject, but unfortunately, after following countless guides and reading several answers, I'm at a loss to answer why this is occurring as a new user to SignalR / SqlDependencies.
I have an ASP.Net WebForms app that uses SignalR to push a realtime figure to the page. The code executes on initial load, and fires the event, but after that, I cannot get the event to fire when the dependency detects a change using the OnChange event.
I can see the Queue and SPs are created on the server just fine, but I can't ever see the queue receives any notifications when data is either added/removed or updated in the table. I think it may be something to do with the OnChange resubscription, but I'm not entirely sure.
What could be causing the event to not fire after initial load or the notification not be received from SQL?
I've posted all code below:
Hub Code
Namespace SignalR.Models
<HubName("notificationHub")>
Public Class NotificationHub
Inherits Hub
Private notifCount As Integer
<HubMethodName("sendNotifications")>
Public Sub SendNotifications()
Using db As SqlConnection = New SqlConnection(System.Web.Configuration.WebConfigurationManager.ConnectionStrings("aspCreate_fetch2").ConnectionString)
Dim query As String = " SELECT IIF(COUNT(l.[id]) > 99, 99, COUNT(l.[id]))
FROM pla.[lv_test] as l
WHERE 1=1
AND l.[lv_int_id] = 419"
Using sp As SqlCommand = New SqlCommand(query, db)
Dim dependency As SqlDependency = New SqlDependency(sp)
AddHandler dependency.OnChange, New OnChangeEventHandler(AddressOf dependency_OnChange)
sp.Notification = Nothing
Dim dt As DataTable = New DataTable()
db.Open()
If db.State = ConnectionState.Closed Then db.Open()
Dim reader = sp.ExecuteReader()
dt.Load(reader)
If dt.Rows.Count > 0 Then
notifCount = Int32.Parse(dt.Rows(0)(0).ToString())
End If
Dim context = GlobalHost.ConnectionManager.GetHubContext(Of NotificationHub)()
context.Clients.All.ReceiveNotification(notifCount)
End Using
End Using
End Sub
Private Sub dependency_OnChange(sender As Object, e As SqlNotificationEventArgs)
If e.Type = SqlNotificationType.Change Then
SendNotifications()
End If
End Sub
End Class
End Namespace
Global ASAX
Sub Application_Start(sender As Object, e As EventArgs)
Dim sConn = System.Web.Configuration.WebConfigurationManager.ConnectionStrings("redacted1").ConnectionString
' Fires when the application is started
RouteConfig.RegisterRoutes(RouteTable.Routes)
BundleConfig.RegisterBundles(BundleTable.Bundles)
SqlDependency.[Stop](sConn)
SqlDependency.Start(sConn)
End Sub
Private Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)
Dim sConn = System.Web.Configuration.WebConfigurationManager.ConnectionStrings("redacted1").ConnectionString
SqlDependency.[Stop](sConn)
End Sub
JavaScript
$(function () {
var nf = $.connection.notificationHub;
nf.client.receiveNotification = function (notifCount) {
console.log("connection started");
$("#notif-badge").text(notifCount);
}
$.connection.hub.start().done(function () {
nf.server.sendNotifications();
}).fail(function (e) {
alert(e);
});
});
I am no VB or Javascript expert but I believe that your subscription to OnChange is removed immediately after exiting SendNotifications().
In your code, you have the following dependencies:
SqlDependency -> SqlCommand -> SqlConnection
and you're getting attached to SqlDependency object. However, because your SqlConnection is disposed at the end of the method, your subscription is just gone.
Declare your SqlConnection as a private property and keep the connection open. Besides, move the event subscription to a separate initialization method or the constructor to do it only once.
EDIT :
Here is more or less what I have in mind (in C# , sorry ^^ ):
public class DemoSqlSubscriber : Hub
{
readonly string connectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings("aspCreate_fetch2").ConnectionString;
private SqlDependency dependency;
public void StartListening()
{
SqlDependency.Start(connectionString);
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
SqlCommand command=new SqlCommand();
command.CommandText= "SELECT [notification_count] FROM pla.[notif_count]";
command.Connection = connection;
command.CommandType = CommandType.Text;
dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(OnCountChanged);
}
private void OnCountChanged(object s,SqlNotificationEventArgs e)
{
if(e.Type == SqlNotificationType.Change)
{
// Publish
IHubContext<NotificationHub> context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
context.Clients.All.ReceiveNotification(notifCount);
}
}
public void StopListening()
{
SqlDependency.Stop(connectionString);
}
}
Could you try to structure your Hub accordingly in VB. NET and let us know ?
The query for notifications has many restrictions as detailed here. One of the limitations is:
The statement must not use any of the following aggregate functions:
AVG, COUNT(*), MAX, MIN, STDEV, STDEVP, VAR, or VARP.
If the query is invalid for notification subscriptions, the OnChange handler will fire immediately with SqlNotificationType.Invalid.
Below are the SqlNotificationEventArgs property values I get when running a query similar to yours (i.e. with a COUNT aggregate function) when OnChange is invoked:
Info=Invalid, Source=Statement, Type=Subscribe
However, your handler code silently ignores the invalid subscription since it checks for only SqlNotificationType.Change.

Crystal report database connections not disposing

I am using Visual Studio 2013 in my asp.net web application and using Crystal Reports heavily. My database is SQL Server (using AWS RDS). Everything is working perfectly. The only issue is, from the database side, the Crystal Report connections are not closing/disposing even after closing the browser window. It continuously increasing the number of connections.
This is my code:
ReportDocument cryRpt = new ReportDocument();
ParameterFields paramFields = new ParameterFields();
ParameterField paramField = new ParameterField();
cryRpt.Load(Server.MapPath("~/Reports/Report001.rpt"));
String host = System.Configuration.ConfigurationManager.AppSettings["SqlServer"];
String database = System.Configuration.ConfigurationManager.AppSettings["SqlDatabase"];
String user = System.Configuration.ConfigurationManager.AppSettings["SqlUsername"];
String password = System.Configuration.ConfigurationManager.AppSettings["SqlPassword"];
var connectionInfo = new ConnectionInfo
{
Type = ConnectionInfoType.SQL,
ServerName = host,
DatabaseName = database
};
connectionInfo.IntegratedSecurity = false;
connectionInfo.UserID = user;
connectionInfo.Password = password;
TableLogOnInfo newLogonInfo = null;
foreach (CrystalDecisions.CrystalReports.Engine.Table currentTable in cryRpt.Database.Tables)
{
newLogonInfo = currentTable.LogOnInfo;
newLogonInfo.ConnectionInfo = connectionInfo;
currentTable.ApplyLogOnInfo(newLogonInfo);
}
ParameterField pReportName = new ParameterField();
pReportName.ParameterFieldName = "REPONAME";
ParameterDiscreteValue dcpReportName = new ParameterDiscreteValue();
dcpReportName.Value = "REPORT";
pReportName.CurrentValues.Add(dcpReportName);
paramFields.Add(pReportName);
CrystalReportViewer1.ParameterFieldInfo = paramFields;
CrystalReportViewer1.Zoom(100);
CrystalReportViewer1.PrintMode = CrystalDecisions.Web.PrintMode.ActiveX;
CrystalReportViewer1.ReportSource = cryRpt;
CrystalReportViewer1.ReuseParameterValuesOnRefresh = true;
CrystalReportViewer1.ShowFirstPage();
// Disposing the report
foreach (CrystalDecisions.CrystalReports.Engine.Table currentTable in cryRpt.Database.Tables)
{
currentTable.Dispose();
}
CrystalReportViewer1.ReportSource = null;
cryRpt.Database.Dispose();
cryRpt.Close();
cryRpt.Dispose();
cryRpt = (ReportDocument)CrystalReportViewer1.ReportSource;
CrystalReportViewer1.Dispose();
connectionInfo.Attributes.Collection.Clear();
GC.Collect();
Tried to use the unload method also like this. but no luck.
protected void CrystalReportViewer1_Unload(object sender, EventArgs e)
{
cryRpt.Close();
cryRpt.Dispose();
CrystalReportViewer1.Dispose();
}
As a temporary solution, I'm manually killing the sleeping database connection from the database using a stored procedure.
I'm using ODBC connection to get the data. ODBC credentials are stored in the config file and retrieved as follows.
String host = System.Configuration.ConfigurationManager.AppSettings["SqlServer"];
String database = System.Configuration.ConfigurationManager.AppSettings["SqlDatabase"];
String user = System.Configuration.ConfigurationManager.AppSettings["SqlUsername"];
String password = System.Configuration.ConfigurationManager.AppSettings["SqlPassword"];
Kindly help me to come out of this issue.
In your above code, how do you exactly use the ODBC connection that is stored in a config file ? for example [Is it a DataSet?], because, if so! then you close the Database connection anyway before loading the report as in before this line, here :
cryRpt.Load(Server.MapPath("~/Reports/Report001.rpt"));
I think your problem lies within the Database connection itself with the application, not with Crystal Reports Components.
Try to, close the connection Connection.Close before disposing the viewer CrystalReportViewer1.Dispose();, but caution :
Do not call Close or Dispose on a Connection, a DataReader, or any
other managed object in the Finalize method of your class. In a
finalizer, you should only release unmanaged resources that your class
owns directly. If your class does not own any unmanaged resources, do
not include a Finalize method in your class definition. For more
information, see Garbage Collection.
source
Also, your situation is natural, because the client keeps the connection open, read this too
Here is a sample of Code that I use (without ODBC and with MS-Access) :
Imports CrystalDecisions.CrystalReports.Engine
Imports System.Data.OleDb
Imports CrystalDecisions.Shared
Public Class CrystalForm
Dim cryRpt As New ReportDocument
Dim crtableLogoninfos As New TableLogOnInfos
Dim crtableLogoninfo As New TableLogOnInfo
Dim crConnectionInfo As New ConnectionInfo
Dim CrTables As Tables
Dim CrTable As Table
Private Sub CrystalForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim CMDSelect As String = ("SELECT * FROM Table_Name")
Try
Using DT As New DataTable
Using CN As New OleDbConnection With {.ConnectionString = GetBuilderCNString()}
CN.Open()
Using DataAdapt As New OleDbDataAdapter(CMDSelect, CN)
DataAdapt.Fill(DT)
End Using
End Using
cryRpt.Load(IO.Path.Combine(Application.StartupPath, "Crystal_Report.rpt"))
AssignConnection(cryRpt)
cryRpt.SetDataSource(DT)
CrystalReportViewer1.ReportSource = cryRpt
End Using
Catch ex As EngineException
MsgBox("Report Load Error : " & ex.Message)
End Try
End Sub
Private Sub AssignConnection(rpt As ReportDocument)
Try
Dim ThisConnection As New ConnectionInfo()
With ThisConnection
.DatabaseName = ""
.ServerName = ""
.UserID = "admin"
.Password = "MyPassWord"
End With
For Each table As Table In rpt.Database.Tables
AssignTableConnection(table, ThisConnection)
Next
For Each section As Section In rpt.ReportDefinition.Sections
For Each reportObject As ReportObject In section.ReportObjects
If reportObject.Kind = ReportObjectKind.SubreportObject Then
Dim subReport As SubreportObject = DirectCast(reportObject, SubreportObject)
Dim subDocument As ReportDocument = subReport.OpenSubreport(subReport.SubreportName)
For Each table As Table In subDocument.Database.Tables
AssignTableConnection(table, ThisConnection)
Next
subDocument.SetDatabaseLogon(ThisConnection.UserID,
ThisConnection.Password,
ThisConnection.ServerName,
ThisConnection.DatabaseName)
End If
Next
Next
rpt.SetDatabaseLogon(ThisConnection.UserID,
ThisConnection.Password,
ThisConnection.ServerName,
ThisConnection.DatabaseName)
Catch ex As EngineException
MsgBox("Load Report Error : " & ex.Message)
End Try
End Sub
Private Sub AssignTableConnection(ByVal table As Table, ByVal connection As ConnectionInfo)
Try
Dim logOnInfo As TableLogOnInfo = table.LogOnInfo
connection.Type = logOnInfo.ConnectionInfo.Type
logOnInfo.ConnectionInfo = connection
With table.LogOnInfo.ConnectionInfo
.DatabaseName = connection.DatabaseName
.ServerName = connection.ServerName
.UserID = connection.UserID
.Password = connection.Password
.Type = connection.Type
End With
table.ApplyLogOnInfo(logOnInfo)
Catch ex As EngineException
MsgBox("Load Table Error : " & ex.Message)
End Try
End Sub
End Class

SQL Server connection remains open, even after closing

I have a website that is designed to multi-tiered. My code works, but I have noticed that the larger my app becomes, the more SQL database connections start to stack up and remain open. This eventually causes this error:
System.InvalidOperationException: 'Timeout expired. The timeout
period elapsed prior to obtaining a connection from the pool. This
may have occurred because all pooled connections were in use and max
pool size was reached.'
My code is split into 3 layers. They are:
Application layer. Every time it wants to CRUD, is calls the Business Layer.
Business Layer - does business logic. When it wants to interface with the MS SQL db, it connects via ConnectionAdapter layer.
The ConnectionAdapter inherits from a SqlConnectionAdapter class and does the actual db interactions.
The following is pseudo code for each:
Application
My application may call the business layer multiple times. Particularly when doing AJAX requests. An example would be like:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
Dim dp As New DataProxy
Dim listOfObs As New List(Of MyObject)
dim someId as integer = 1
Try
If Not Page.IsPostBack Then
listOfObs = dp.ExampleReadFuncion(someId)
End If
Catch ex As Exception
Throw
Finally
dp.dispose()
dp = Nothing
SetMenue()
End Try
End Sub
DatatProxy (business layer)
Public Class DataProxy
Dim scConAdapter As New ConnectionAdapter
Public Sub New()
Try
scConAdapter.Connect()
Catch ex As Exception
Throw
End Try
End Sub
Public Sub dispose()
scConAdapter.Dispose()
End Sub
Private Shared Sub Main()
End Sub
Public Function ExampleReadFuncion(ByVal someId As Integer) As List(Of MyObject)
Dim successFactor As LogStatusEnum = LogStatusEnum.INFO
Dim newEx As Exception = Nothing
Dim conn As New ConnectionAdapter
Dim myObj As ActivityMarker
Dim listOfObs As New List(Of MyObject)
Dim dr As SqlDataReader = Nothing
Try
successFactor = LogStatusEnum.INFO
conn.Connect()
dr = conn.ExampleReadFuncion(someId)
Using dr
If (dr.HasRows = True) Then
While dr.Read
myObj = New myObj
myObj.Marker_Id = dr.Item("id")
myObj.Acitvity_Id = dr.Item("someValue")
listOfObs.Add(myObj)
End While
End If
End Using
Return listOfObs
Catch ex As Exception
successFactor = LogStatusEnum.ERRORS
Throw
Finally
dr.Close()
dr = Nothing
conn.Dispose()
conn = Nothing
End Try
End Function
End class
ConnectionAdapter
Public Class ConnectionAdapter
Inherits SqlConnectionAdapter
Public Sub New()
End Sub
Public Function ExampleReadFuncion(ByVal someId As Integer) As SqlDataReader
Try
Dim dr As SqlDataReader = Nothing
Dim selectString As New StringBuilder
Dim cmd As SqlCommand = Nothing
Try
cmd = CreateCommand()
selectString.Append("SELECT * " & vbCrLf)
selectString.Append("FROM " & vbCrLf)
selectString.Append("dbo.mytable " & vbCrLf)
selectString.Append("WHERE " & vbCrLf)
selectString.Append("id = #SOME_ID " & vbCrLf)
With cmd
.CommandType = CommandType.Text
.CommandText = selectString.ToString
.Parameters.Add("#SOME_ID", SqlDbType.Int).Value = someId
dr = .ExecuteReader
End With
Catch ex As Exception
Throw
Finally
cmd.Dispose()
End Try
Return dr
Catch ex As Exception
Throw ex
End Try
End Function
end class
SqlConnectionAdapter
Public MustInherit Class SqlConnectionAdapter
Protected CurrentTransaction As SqlTransaction
Public Property db As SqlConnection
Public Property Password As String
Public Property TNSName As String
Public Property User As String
Public Property DBName As String
Public Property PortNumber As Integer
Public Overridable Sub Dispose()
Try
If Not CurrentTransaction Is Nothing Then
CurrentTransaction.Commit()
End If
Catch ex As Exception
Throw
Finally
If Not db Is Nothing Then
db.Close()
db.Dispose()
db = Nothing
End If
End Try
End Sub
Public Overridable Sub Connect()
Try
Dim appSettings = ConfigurationManager.AppSettings
If (appSettings("releaseVersion") = "DEBUG") Then
Connect(appSettings("db_sqlHost"), appSettings("db_sqlDb"))
Else
Connect(appSettings("db_sqlHost"), appSettings("db_sqlPort"), appSettings("db_sqlDb"), appSettings("db_sqlUser"), appSettings("db_sqlPassword"))
End If
Catch ex As Exception
Throw
End Try
End Sub
Public Sub Connect(ByVal GetServername As String, ByVal GetDatabaseName As String)
Try
TNSName = GetServername
DBName = GetDatabaseName
db = New SqlConnection
db = SqlConnectionUtilities.GetConnection(GetServername, GetDatabaseName)
Catch ex As Exception
Throw
End Try
End Sub
Public Sub Connect(ByVal GetServerName As String, ByVal GetPort As Long, ByVal GetDatabase As String, ByVal GetUsername As String, ByVal Getpassword As String)
Try
User = GetUsername
Password = Getpassword
PortNumber = GetPort
DBName = GetDatabase
TNSName = GetServerName
db = New SqlConnection
db = SqlConnectionUtilities.GetConnection(GetServerName, GetPort, GetDatabase, GetUsername, Getpassword)
Catch ex As Exception
Throw
End Try
End Sub
Protected Function CreateCommand() As SqlCommand
Dim ret As SqlCommand = Nothing
Try
ret = db.CreateCommand
If Not CurrentTransaction Is Nothing Then
ret.Transaction = CurrentTransaction
End If
Catch ex As Exception
Throw
Finally
End Try
Return ret
End Function
Public Sub BeginTransaction()
If CurrentTransaction Is Nothing Then
CurrentTransaction = db.BeginTransaction
End If
End Sub
Public Sub CommitTransaction()
If Not CurrentTransaction Is Nothing Then
CurrentTransaction.Commit()
CurrentTransaction.Dispose()
CurrentTransaction = Nothing
End If
End Sub
Public Sub RollbackTransaction()
If Not CurrentTransaction Is Nothing Then
CurrentTransaction.Rollback()
CurrentTransaction.Dispose()
CurrentTransaction = Nothing
End If
End Sub
Protected Overrides Sub Finalize()
MyBase.Finalize()
End Sub
End Class
Utilities class
Public Class SqlConnectionUtilities
Public Shared Property connectionString As String
Public Shared Function GetConnection(ByVal ServerName As String, ByVal Port As String, ByVal Database As String, ByVal username As String, ByVal password As String) As SqlConnection
Dim connString As New StringBuilder
Dim con As SqlConnection
Try
connString.Append("Server=tcp:" & ServerName & "," & Port & ";")
connString.Append("Initial Catalog = " & Database & "; Persist Security Info=False;")
connString.Append("User ID = " & username & ";")
connString.Append("Password = " & password & ";")
connString.Append("MultipleActiveResultSets = False;")
connString.Append("Encrypt = True;TrustServerCertificate=False;Connection Timeout=30;")
connectionString = connString.ToString
con = New SqlConnection(connString.ToString)
con.Open()
Return con
Catch ex As Exception
Throw
End Try
End Function
Public Shared Function GetConnection(ByVal Servername As String, ByVal DatabaseName As String) As SqlConnection
Dim ConnectString As String
Dim con As SqlConnection
Try
ConnectString = "Data Source=" & Servername & ";Initial Catalog=" & DatabaseName & ";Integrated Security=True"
connectionString = ConnectString
con = New SqlConnection(ConnectString)
con.Open()
Return con
Catch ex As Exception
Throw
End Try
End Function
End class
I can tell that connections are remaining open by running this SQL statement:
SELECT
DB_NAME(dbid) as DBName,
COUNT(dbid) as NumberOfConnections,
loginame as LoginName
FROM
sys.sysprocesses
WHERE
dbid > 0
GROUP BY
dbid, loginame
I set up break points when my DataProxy class is called. I run the SQL code and can see a new connection is opened. Then, I run the code again when I dispose of the DataProxy class and I can see the connection remains. This will build up until it hits 101 connections, then it causes the above error. How am I not handling the connections correctly?
System.InvalidOperationException: 'Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.'
How am I not handling the connections correctly?
You are "leaking" connections. IE you have some code path that opens a SqlConnection, and doesn't Close/Dispose it. The SqlConnection remains open and is sitting on the managed heap. Eventually it will be GC'd and its Finalizer will close the connection. But if you leak 100 connections before that happens, you get this error.
So you need to ensure that your SqlConnections are always closed using a USING block, or are managed by some other object that's closed with a USING block.
Note that if you are returning a SqlDataReader from a function, there's a special CommandBehavior that will close the SqlConnection when the SqlDataReader is closed.
No, even this code not work and it wait a few minutes to remove sql connection from sql server.
using (var conn = new SqlConnection(connStr))
{
conn.Open();
conn.Close();
}
GC.Collect();
GC.WaitForPendingFinalizers();

Catching errors or exceptions

I built a mashup of google maps and weather.com and everytime one of these server is not responding my application hangs up too.What do you think I can do to prevent or minimize hanging up of my web apps?Hanging up like you can't navigate away from that page....
I got this code on my app code to access the weather service;
Public Class WeatherIn
Private _path As String
Private _cachedFile As String
Public Sub New(ByVal path As String)
_path = path
_cachedFile = String.Format("{0}\WeatherInCache.xml", _path)
End Sub
Public Function GetWeather(ByVal arg As String) As String
Return _getWebWeather(arg)
End Function
Private Function _getCachedWeather() As String
Dim str As String = String.Empty
Using reader As New StreamReader(_cachedFile)
str = reader.ReadToEnd()
End Using
Return str
End Function
Private Function _getWebWeather(ByVal arg As String) As String
Dim baseUrl As String = "http://xoap.weather.com/weather/local/{0}?cc=*&dayf=5&link=xoap&prod=xoap&par={1}&key={2}"
Dim jane As String = arg
Dim james As String = "api key"
Dim john As String = "another api key"
Dim url As String = String.Format(baseUrl, jane, james, john)
Using client As New WebClient()
Try
Dim xml As New XmlTextReader(client.OpenRead(url))
Dim xslt As New XslCompiledTransform()
xslt.Load(_path + "/Pathto.xslt")
Using writer As New StreamWriter(_cachedFile)
xslt.Transform(xml, Nothing, writer)
End Using
Return _getCachedWeather()
Catch exception As WebException
Dim xmlStr As String = "<errorDoc>"
xmlStr += "<alert>An Error Occurred!</alert>"
xmlStr += [String].Format("<message>{0}</message>", exception.Message)
xmlStr += "</errorDoc>"
Dim doc As New XmlDocument()
doc.LoadXml(xmlStr)
Dim reader As New XmlNodeReader(doc)
Dim xslt As New XslCompiledTransform()
xslt.Load(_path + "/Pathto.xslt")
Dim resultDocument As New XmlDocument()
Using writer As XmlWriter = resultDocument.CreateNavigator().AppendChild()
xslt.Transform(reader, DirectCast(Nothing, XsltArgumentList), writer)
End Using
Return resultDocument.OuterXml
End Try
End Using
End Function
Then I used the class above on my page where I display the weather like this:
'specific zip code or could be retrieved from querystring for dynamic retrieval
var jay="94576"
Dim weather As New WeatherIn(Server.MapPath(String.Empty))
Dim weatherData As String = weather.GetWeather(jay)
Response.ContentType = "text/xml"
Response.CacheControl = "no-cache"
Response.Write(weatherData)
which I retrieve the data and write on the page through javascript.Most of the time its the weather.com that goes down.I got no problem with google map its reliable....anybody got a solution why my page hangs up too if the remote server is not responding?The mashup is running smoothly if the remote server is responding...
When depending on external web services it is best to load asynchronously so that if one of them is slow you can show some kind of loading spinner to the page viewer. If it fails your page could simply report that reading from the web server failed and to try again later.
In this case I would load up the page with the Google map in place and then make an AJAX request for the Weather data.

Resources