RaiseEvent Issue while Converting Code C# to VB.NET - asp.net

I have following C# function,
private void btnSendtoGeoDecision_Click(object sender, RoutedEventArgs e)
{
List<FenceModel> lst = new List<FenceModel>();
int FencesInsert;
foreach (FenceModel item in FenceList.SelectedItems)
{
lst.Add(item);
}
BackgroundWorker worker = new BackgroundWorker();
//this is where the long running process should go
worker.DoWork += (o, ea) =>
{
//no direct interaction with the UI is allowed from this method
bool result = objFenceRepository.SendFences(lst, out FencesInsert);
if (result)
{
MessageBox.Show(string.Format("The total of {0} fences have been sent to Geo Decision.", FencesInsert));
}
else
{
MessageBox.Show(string.Format("The error occurs in sending fences to Geo Decision."));
}
};
worker.RunWorkerCompleted += (o, ea) =>
{
//work has completed. you can now interact with the UI
// _busyIndicator.IsBusy = false;
};
//set the IsBusy before you start the thread
// _busyIndicator.IsBusy = true;
worker.RunWorkerAsync();
}
And I Convert it into VB.NET Using Language Converter and It gave me below code
Private Sub btnSendtoGeoDecision_Click(sender As Object, e As RoutedEventArgs)
Dim lst As New List(Of FenceModel)()
Dim FencesInsert As Integer
For Each item As FenceModel In FenceList.SelectedItems
lst.Add(item)
Next
Dim worker As New BackgroundWorker()
'this is where the long running process should go
worker.DoWork += Function(o, ea)
'no direct interaction with the UI is allowed from this method
Dim result As Boolean = objFenceRepository.SendFences(lst, FencesInsert)
If result Then
MessageBox.Show(String.Format("The total of {0} fences have been sent to Geo Decision.", FencesInsert))
Else
MessageBox.Show(String.Format("The error occurs in sending fences to Geo Decision."))
End If
End Function
'work has completed. you can now interact with the UI
' _busyIndicator.IsBusy = false;
worker.RunWorkerCompleted += Function(o, ea)
End Function
'set the IsBusy before you start the thread
' _busyIndicator.IsBusy = true;
worker.RunWorkerAsync()
End Sub
But when I build it, I get following two Errors, I know its asking me to use RaiseEvent since += equivalent to RaiseEvent in VB.Net, But can Anybody Show me how?
'Public Event DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
'Public Event RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs)' is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.

You need:
AddHandler worker.DoWork, Sub(o, ea)
' code here
End Function
AddHandler worker.RunWorkerCompleted, Sub(o, ea)
' code here
End Function
For your anonymous eventhandler to work.

If you need anonymous event handler follow Ric answer.
Otherwise you have to declare worker as a member variable of the class/module that includes your function like:
Private WithEvents worker As BackgroundWorker
And then you can create named function that handle your event like this:
Private Sub DoWorkHandler (sender As Object, args As DoWorkEventArgs) Handles worker.DoWork

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.

Personalized push notification with SignalR and SqlDependency

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.

Trying to get a querystring variable with an ashx

