2010-12-01 6 views
15

Después de leer documentation on AsyncControllers en ASP.NET MVC 2, me pregunto cuál es la mejor manera de implementar una barra de progreso ajax en este escenario. Parece un poco extraño que el tutorial no cubra esto en absoluto.Implementación de una barra de progreso para una tarea de larga ejecución implementada con ASP.NET MVC 2 AsyncController

Supongo que la implementación de una barra de progreso AJAX implica requiere un método de acción adicional que devuelve el estado de la tarea actual. Sin embargo, no estoy seguro sobre la mejor forma de intercambiar información sobre el estado de la tarea entre los hilos de trabajo y ese método de acción.

Mi mejor idea hasta ahora era poner información sobre el progreso actual en el diccionario de sesión junto con una identificación única, y compartir esa identificación con el cliente para que pueda sondear el estado. Pero tal vez hay una manera mucho más fácil que no noté.

¿Cuál es la mejor manera de hacerlo?

Gracias,

Adrian

+0

Esto es como preguntar por qué no obtiene una barra de progreso para una solicitud normal. Debería responderse solo cuando lo piense de esa manera. – nick

+2

@nick: No realmente. Las solicitudes normales no son de larga ejecución. Nadie necesita una barra de progreso para algo que tome un par de segundos como máximo. Sin embargo, si está usando un controlador asíncrono, espera que la solicitud tarde mucho tiempo. Y es entonces cuando necesitas una barra de progreso. ¿Soy el único que encuentra esto obvio? –

+0

Con un controlador Async, significa que una tarea se va a otro lugar, por lo que se convierte en Async y puede permitir que el resto del código continúe la extracción, sin necesidad de que ninguna de esas tareas sea de larga ejecución. Solo significa que puedes mejorar el rendimiento. con una solicitud web: el cliente notará cualquier beneficio.¿Eres el único? ¿Eso dice algo? ¿Qué estás esperando? El servidor para seguir enviando respuestas múltiples para que obtenga una barra de progreso, que negará los beneficios de rendimiento y agregará un comportamiento realmente estúpido. – nick

Respuesta

16

pregunta muy interesante! En realidad, parece que no es una tarea para AsyncController. Los controladores asíncronos están diseñados para operaciones largas de consulta HTTP único en el lado del servidor. Cuando utilice una acción asíncrona, esto solo podría ayudarlo a liberar el hilo de trabajo de ASP.Net durante algunas operaciones de larga ejecución y permitirle atender otras solicitudes mientras se realiza la operación. Pero desde el punto de vista del cliente no importa, es este controlador asíncrono o no. Para el cliente, esta es solo una solicitud HTTP.

Necesita rediseñar esto utilizando algún servicio de consultas de larga ejecución en su aplicación. Aquí es ejemplo de controlador, que podría servir como el flujo de trabajo:

public class LongOperationsController : Controller 
{ 
    public ActionResult StartOperation(OperationData data) 
    { 
     Guid operationId = Guid.NewGuid(); // unique identifier for your operation 
     OperationsService.DoStartOperation(operationId, data); // service starts to perform operation using separate thread 
     return new JsonResult(operationId); // operation id should be sent to client to allow progress monitoring 
    } 

    public ActionResult GetOperationStatus(Guid operationId) 
    { 
     var status = OperationsService.GetStatus(operationId); // this method returns some object, that describes status of operation (e.g. progress, current task etc.) 
     return new JsonResult(status); // returning it to client 
    } 

    public ActionResult GetOperationResult(Guid operationId) 
    { 
     var result = OperationsService.GetOperationResult(operationId); // this should throw exception if operation is not yet completed 
     return new JsonResult(result); 
    } 

    public ActionResult ClearOperation(Guid operationId) 
    { 
     OperationsService.ClearOperationResult(operationId); // we should delete operation result if it was handled by client 
     return true; 
    } 
} 

Y aquí es el código del lado del cliente, que pueden interactuar con este controlador:

var operationId; 
function startOperation(data) { 
    $.post('/LongOperations/StartOperation', data, function(response) { 
     operationId = response; // store operationId 
     startOperationMonitoring(); // start 
    }, 'json'); 
} 

function startOperationMonitoring() { 
    // todo : periodically call updateOperationStatus() to check status at server-side 
} 

function updateOperationStatus() { 
    // todo : get result of GetOperationStatus action from controller 
    // todo : if status is 'running', update progress bar with value from server, if 'completed' - stop operation monitoring and call finishOperation() 
} 

function finishOperation() { 
    // todo : get result of GetOperationResult action from controller and update UI 
    // todo : call ClearOperation action from controller to free resources 
} 

Este es el concepto muy básico, hay algunos artículos perdidos aquí, pero espero que tengas la idea principal. También depende de cómo diseñar los componentes de este sistema, por ejemplo:

  • uso Singleton para OperationsService, o no;
  • dónde y cuánto tiempo debe almacenarse el resultado de la operación (DB? Cache? Session?);
  • ¿Es realmente necesaria para liberar manualmente los recursos y qué hacer cuando cliente detuvo para monitorear la operación (usuario del navegador cerrado), etc.

Mejor suerte!

+0

Hola maza, gracias por tu respuesta detallada. Es exactamente el enfoque que también ideé y que describí en el tercer párrafo de mi PO. Esto funciona bien, pero parece una implementación demasiado tediosa que debería ser parte de casi todos los controladores asíncronos (es decir, una barra de progreso). Hubiera pensado (o al menos esperado) que ASP.NET MVC es mejor que esto y proporciona algún tipo de indicador de progreso para los controladores asíncronos listos para usar. –

+1

Me pregunto, que no está completamente entendido para qué están diseñados los controladores asíncronos. No se trata de la gestión de solicitudes asíncronas, se trata de ejecutar operaciones largas en el servidor. Desafortunadamente HTTP es un protocolo sincrónico y no fue diseñado para tales propósitos desde el principio. –

+0

Además, en mi opinión, no es una buena idea mantener una solicitud en estado abierto y periódicamente sondear el servidor sobre el progreso usando solicitudes paralelas. –

Cuestiones relacionadas