404 messaggi dal 09 maggio 2012
Ciao ragazzi, ho un button che invoca una sub che esegue un processo abbastanza lungo (invio di circa 500 mail). Vorrei però che l'utente possa annullare l'invio e quindi tornare nuovamente sulla home page. Attualmente se durante l'invio (in postback) clicco su un nuovo link o cerca di uscire dalla pagina ... non accade nulla e la pagina rimane come impallata in attesa che la sub termini ... ho notato infatti che se anche dovessi chiudere il browser l'invio viene portato a termine.
Chi mi suggerisce come interrompere immediatamente la sub chiamata ? Grazie
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao Francesco,
nulla ti vieta di inviare 500 email da una Sub ma, come hai visto tu stesso, non si concilia bene con le esigenze dell'utente. Il modo "classico" di risolvere il problema è quello di spezzare l'invio in gruppi di poche decine di destinatari alla volta. Ad esempio, ai tempi di ASP classico, ricordo di averlo fatto tramite una pagina che si ricaricava costantemente in un iframe nascosto e ad ogni ricaricamento aggiornava una barra nella pagina contenitrice.

Tuttavia, questo richiedeva che l'utente mantenesse aperta la pagina per l'intera durata della spedizione.
Dovremmo prendere atto che inviare così tante email è un compito di lunga durata che andrebbe svolto da un servizio per windows, ovvero al di fuori del contesto di una richiesta web. In questo modo può funzionare anche se l'utente si scollega dal sito o naviga in altre pagine.

Se sei in hosting condiviso non avrai la possibilità di installare un servizio per windows ma dovresti comunque ricorrere a dei task in background in modo che l'utente non sia costretto ad aspettare che la pagina termini la sua esecuzione.
Qui trovi elencati dei modi per eseguire tali task, dai più semplici fino a soluzioni complete come Hangfire.
http://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx

Se l'invio avviene in background, allora le tue pagine aspx serviranno semplicemente a comandare tale invio, cioè ad avviarlo, fermarlo o visualizzarne lo stato corrente, rendendo l'esperienza per l'utente estremamente responsiva perché indipendente dalla durata dell'invio.

Dimmi tu se vuoi provare a farlo con i task in background. In caso, approfondiamo l'argomento.

ciao,
Moreno

Enjoy learning and just keep making
404 messaggi dal 09 maggio 2012
Si infatti il cliente ha un hosting condiviso ... e ha scelto questa modalità per inviare le mail della sua lista. Come posso lavorare con i task integrando il tutto al modulo che ho sviluppato ?
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao Francensco,

drugomatera ha scritto:

Come posso lavorare con i task integrando il tutto al modulo che ho sviluppato ?

Nella tua Sub, anziché inviare ogni email direttamente, dovresti invece accodare i Task che invieranno quelle email.

Accodare un Task è un'operazione molto rapida, e quindi la tua Sub si completerebbe molto rapidamente.
Ci sarà poi un TaskScheduler che, in background e con tutta calma, si occuperà di scodare i Task uno ad uno per eseguirli.

Le librerie che sono elencate nell'articolo che ti ho linkato, ti mettono appunto a disposizione un metodo per accodare Task e dispongono di un TaskScheduler che andrà a scodarli.

Tra tutti quelli elencati nell'articolo, forse inizierei col provare FluentScheduler. Mi sembra abbastanza immediato da usare e *dovrebbe* funzionare anche in regime di Medium Trust (importante dato che sei in hosting condiviso).

Nella tua Sub, potresti fare una cosa del genere (il codice è molto semplice):
'Creo un "registro" di FluentScheduler. E' il coordinatore che si occuperà di scodare le azioni.
Dim registry As New Registry()
'Piccolo espediente: inizio con l'accodare un'azione vuota perché mi serve un riferimento all'oggetto Schedule, che userò fra poco nel ciclo For Each
Dim schedule = registry.Schedule(Sub() Return)
'Questi sono i destinatari del tuo mailing
Dim destinatari = New String() {"info@example.com", "info@contoso.com", "info@fabrikam.com"}

For Each destinatario As String In destinatari
    'Accodo un'azione allo Schedule che avevo ottenuto prima
    'C'è un comodo metodo AndThen che mi permette di accodarli uno dopo l'altro
    'La funzione InvioEmail sarà quella che conterrà il codice di spedizione
    schedule.AndThen(Sub() InvioEmail(destinatario))
