c# - method - Ejecutar una operación asincrónica activada por una solicitud de página web ASP.NET
task actionresult c# (5)
Bien, aquí está el problema: el atributo Async es para el caso en que su página va a llamar a alguna tarea larga que también bloquea el hilo, y luego su página necesita el resultado de esa tarea para devolver información al usuario. Por ejemplo, si su página necesita llamar a un servicio web, espere su respuesta y luego use los datos de la respuesta para representar su página.
La razón por la que usarías el atributo Async es para evitar bloquear el hilo. Esto es importante porque las aplicaciones ASP.NET usan un grupo de subprocesos para atender las solicitudes, y solo hay un número relativamente pequeño de subprocesos disponibles. Y si cada llamada ata el hilo mientras espera la llamada del servicio web, pronto llegará a suficientes usuarios simultáneos que los usuarios tendrán que esperar hasta que se completen estas llamadas al servicio web. El atributo Async permite que el hilo vuelva al grupo de subprocesos y sirva a otros visitantes simultáneos en su sitio web, en lugar de obligarlo a quedarse quieto sin hacer nada mientras espera que vuelva la llamada del servicio web.
El resultado para usted es el siguiente: el atributo Async está diseñado para el caso en que no puede renderizar la página hasta que la tarea asíncrona se complete, y es por eso que no representa la página de inmediato.
Debes iniciar tu propio hilo y convertirlo en un hilo de daemon. No recuerdo la sintaxis exacta para eso, pero puede encontrarlo fácilmente en el documento buscando en el documento BCL "daemon". Esto significa que el hilo evitará que su aplicación se cierre mientras está activa, lo cual es importante porque ASP.NET e IIS se reservan el derecho de "reciclar su proceso" cuando lo consideren necesario, y si eso sucede mientras el hilo está funcionando, tu tarea será detenida Hacer que el demonio de subprocesos lo evite (excepto en algunos casos de borde raros posibles ... descubrirá más cuando encuentre la documentación sobre esto).
Ese hilo daemon es donde iniciarás estas tareas. Y después de que hayas indicado el hilo del daemon para realizar la tarea, puedes renderizar tu página de inmediato ... para que el procesamiento de la página se realice de inmediato.
Incluso mejor que un hilo daemon en su proceso ASP.NET, sin embargo, sería implementar un servicio de Windows para realizar la tarea. Haga que su aplicación ASP.NET comunique la tarea que se realizará al Servicio. No es necesario tener un hilo de daemon ni preocuparse por el reciclado de su proceso ASP.NET. ¿Cómo le dices al Servicio que haga la tarea? Tal vez a través de WCF, o tal vez mediante la inserción de un registro en una tabla de base de datos que el Servicio sondea. O una cantidad de otras formas.
EDITAR: Aquí hay otra idea, que he utilizado antes para este mismo propósito. Escriba la información sobre su tarea en una cola de MSMQ. Haga que otro proceso (tal vez incluso en otra máquina) salga de esa cola y realice la tarea que consume mucho tiempo. El trabajo de insertar en una cola está optimizado para regresar lo más rápido posible, por lo que su hilo no se bloqueará mientras los datos que ingresa en la cola se envíen por el cable o algo por el estilo. Es una de las formas más rápidas de tomar nota del hecho de que una tarea debe realizarse sin esperar a que se ejecute.
Tengo una operación asincrónica que por diversos motivos debe activarse mediante una llamada HTTP a una página web ASP.NET. Cuando se solicita mi página, debe comenzar esta operación e inmediatamente devolver un reconocimiento al cliente.
Este método también está expuesto a través de un servicio web de WCF, y funciona perfectamente.
En mi primer intento, se produjo una excepción, diciéndome:
Asynchronous operations are not allowed in this context. Page starting an asynchronous operation has to have the Async attribute set to true and an asynchronous operation can only be started on a page prior to PreRenderComplete event.
Así que, por supuesto, agregué el parámetro Async="true"
a la directiva @Page
. Ahora, no obtengo un error, pero la página se está bloqueando hasta que se complete la operación asincrónica.
¿Cómo hago para que funcione una verdadera página de "olvídate del fuego"?
Editar: Algunos códigos para más información. Es un poco más complicado que esto, pero traté de tener una idea general allí.
public partial class SendMessagePage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string message = Request.QueryString["Message"];
string clientId = Request.QueryString["ClientId"];
AsyncMessageSender sender = new AsyncMessageSender(clientId, message);
sender.Start();
Response.Write("Success");
}
}
La clase AsyncMessageSender:
public class AsyncMessageSender
{
private BackgroundWorker backgroundWorker;
private string client;
private string msg;
public AsyncMessageSender(string clientId, string message)
{
this.client = clientId;
this.msg = message;
// setup background thread to listen
backgroundThread = new BackgroundWorker();
backgroundThread.WorkerSupportsCancellation = true;
backgroundThread.DoWork += new DoWorkEventHandler(backgroundThread_DoWork);
}
public void Start()
{
backgroundThread.RunWorkerAsync();
}
...
// after that it''s pretty predictable
}
Puede solucionar esta limitación con bastante facilidad y sin configurar Async como verdadero.
public void Start()
{
new Task(() =>
{
backgroundThread.RunWorkerAsync();
}).Start();
}
Si está ejecutando formularios web, establezca Ansync = "verdadero" en su página .aspx donde realiza la solicitud.
<%@ Page Language="C#" Async="true" ... %>
Si no le importa devolver algo al usuario, puede simplemente iniciar un hilo separado o un enfoque rápido y sucio, usar un delegado e invocarlo de forma asincrónica. Si no le importa notificar al usuario cuando finaliza la tarea asíncrona, puede ignorar la devolución de llamada. Intente colocar un punto de interrupción al final del método SomeVeryLongAction () y verá que termina de ejecutarse después de que la página ya se haya publicado:
private delegate void DoStuff(); //delegate for the action
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
//create the delegate
DoStuff myAction = new DoStuff(SomeVeryLongAction);
//invoke it asynchrnously, control passes to next statement
myAction.BeginInvoke(null, null);
Button1.Text = DateTime.Now.ToString();
}
private void SomeVeryLongAction()
{
for (int i = 0; i < 100; i++)
{
//simulation of some VERY long job
System.Threading.Thread.Sleep(100);
}
}
Si obtiene este error al llamar de manera asincrónica al servicio web, asegúrese de agregar el atributo Async = ''true'' tal como lo indica el mensaje de excepción.
parte superior de la página <Idioma de la página = ''VB'' Async = ''true'' AutoEventWireup = ''falso'' CodeFile = ''mynewpage.aspx.vb'' Hereda = ''mynewpage''%>