How can I send an email with my vb.net code? - asp.net

I am using asp.net / vb.net. I want to send an email. My code does not send an email as it is. I am wondering what I am doing wrong here.
I created a file called email.text that holds the email template. The rest of the code to send the email is below. I removed personal information from my code.
I setup the SMTP connection as such:
Private SMTPClientConnection As SmtpClient
Sub New()
SMTPClientConnection = New SmtpClient
SMTPClientConnection.Host = "HOSTHERE"
SMTPClientConnection.Port = PORTHERE
SMTPClientConnection.DeliveryMethod = SmtpDeliveryMethod.Network
End Sub
Then I created a function to send the email:
Private Shared Function SendEmail(ByVal emailUser As String, ByVal bodyMessage As List(Of String), ByVal priority As MailPriority) As Boolean
Dim functionReturnValue As Boolean = False
Try
If Not String.IsNullOrWhiteSpace(emailUser) Then
If Regex.IsMatch(emailUser, "^([a-zA-Z0-9]+([\.+_-][a-zA-Z0-9]+)*)#(([a-zA-Z0-9]+((\.|[-]{1,2})[a-zA-Z0-9]+)*)\.[a-zA-Z]{2,6})$") Then
Using SMTPClientConnection
Dim smtpMessage As MailMessage = New MailMessage()
Dim _with1 = smtpMessage
_with1.[To].Add(New MailAddress(emailUser))
_with1.From = New MailAddress("Test Email" & " <email#email.com>")
_with1.ReplyToList.Add(New MailAddress("email#email.com"))
_with1.Subject = "Test Email"
_with1.Priority = priority
Dim htmlView As AlternateView = AlternateView.CreateAlternateViewFromString(bodyMessage(0), Nothing, "text/html")
Dim plainView As AlternateView = AlternateView.CreateAlternateViewFromString(bodyMessage(1), Nothing, "text/plain")
_with1.AlternateViews.Add(plainView)
_with1.AlternateViews.Add(htmlView)
SMTPClientConnection.Send(smtpMessage)
Return True
End Using
Else
Throw New SmtpException("Invalid email.")
End If
End If
Catch ex As Exception
End Try
Return functionReturnValue
End Function
I use the function on my code here:
Dim plainBody As String = File.ReadAllText(HttpContext.Current.Server.MapPath("email.txt"))
plainBody = plainBody.Replace("%Name%", emailName)
Dim emailBody As List(Of String) = New List(Of String)(New String() {plainBody})
SendEmail("email#email.com", emailBody, MailPriority.Normal)

The compiler error message is clear. The variable SmtpClientConnection is an instance variable (it exists as a different entity in any class instance where is declared) but you are trying to use inside a Shared method (a method that exists without a class instance). Inside this kind of methods you cannot use instance variables because you don't have an instance from which the method could pick the variable value and use it.
The solution could be to remove the Shared keyword from the method and then, whenever you want to call the method you need to create an instance of the class where the instance variable SmtpClientConnection is initialized and ready to be used in the following call to the SendMail method.
However, you could still use the Shared method but should remove the instance variable and create it inside the SmtpClient method:
Private Shared Function SendEmail(ByVal emailUser As String, ByVal bodyMessage As List(Of String), ByVal priority As MailPriority) As Boolean
Dim functionReturnValue As Boolean = False
Try
If Not String.IsNullOrWhiteSpace(emailUser) Then
If Regex.IsMatch(emailUser, "^([a-zA-Z0-9]+([\.+_-][a-zA-Z0-9]+)*)#(([a-zA-Z0-9]+((\.|[-]{1,2})[a-zA-Z0-9]+)*)\.[a-zA-Z]{2,6})$") Then
Dim SMTPClientConnection As SmtpClient = New SmtpClient
SMTPClientConnection.Host = "HOSTHERE"
SMTPClientConnection.Port = PORTHERE
SMTPClientConnection.DeliveryMethod = SmtpDeliveryMethod.Network
Using SMTPClientConnection
Dim smtpMessage As MailMessage = New MailMessage()
......
SMTPClientConnection.Send(smtpMessage)
Return True
End Using
Else
Throw New SmtpException("Invalid email.")
End If
End If
Catch ex As Exception
' No point in catching an exception and doing nothing here.
' You can log the exception somewhere and then throw it again
LogException(ex)
Throw
' or just remove the try/catch block.
End Try
Return functionReturnValue
End Function
In this way the variable is created only when needed and destroyed as well when the using statement ends. Take also note of the comments relative to the Try/Catch block.

