I have a database of email subscribers; approx. 1800 in the list. We have our own exchange server. I'm using the code below to grab each email address from the DB and send email, one at a time. I'm using an ASP.NET 4.0 Web Form to do this.
I notice the page hanging when the emails are being sent. What would be the best approach for implementing this - use a console app? How would I go about stress testing something like this?
I'm also getting an unhandled error message in the server log:
Event code: 3001
Event message: The request has been aborted.
// Call data access method via business class
TaxSalesBusiness bizClass = new TaxSalesBusiness();
DataSet ds = bizClass.GetSubscribers();
foreach (DataRow row in ds.Tables[0].Rows)
{
// Check well-formedness of each email adddress
if (!IsWellformedEmailAddr(row["Email"].ToString()))
{
// Ignore and log mal-formed email address
LogError(row["Email"].ToString()
+ " is a malformed email address. Message was not sent to this subscriber "
+ row["Name"].ToString() + ".", "");
continue;
}
else
{
string toAddress = row["Email"].ToString();
smtpClient.Send(fromAddress, toAddress, message.Subject, message.Body);
}
}
I notice the page hanging when the emails are being sent. What would
be the best approach for implementing this - use a console app?
Yes.
And you can SendAsync instead of waiting for one email to be sent before you send the next one. I don't know how much your Exchange server will like that, though.
The problem with your current approach is that sending 1800 emails one by one is going to take a lot of time and using a web page to perform such a long operation will probably timeout the request. You can perhaps do it on an async page and launch everything on its own thread, but that's just complicating things more than it needs to when you can perfectly do this in a Console App with far less lines of code and complications. Remember the KISS principle.
Another (more stable) solution could be to forward the mails to a (database?) queue, and have a Windows Service poll that queue once in a while. If there are new things on the queue the Windows Service is responsible for sending the e-mails.
This approach will help you steer clear from performance issues in your website, and it could make the delivery of the mails to be more reliable.
Related
I am researching to use signalr to send messages from an api to a specific user (keyword). Locally, I have everything working as designed (even using redis backplane).
When I move up to an actual environment with multiple servers (azure app service), it seems like messages to specific users don't flow through the backplane. If I send a message to Clients.All it works. But, if I send a message to Clients.User(username), the message is never received. This works locally because it's a single server, but doesn't seem to work in multiple servers.
await this.impersonationContext.Clients.User(mainUserName).SendAsync("msguser", new object[] { mainUserName });
await this.impersonationContext.Clients.All.SendAsync("msg", new object[] { "wtf" });
If I call the above code, only the msg event is fired, but the msguser is never recieved.
Could I be missing something on the setup? That's my assumption, I cannot be the only one doing this.
Below is my setup in the startup.cs. This is using .net core 5 with the latest nugets, etc
services.AddSignalR(options =>
{
options.EnableDetailedErrors = true;
})
.AddStackExchangeRedis(this.Configuration["Redis:Cache"], options => {
options.Configuration.ChannelPrefix = "ImpersonationService";
});
services.AddSingleton<IUserIdProvider, NameUserIdProvider>();
Any help would be appreciated.
Update #1
Looks like the user info is being pushed through the backplane (username hidden). So maybe its the connection from javascript client?
Update #2
Getting closer...looks like the subscription isn't setup for the specific user like I see locally. Could this be websockets?
Update #3
Found it....sorta.
I was missing the authorize attribute on the hub, which was allowing the websocket to connect, even though websockets isn't authenticating for some reason (different issue). Once I added the authorize, it will drop down to long polling with the user info and works as designed
I'm playing with different ways to create push notifications in asp.net core, since my boss asked me to research it.
So i just set up a barebones project that uses signalr to send messages from a hub to the client, and conversely for the client to the hub.
Currently, I have a button on a certain page where this javascript is used:
function receive() {
$.ajax({
url: '/msg/SendToClient',
type: 'get',
});
}
var connection = new signalR.HubConnectionBuilder()
.withUrl("/NotificationHub")
.build();
connection.on("ReceiveMessage", function (user, message) {
alert(message);
});
connection.start();
Where the receive() is called everytime the button is pushed, that means that a corresponding controller action is called, which sends a message from server -> client.
But what I want is that I would like the javascript file to be laying on the client, and just run once in a while to check for new available push notifications.
A few scenarios are available, and I would like to know about all of them:
Push notifications when browser is closed. I'm guessing this is not possible with a "regular" service worker?
Push notification when browser is open, but site is not open. For this, I guess I will need to somehow have a javascript file/service worker on the clients computer just always running. This I really have no idea how to achieve this.
A push notification that can work when the site is open in the browser. All I think I need for this is to have the javascript included always when the user is on the site, and then somehow make a request every few minutes.
Any inputs on these three things will be greatly appreciated. Is any of them easily achieveable/advisable? Is there any "normal" mode of operation for these three approaches to push notifications?
For any of these three scenarios, is there a case where signalr is parhaps not the best resource?
I'm building a new application and one of the its function is communication between seller and customer. For this reason I want to use Twilio API.
So let's imagine we have two person: seller and customer, and they are going to communicate. My idea is that these two person shouldn't know real phone number each other, so I buy two phone numbers from Twilio, one for seller and one for customer and connect them with real phones in my app. For convenience I've created TwiML App in Twilio console and set REQUEST and STATUS CALLBACK URLs for Voice calls, these urls are pointed to Webhook in my app. My application is based on .Net Core, but I still use full .Net4.6 framework, because there are no some .dlls for .Net Core and seems Twilio helpers for C# have also been built for full .Net framework. Any way, my webhook method looks like:
[HttpPost("call")]
public IActionResult IncomingCall(VoiceRequest request) {
// some logic
VoiceResponse response = new VoiceResponse();
response.Dial({real_seller_number}, callerId: {virtual_customer_number}, record: "record-from-ringing-dual");
return Content(response.ToString(), "application/xml");
}
Here, let's imagine I'm customer, I want to call seller, I call its virtual Twilio number, Twilio makes a request to this webhook and it make a call to real seller's number from virtual customer number. This is OK and works as intended.
When the call ends, Twilio makes a request to STATUS CALLBACK url, and this methos looks like:
[HttpPost("call/callback")]
public IActionResult IncomingCallCallback(StatusCallbackRequest request) {
// some logic
return Ok("Handled");
}
In a first method you can see I want to record conversation for internal reason, and I expected RecordingSid and RecordingUrl in second method, but I always get them null. I can see the recording in Twilio console, but cannot get them via API, that's my problem. I spent a lot of time and read a lot of docs, but didn't find clear explanation how to do it right. Can someone help me?
Twilio developer evangelist here.
When recording calls the recording might not be ready by the time you receive the statusCallback request. Instead you should set a recordingStatusCallback URL which will be called when the recording is complete and ready.
[HttpPost("call")]
public IActionResult IncomingCall(VoiceRequest request) {
// some logic
VoiceResponse response = new VoiceResponse();
response.Dial({real_seller_number},
callerId: {virtual_customer_number},
record: "record-from-ringing-dual",
recordingStatusCallback: {url_in_your_application_that_processes_recordings}
);
return Content(response.ToString(), "application/xml");
}
I am using ASP.NET Web forms,
When a user submit a page, an email will be sent to many people which is slowing the post-back,
what is the best way to send the emails without slowing the reloading of the page?
thanks
You can use the System.Net.Mail.SmtpClient class to send the email using the SendAsync() method.
var smtpClient = new SmtpClient();
var message = new MailMessage(fromAddress, toAddress, subject, body);
smtpClient.SendCompleted += new SendCompletedEventHandler(OnSendCompletedCallback);
smtpClient.SendAsync(message, null); // Null Or pass a user token to be send when the send is complete
If you need to handle perform some additional stuff after the async send is complete you can subscribe to the SendCompleted event of the SmtpClient as well.
private void OnSendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
// Handle the callback if you need to do anything after the email is sent.
}
Here is a link to the documentation on MSDN.
I've found unless you're building a very small website, it's almost always best to send mail from a separate Windows Service.
Your Web front-end logs the mail to be sent in your database for example. This has a nice side-effect of allowing you do also develop an sent folder, outbox, etc. Your windows service polls the mail table and does the actual sending.
Sending mail can cause lots of exceptions, can be slow, can timeout, host processes reaped, etc. Handling it in the background makes a lot of sense in many situations.
Here's more information on Windows Services.
I have to implement gmail style chatting in my asp.net website. now i know much has been said in this regard here and other forums...about COMET and its befits....
i recently saw this site www.indyarocks.com and when i profiled their website i found out that for chatting they send a async request and the page waits until the server has some data to return and only after the page returns....(i mean it shows status 200 OK) and again a request is dispatched.
i have implemeted chat in my website in which i poll the database after 5 sec for any new chat...so i want to know if i send a request using ASP.NET AJAX to a web method and keep on looping on the server until it has some data to return and then return to the webpage that called it is it a good approach and if not what are its demerits????
the code that i can use
<WebMethod(EnableSession:=True)> _
Public Function looper(ByVal x As String) As String
Dim flag As Boolean = False
While (flag = False)
Dim ans As String = getScalar("select 1 from Chat where sent_by=1")
If Not ans Is Nothing Then
flag = True
End If
End While
Return "x"
End Function
here i can loop over the server until it has some data
in any case is it better than the polling approach????
Does anyone have suggestions to improve this approach???
Its better than polling approach from client side
Why, because
It avoids server roundtrip - saves lot of time
And avoid unnessary calls to server (Polling approach calls the webmethod even though the data is not available)
In other hand, your current COMET approach, Server calls are minimal from javascript because the new request only be made from client if the server return the updated data.
So keep up with the current design