I have been trying to sort this out all day with lots of Googling but with little effect so thanks in advance if you read and are able to help.
I have a simple page which allows a user to select files and upload to an Amazon bucket, the first page looks like this:
var checkError = false;
$(window).load(
function () {
$("#<%=FileImages.ClientID %>").fileUpload({
'fileSizeLimit': '100MB',
'uploader': 'scripts/uploader.swf',
'cancelImg': 'images/cancel.png',
'buttonText': 'Upload Files',
'script': 'UploadVB.ashx?gid=56',
'folder': 'uploads',
'multi': true,
'auto': true,
'onAllComplete': function (uploads) {
if (!checkError) {
location.href = "finished";
}
},
'onComplete': function (event, ID, fileObj, response, data) {
if (200 != parseInt(response)) {
checkError = true;
$('#FileImages' + ID).addClass('uploadifyError');
$('#FileImages' + ID + ' .percentage').text(' - ' + response);
return false;
}
}
});
}
);
Note the gid=56. It then sends the files over to UploadVB.ashx and this looks like this:
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim awsRegion As Amazon.RegionEndpoint = Amazon.RegionEndpoint.EUWest1
Dim client As New AmazonS3Client(System.Configuration.ConfigurationManager.AppSettings("AWSAccessKey").ToString(), System.Configuration.ConfigurationManager.AppSettings("AWSSecretKey").ToString(), awsRegion)
Dim fileID As String = Guid.NewGuid().ToString("N")
Dim postedFile As HttpPostedFile = context.Request.Files("Filedata")
Dim galleryid = context.Request.QueryString("gid")
Try
Dim filename As String = Path.GetFileName(postedFile.FileName)
'### I WANT TO SUBMIT THE FILENAME AND ID INTO A TABLE HERE ######
AddPortfolioPhoto(filename, Convert.ToInt16(galleryid))
'#################################################################
Dim S3_KEY As [String] = filename.Replace(" ", "")
Dim request As New PutObjectRequest()
With request
.BucketName = System.Configuration.ConfigurationManager.AppSettings("AWSBucketName").ToString()
.Key = S3_KEY
.InputStream = postedFile.InputStream
End With
client.PutObject(request)
context.Response.Write("200")
context.Response.StatusCode = 200
Catch ex As Exception
context.Response.Write("AWS ERROR :: " + ex.Message)
End Try
End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
Every time I run this above it just doesn't do anything, If I remove this line:
AddPortfolioPhoto(filename, Convert.ToInt16(galleryid))
it works great but it is crucial I get this inserted into the database someway and I just can't seem to be able to grab the gid value.
Any help is greatly appreciated.
Public Shared Sub AddPortfolioPhoto(ByVal fn As String, gid As Integer)
Dim Writer As New Data.SqlClient.SqlCommand
Writer.CommandType = Data.CommandType.StoredProcedure
Writer.CommandText = "BCMS_AddGalleryPhoto"
Writer.Connection = New Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.AppSettings("sqlstr"))
Writer.Parameters.AddWithValue("#imgstr", Data.SqlTypes.SqlString.Null).Value = fn
Writer.Parameters.AddWithValue("#galleryid", Data.SqlTypes.SqlInt32.Null).Value = gid
Writer.Parameters.AddWithValue("#so", Data.SqlTypes.SqlInt32.Null).Value = 0
Writer.Parameters.AddWithValue("#featured", Data.SqlTypes.SqlInt32.Null).Value = 0
Writer.Prepare()
Writer.Connection.Open()
Writer.ExecuteNonQuery()
Writer.Connection.Close()
End Sub
Looks like with your help I may have gotten to the bottom of this, the value I was expecting (56) wasn't what I was actually getting, I was actually getting "uploads" in the same variable so sending a string down to this method was never going to work, thanks #matt-dot-net for suggesting and thanks Andrew Morton for the tip on dispose, I will use that rather than close.

How Do I Get an Object to Listen For its Property's Event?

I have an object of type SomeObject, with an event StatusChanged.
I have a property in SomeObject of type Status also with an event StatusChanged.
Within a private function in SomeObject, I would like to run some logic (including firing the StatusChanged event) in the event that Status has fired its StatusChanged event. I have been away from events for a while so it's a bit cloudy to me. How do I do this?
I'm writing in ASP.NET/VB.NET
Thanks :)
EDIT Ok, in the event that I can't do the above, how would I get the outer object (SomeObject) to fire its StatusChanged event when the inner object (Status) fires its StatusChanged event?
Events don't work that way. You can't perform logic based on whether an event has been fired. You can only write logic that takes place when an event is fired.
Ok, here's an attempt. It's been a while since I've done this in VB.NET, though:
Public Enum CurrentStatus
Good
Bad
End Enum
Public Class StatusEventArgs
Inherits EventArgs
Private _currentStatus As CurrentStatus
Public Property CurrentStatus() As CurrentStatus
Get
Return _currentStatus
End Get
Set(ByVal value As CurrentStatus)
_currentStatus = value
End Set
End Property
End Class
Public Class StatusClass
Public Event StatusChanged As EventHandler(Of StatusEventArgs)
Protected Overridable Sub OnStatusChanged(ByVal newStatus As CurrentStatus)
Dim s As New StatusEventArgs()
s.CurrentStatus = newStatus
RaiseEvent StatusChanged(Me, s)
End Sub
End Class
Public Class SomeClass
Private _status As StatusClass
Public Event StatusChanged As EventHandler(Of StatusEventArgs)
Protected Overridable Sub OnStatusChanged(ByVal newStatus As CurrentStatus)
Dim s As New StatusEventArgs()
s.CurrentStatus = newStatus
RaiseEvent StatusChanged(Me, s)
End Sub
Public Property Status() As StatusClass
Get
Return _status
End Get
Set(ByVal value As StatusClass)
If Not _status Is Nothing Then
RemoveHandler _status.StatusChanged, AddressOf StatusHandler
End If
_status = value
If Not _status Is Nothing Then
AddHandler _status.StatusChanged, AddressOf StatusHandler
End If
End Set
End Property
Private Sub StatusHandler(ByVal sender As Object, ByVal e As StatusEventArgs)
OnStatusChanged(e.CurrentStatus)
End Sub
End Class

Resources