Related

Managing licenses for Office 365 in vb.net

I am trying to run Office365 cmdlets in a vb.net webservice project.The code is:
Public Function ExcutePowershellCommands() As ObjectModel.Collection(Of PSObject)
Try
Dim userList As ObjectModel.Collection(Of PSObject) = Nothing
Dim initialSession As InitialSessionState = InitialSessionState.CreateDefault()
initialSession.ImportPSModule(New String() {"MSOnline"})
Dim O365Password_secureString As New System.Security.SecureString()
Dim O365Password As String = "password"
For Each x As Char In O365Password
O365Password_secureString.AppendChar(x)
Next
Dim credential As New PSCredential("username", O365Password_secureString)
Dim connectCommand As New Command("Connect-MsolService")
connectCommand.Parameters.Add((New CommandParameter("Credential", credential)))
Dim getCommand As New Command("Get-MsolUser")
Using psRunSpace As Runspace = RunspaceFactory.CreateRunspace(initialSession)
psRunSpace.Open()
For Each com As Command In New Command() {connectCommand, getCommand}
Dim pipe As Pipeline = psRunSpace.CreatePipeline()
pipe.Commands.Add(com)
Dim results As ObjectModel.Collection(Of PSObject) = pipe.Invoke()
Dim [error] As ObjectModel.Collection(Of Object) = pipe.[Error].ReadToEnd()
If [error].Count > 0 AndAlso com.Equals(connectCommand) Then
Throw New ApplicationException("Problem in login! " + [error](0).ToString())
Return Nothing
End If
If [error].Count > 0 AndAlso com.Equals(getCommand) Then
Throw New ApplicationException("Problem in getting data! " + [error](0).ToString())
Return Nothing
Else
userList = results
End If
Next
psRunSpace.Close()
End Using
Return userList
Catch generatedExceptionName As Exception
Throw
End Try
End Function
When Connect-MsolService is run, I get this error message:
There was no endpoint listening at https://provisioningapi.microsoftonline.com/provisioningwebservice.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
I can run this function successfully within a windows App. I think some thing might be wrong in IIS. any idea?

Unable to cast object of type 'VB$StateMachine_4_GetAllFrontPageBanners' to type IEnumerable(Of FrontPageBanner)