Next
'Avvio l'esecuzione di tutta la catena di azioni
schedule.Execute()


Ma fai un test su un nuovo progetto vuoto prima di integrarlo nella tua applicazione. Vedi se ti soddisfa. Puoi installare FluentScheduler con questo comando NuGet dalla console di gestione pacchetti di Visual Studio.

Install-Package FluentScheduler


ciao,
Moreno
Modificato da BrightSoul il 18 dicembre 2014 08.04 -

Enjoy learning and just keep making
404 messaggi dal 09 maggio 2012
si questo metodo funziona e posso integrarlo facilmente nel progetto completo. Non capisco alcune cose:
- che vantaggio ha usare una task rispetto ad una normale sub ?
- inoltre, il mio intendo è quello di poter interrompere tale invio al semplice clic di un pulsante "interrompi".
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,

drugomatera ha scritto:

che vantaggio ha usare una task rispetto ad una normale sub ?

Il vantaggio è che non blocchi il thread della pagina aspx. Di conseguenza, l'utente non dovrà attendere molto prima di riguadagnare il controllo sull'interfaccia del sito. Così offri un'esperienza d'uso migliore e non tieni impegnato un thread del pool usato da IIS, che è una risorsa preziosa per il server.

E' come quando vai alla lavanderia a gettoni: l'utente non deve per forza fermarsi a guardare il cestello che gira ma in quell'ora può fare altro, come farsi un giro per il centro commerciale.

drugomatera ha scritto:

inoltre, il mio intendo è quello di poter interrompere tale invio al semplice clic di un pulsante "interrompi".

Bisognerebbe approfondire la API di FluentScheduler, magari esiste un metodo apposito per terminare azioni già accodate.
Nel repository Github ho trovato solo un esempio per disabilitare task ricorrenti, che non si adatta a questo caso, così come te l'ho presentato nel post precedente.

Nel frattempo, potresti implementarlo con poche altre righe di codice usando un CancellationTokenSource su cui invocherai Cancel() nel momento in cui vuoi interrompere l'esecuzione. Nella Sub InvioEmail, vai a controllare se la sua proprietà IsCancellationRequested è true, oppure invoca ThrowIfCancellationRequested, in modo da arrestare l'esecuzione del thread. Occhio che l'eccezione non tiri giù l'intero processo, spero che FluentScheduler riesca a gestirla. Questa è un'altra cosa da verificare prima di mettere il sistema in produzione.

ciao,
Moreno
Modificato da BrightSoul il 19 dicembre 2014 09.07 -

Enjoy learning and just keep making
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,
ho messo una demo qui, se vuoi dare un'occhiata alla soluzione che usa il CancellationTokenSource di cui ti parlavo nel post precedente.
http://1drv.ms/1v5yAom

In questo esempio c'è una classe TaskInvioEmail che ti dà dei metodi per aggiungere dei destinatari, avviare la spedizione e fermarla.
Questi metodi vengono invocati dalla pagina aspx, che diventa il tuo punto di comando della spedizione.

La spedizione avviene, come al solito, attraverso FluentScheduler e può essere parallelizzata per inviare più email contemporaneamente. Attenzione però perché più frequenti sono gli invii e più è probabile che sorgano dei problemi nella spedizione.

Dato che sei in hosting condiviso, il server SMTP potrebbe avere questi problemi:
  • Dato che viene usato da molti clienti contemporaneamente, è probabile che esistano delle limitazioni al numero di messaggi inviabili nell'unità di tempo;
  • La sua reputazione potrebbe non essere delle migliori, se qualche cliente l'ha usato in passato per inviare SPAM. Come conseguenza, potresti notare che le tue email, su alcuni provider, vanno a finire nella posta indesiderata o semplicemente non arrivano.

Se ti capitasse di incontrare questi problemi, forse dovresti usare un altro SMTP oppure appoggiarti ad un servizio di invio newsletter, che magari è in grando anche di fornirti delle statistiche di invio e ti notifica gli eventuali errori di consegna.

Nel progetto che ti ho linkato, il servizio di spedizione è su una classe apposita e quindi puoi decidere da lì se inviare tu stesso l'email tramite la classe SmtpClient, o se invece affidarti ad un servizio remoto che probabilmente dovrai invocare con delle chiamate HTTP REST.

ciao,
Moreno
Modificato da BrightSoul il 20 dicembre 2014 18.49 -

Enjoy learning and just keep making

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.