Una respuesta breve es utilizar métodos de delegado (anónimos) con código de manejo común cuando se invoca al delegado.
Antecedentes: Si ha orientado los puntos débiles, o tiene algún código de manejo de errores repetitivo es necesario aplicar universalmente a una clase particular de problema, y que no desea escribir el mismo para try..catch cada ubicación de invocación (como actualizar un control específico en cada página, etc.).
Estudio de caso: Un punto importante es la creación de formularios web y el guardado de datos en la base de datos. Tenemos un control que muestra el estado guardado al usuario, y queríamos tener un código de manejo de errores común así como una visualización común sin copiar-pegar-reutilizar en cada página. Además, cada página hacía su propia cosa a su manera, por lo que la única parte realmente común del código era el manejo y visualización de errores.
Ahora, antes de ser cerrado, esto no reemplaza una capa de acceso a datos y un código de acceso a datos. Todavía se supone que existe, una buena separación de n niveles, etc. Este código es específico de la capa UI para permitirnos escribir códigos de UI limpios y no repetirnos. Creemos firmemente en no anular las excepciones, pero ciertas excepciones no deberían obligar al usuario a obtener una página de error genérica y perder su trabajo. Habrá tiempos de espera de SQL, servidores bajan, bloqueos, etc.
Una solución: La forma en que lo hicimos fue pasar un delegado anónimo a un método en un control personalizado y esencialmente inyectar el bloque try usando delegados anónimos .
// normal form code.
private void Save()
{
// you can do stuff before and after. normal scoping rules apply
saveControl.InvokeSave(
delegate
{
// everywhere the save control is used, this code is different
// but the class of errors and the stage we are catching them at
// is the same
DataContext.SomeStoredProcedure();
DataContext.SomeOtherStoredProcedure();
DataContext.SubmitChanges();
});
}
El SaveControl en sí tiene un método similar:
public delegate void SaveControlDelegate();
public void InvokeSave(SaveControlDelegate saveControlDelegate)
{
// I've changed the code from our code.
// You'll have to make up your own logic.
// this just gives an idea of common handling.
retryButton.Visible = false;
try
{
saveControlDelegate.Invoke();
}
catch (SqlTimeoutException ex)
{
// perform other logic here.
statusLabel.Text = "The server took too long to respond.";
retryButton.Visible = true;
LogSqlTimeoutOnSave(ex);
}
// catch other exceptions as necessary. i.e.
// detect deadlocks
catch (Exception ex)
{
statusLabel.Text = "An unknown Error occurred";
LogGenericExceptionOnSave(ex);
}
SetSavedStatus();
}
- Hay otras maneras de lograr esto (por ejemplo clase base común, intefaces), pero en nuestro caso esto tenía el mejor ajuste.
- Esto no es un reemplazo de una gran herramienta como Elmah para registrar todas las excepciones no controladas. Este es un enfoque específico para manejar ciertas excepciones de manera estándar.
¿No es eso el tratamiento de los síntomas y no la causa? es decir, ¿no debería estar mirando la causa de los tiempos de espera de SQL ejecutando un rastreo del Analizador de SQL en el servidor de la base de datos? –
Creo que debes aclarar lo que quieres decir con "catch": como en try ...detecte dónde puede manejar la excepción, o si simplemente desea que se le informe una excepción no controlada, y registre dónde/cuándo (por ejemplo, ELMAH) –