I'm not really used to working with VB.NET, but i've come across an error where googling did not suffice. I've created this data access class, it has a method that makes use of Yield and vb.net's object initializer shortcut
Public Class FMACMarketingRepository
Private cvConnection As SqlConnection
Private cvCommand As SqlCommand
Private cvReader As SqlDataReader
Public Sub New(Role As InfotelLibrary.Data.DatabaseRole)
cvConnection = New SqlConnection(InfotelLibrary.Data.ConnectionString(Role, InfotelLibrary.Data.DatabaseName.Mongoose))
End Sub
Public Iterator Function GetAllFrontPageBanners() As IEnumerable(Of FrontPageBanner)
Using dbConnection As IDbConnection = cvConnection
Using cmd As IDbCommand = dbConnection.CreateCommand()
cmd.CommandType = CommandType.StoredProcedure
cmd.CommandText = "sel_AllFmacFrontPageBanners"
Using reader As IDataReader = cmd.ExecuteReader()
If reader Is Nothing Then
Yield Nothing
End If
While reader.Read()
Yield New FrontPageBanner() With
{
.Banner_Id = CType(reader("Banner_ID"), Integer),
.Geo_Id = CType(reader("Geo_ID"), Long),
.Title = CType(reader("Title"), String),
.Description = CType(reader("Description"), String),
.Link = CType(reader("Link"), String),
.Image = CType(reader("Image"), Byte()),
.SpecialOffer = CType(reader("Special_Offer"), Boolean)
}
End While
End Using
End Using
End Using
End Function
End Class
There are 0 errors in Intellisense, it builds but when i run the webpage it get the error
System.InvalidCastException: Unable to cast object of type 'VB$StateMachine_4_GetAllFrontPageBanners' to type 'System.Collections.Generic.List`1[InfotelData.Mongoose.Data.FrontPageBanner]'.
Line 7:
Line 8: Protected Sub Page_Load(ByVal sender As Object, e As EventArgs) Handles Me.Load
Line 9: Dim banners As List(Of FrontPageBanner) = cvRepo.GetAllFrontPageBanners()
Line 10: If banners.Count() > 0 Then
Line 11: rptUploadedBanners.DataSource = banners
Debugging just gives the same error when it hits page_load.
I've the distinct feeling that user error is to blame.
GetAllFrontPageBanners returns an IEnumerable(Of FrontPageBanner)(*) and you're trying to store it inside a List(Of FrontPageBanner). I'm surprised it doesn't give a compile time error (you're probably in Option Strict Off mode)
you need to make a List from the enumerable using .ToList for example :
Dim banners As List(Of FrontBanner) = cvRepo.GetAllFrontPageBanners.ToList
(*) Internally an Iterator block transform the function into a generated "class-state-machine" (which implement IEnumerable(Of FrontBanner) in your case).
That's the odd name you got but you can (and should) consider it like the return type given in your source code.
More information about that here

Trying to spawn a new thread in ASP.NET; no errors, no thread

I am trying to spawn a new thread from an ASP page written in VB.NET, on .NET 3.5.
The page allows a user to upload files and then processes the files into the database.
As the processing can take a while, I want to upload them, spawn the processing onto a new thread, and then when it completes send the user a notification through our database-driven notification module in the system.
I've tried a couple different examples I've found online, but they don't seem to work. There is no error thrown, but it never seems to actually launch the processing code on a new thread either.
Here is my submittal code in the web page:
Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSubmit.Click
Try
If Not (file1.HasFile Or file2.HasFile Or file3.HasFile Or file4.HasFile Or file5.HasFile) Then
AddErrorMessage("Please specify at least one file.")
Else
Dim l = New List(Of InventoryUploads.File)
If file1.HasFile Then l.Add(New InventoryUploads.File With {.Name = file1.FileName, .Content = file1.FileContent})
If file2.HasFile Then l.Add(New InventoryUploads.File With {.Name = file2.FileName, .Content = file2.FileContent})
If file3.HasFile Then l.Add(New InventoryUploads.File With {.Name = file3.FileName, .Content = file3.FileContent})
If file4.HasFile Then l.Add(New InventoryUploads.File With {.Name = file4.FileName, .Content = file4.FileContent})
If file5.HasFile Then l.Add(New InventoryUploads.File With {.Name = file5.FileName, .Content = file5.FileContent})
InventoryUploads.ProcessFiles(l, Session.UserIdent, chkRcvOverwrite.Checked)
NewRow("Your files have been queued and are being processed. You will be sent a notification when they are completed.")
End If
Catch ex As Exception
LogEx(ex)
NewRow("There was an error queueing your files." & BR & ex.Message)
End Try
End Sub
From a UI point of view, this all works, the page posts the files, and it shows the user the message about "your files have been queued".
The call to InventoryUploads.ProcessFiles is an encapsulation function in front of the threading code, which is all contained in the InventoryUploads module (following):
Imports System.Threading
Imports System.Threading.Tasks
Public Module InventoryUploads
Public Structure File
Private pName As String
Private pContent As IO.Stream
Private pProcessed As Boolean
Public Property Name As String
Get
Return pName
End Get
Set(value As String)
pName = value
End Set
End Property
Public Property Content As IO.Stream
Get
Return pContent
End Get
Set(value As IO.Stream)
pContent = value
End Set
End Property
Public Property Processed As Boolean
Get
Return pProcessed
End Get
Set(value As Boolean)
pProcessed = value
End Set
End Property
End Structure
Public Sub ProcessFiles(files As List(Of File), userident As String, receivingsOverwrite As Boolean)
Try
Dim params = Array.CreateInstance(GetType(Object), 3)
params(0) = files
params(1) = userident
params(2) = receivingsOverwrite
'// Threading Method 1
Dim pts = New ParameterizedThreadStart(AddressOf ThreadedProcessFiles)
Dim thd = New Thread(pts)
thd.IsBackground = True
thd.Start(params)
'// Threading Method 2
'ThreadPool.QueueUserWorkItem(AddressOf ThreadedProcessFiles, params)
'// Threading Method 3
Dim f As Func(Of Integer) = Function() ThreadedProcessFiles(params)
Task.Factory.StartNew(f)
Catch ex As Exception
IO.File.WriteAllText("C:\idwherenet.log", ex.Message)
Throw
End Try
End Sub
''' <summary>
'''
''' </summary>
''' <param name="params">exepcts params to contain 3 objects,
''' 1) type List(Of File),
''' 2) string userident to notify on finish
''' 3) boolean whether receivings should overwrite</param>
''' <remarks></remarks>
Private Function ThreadedProcessFiles(params() As Object) As Boolean
IO.File.WriteAllText("C:\mylog.log", "hello ThreadedProcessFiles?")
'Log("threadedprocessfiles: got here")
Dim files As List(Of File), uident As String = "", rcvovr As Boolean
Try
files = params(0)
uident = CStr(params(1))
rcvovr = CBool(params(2))
If files.Count = 0 Then
SendNotification(NotificationTypes.SYS, uident, "No files provided for inventory upload; nothing processed.")
Exit Sub
End If
For Each f In files
f.Processed = False
If f.Content.Length = 0 Then Continue For
'// process the file here....
f.Processed = True
Next
SendNotification(NotificationTypes.SYS, uident, "Inventory upload processing completed.")
Return True
Catch ex As Exception
'LogEx(ex)
'Log(ex.Message, ex.ToString)
If Not uident.IsEmpty Then SendNotification(NotificationTypes.SYS, uident, "Inventory upload processing encountered an error. " & ex.Message, ex.ToString)
Return False
End Try
End Sub
End Module
In the ProcessFiles sub, you can see the three different methods I have tried to spawn the thread, including a NuGet backport of the Task Parallel Library... neither works. I have confirmed that is is making it into the ProcessFiles sub, and the code to spawn the thread is not throwing any errors... it just never actually calls the ThreadedProcessFiles function.
Any ideas?
UPDATE: Oh, actually, the NuGet package DOES seem to be working, FINALLY! It just doesn't write out to the file (context/security/impersonation permissions I guess). Now I can finally move on!
If you're using .NET 4 or 4.5, the Task Parallel Library makes this sort of thing super easy:
Task.Factory.StartNew(Function() ThreadedProcessFiles(params));
(I think that's the right syntax for VB)
If you go this route, I would change the params to just send the three parameters separately.

smtp clients `SendAsync()` method

Protected Sub btnLocalSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnLocalSubmit.Click
Dim logic = New connections
logic.emailsToSend(User.Identity.Name, getURL, reportedBy)
SendAsync()
Response.Redirect(getRedirectionPath, False)
Catch ex As Exception
Response.Write(ex.Message)
Finally
_con.Close()
_con.Dispose()
_sqlComm.Dispose()
End Try
End Sub
Sub SendAsync()
Dim _con As New SqlConnection(ConfigurationManager.ConnectionStrings("CitizenJDBConnectionString").ConnectionString)
Dim _sqlDataAdapter As New SqlDataAdapter("SELECT * FROM EmailSender", _con)
Dim _table As New System.Data.DataTable
Try
_con.Open()
_sqlDataAdapter.Fill(_table)
_con.Close()
For i As Integer = 0 To _table.Rows.Count - 1
Dim AppPath As String = Request.PhysicalApplicationPath
Dim sr As New StreamReader(AppPath & "EmailTemplates/NewReport.txt")
Dim message As New MailMessage()
message.IsBodyHtml = True
message.From = New MailAddress("admin#xxxx.com")
message.To.Add(New MailAddress(_table.Rows(i).Item(1)))
message.Subject = "New User registration !"
message.Body = sr.ReadToEnd()
sr.Close()
message.Body = message.Body.Replace("<%ReporterName%>", _table.Rows(i).Item(3))
message.Body = message.Body.Replace("<%ReportURL%>", _table.Rows(i).Item(2))
Dim client As New SmtpClient()
client.Host = "smtp.xxxxx.com"
'smtp.gmail.com
client.Port = 25
client.UseDefaultCredentials = True
client.Credentials = New System.Net.NetworkCredential("admin#xxxx.com", "123456")
'client.EnableSsl = True
Dim userState As Object = message
'wire up the event for when the Async send is completed
AddHandler client.SendCompleted, AddressOf SmtpClient_OnCompleted
client.SendAsync(message, userState)
Next
Catch ex As Exception
Response.Write(ex.Message)
End Try
End Sub 'SendAsync
Public Sub SmtpClient_OnCompleted(ByVal sender As Object, ByVal e As AsyncCompletedEventArgs)
'Get the Original MailMessage object
Dim message As MailMessage = CType(e.UserState, MailMessage)
'write out the subject
Dim subject As String = message.Subject
If e.Cancelled Then
Console.WriteLine("Send canceled for mail with subject [{0}].", subject)
End If
If Not (e.Error Is Nothing) Then
Console.WriteLine("Error {1} occurred when sending mail [{0}] ", subject, e.Error.ToString())
Else
Console.WriteLine("Message [{0}] sent.", subject)
End If
End Sub 'SmtpClient_OnCompleted
I am using the smtp clients SendAsync() function to send out emails asynchronously...but this function does not work ...why?? i do not get any email..when i send it Synchronously...i get the emails, this means my settings are correct...so what is wrong with the SendAsync() method??
I do this all the time, and after years of doing this I suggest a (2) fold solution to your problem:
Refactor the actual sending email code (System.Net stuff) into a WCF service or separate .dll (I prefer the service).
Continue to use your asynchronous delegate call from your ASP.NET page but do so in a 'fire-and-forget' manner where you do not wire up any callbacks.
You might say you need to know if something went wrong with sending the email. Let the WCF service that sends the emails handle this. Do any logging in the service. After all that's all you were really doing anyways was logging. If you need to get fancier with a workflow if the email fails, there are ways that your ASP.NET can be flagged, but I think you will find that once the service to send the emails is stable, you will have very few problems.
In fact I have been doing this exact method for years using a service called by ASP.NET to send emails and have sent 10 of thousands of differing emails and never had any problem with this fire-and-forget design.
And lastly, setting the page Async=True makes the page act overall synchronously in the end by blocking the main thread until all asynchronous process are completed. This can make the pages very slow to load and is typically not desired.

Find If User is Member of Active Directory Group ASP.NET VB?

I am using Active Directory to authenticate users for an intranet site. I would like to refine the users that are authenticated based on the group they are in in Active Directory. Can someone show me or point me to directions on how to find what groups a user is in in ASP.NET 4.0 (VB)?
I realize this post is quite old but I thought I might update it with processes I am using. (ASP.Net 4.0, VB)
If using integrated windows security, on a domain.
Page.User.IsInRole("domain\GroupName") will check to see if the authenticated user is a member of the specified group.
If you would like to check another users group membership other than the authenticated user.
Two stage for checking multiple groups with the same user principal:
Dim MyPrincipal As New System.Security.Principal.WindowsPrincipal _
(New System.Security.Principal.WindowsIdentity("UserID"))
Dim blnValid1 As Boolean = MyPrincipal.IsInRole("domain\GroupName")
Single stage for checkin a single group:
Dim blnValid2 As Boolean = New System.Security.Principal.WindowsPrincipal _
(New System.Security.Principal.WindowsIdentity("userID")).IsInRole("domain\GroupName")
NOTE:: The IsInRole method does work with nested groups. If you have a top level group with a sub group that is a member, and the user is a member of the sub group.
I think I have the ultimate function to get all AD groups of an user included nested groups without explicit recursion:
Imports System.Security.Principal
Private Function GetGroups(userName As String) As List(Of String)
Dim result As New List(Of String)
Dim wi As WindowsIdentity = New WindowsIdentity(userName)
For Each group As IdentityReference In wi.Groups
Try
result.Add(group.Translate(GetType(NTAccount)).ToString())
Catch ex As Exception
End Try
Next
result.Sort()
Return result
End Function
So just use GetGroups("userID"). Because this approach uses the SID of the user, no explicit LDAP call is done. If you use your own user name it will use the cached credentials and so this function is very fast.
The Try Catch is necessary because in large companyies the AD is so big that some SIDs are getting lost in space.
For those who may be interested, this is how I ended up coding it:
Dim ID As FormsIdentity = DirectCast(User.Identity, FormsIdentity)
Dim ticket As FormsAuthenticationTicket = ID.Ticket
Dim adTicketID As String = ticket.Name
Dim adSearch As New DirectorySearcher
adSearch.Filter = ("(userPrincipalName=" & adTicketID & ")")
Dim adResults = adSearch.FindOne.Path
Dim adResultsDirectory As New DirectoryEntry(adResults)
Dim found As Boolean = False
For Each entry In adResultsDirectory.Properties("memberOf")
Response.Write(entry)
Response.Write("<br/>")
If entry = "CN=GroupName,CN=UserGroup,DC=my,DC=domain,DC=com" Then
found = True
End If
Next
If Not (found) Then
Response.Redirect("login.aspx")
End If
I found this here.
''' <summary>
''' Function to return all the groups the user is a member od
''' </summary>
''' <param name="_path">Path to bind to the AD</param>
''' <param name="username">Username of the user</param>
''' <param name="password">password of the user</param>
Private Function GetGroups(ByVal _path As String, ByVal username As String, _
ByVal password As String) As Collection
Dim Groups As New Collection
Dim dirEntry As New _
System.DirectoryServices.DirectoryEntry(_path, username, password)
Dim dirSearcher As New DirectorySearcher(dirEntry)
dirSearcher.Filter = String.Format("(sAMAccountName={0}))", username)
dirSearcher.PropertiesToLoad.Add("memberOf")
Dim propCount As Integer
Try
Dim dirSearchResults As SearchResult = dirSearcher.FindOne()
propCount = dirSearchResults.Properties("memberOf").Count
Dim dn As String
Dim equalsIndex As String
Dim commaIndex As String
For i As Integer = 0 To propCount - 1
dn = dirSearchResults.Properties("memberOf")(i)
equalsIndex = dn.IndexOf("=", 1)
commaIndex = dn.IndexOf(",", 1)
If equalsIndex = -1 Then
Return Nothing
End If
If Not Groups.Contains(dn.Substring((equalsIndex + 1), _
(commaIndex - equalsIndex) - 1)) Then
Groups.Add(dn.Substring((equalsIndex + 1), & _
(commaIndex - equalsIndex) - 1))
End If
Next
Catch ex As Exception
If ex.GetType Is GetType(System.NullReferenceException) Then
MessageBox.Show("Selected user isn't a member of any groups " & _
"at this time.", "No groups listed", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
'they are still a good user just does not
'have a "memberOf" attribute so it errors out.
'code to do something else here if you want
Else
MessageBox.Show(ex.Message.ToString, "Search Error", & _
MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
End Try
Return Groups
End Function
End Class
To just check if a user is member of a group including sub-groups just use:
Public Function IsInGroup(ByVal objectName As String, groupName As String) As Boolean
Try
return New WindowsPrincipal(New WindowsIdentity(objectName)).IsInRole(groupName))
Catch ex As Exception
End Try
Return False
End Function

Resources