Handling database exceptions in Dynamic Data
This post was prompted from a forum thread in which the user wanted to display database errors in a Dynamic Data page, instead of the default behavior that ends up with an unhandled exception (or an AJAX error with partial rendering).
When using Linq To Sql, this can be done fairly easily in a couple different ways, by wrapping the exception in a ValidationException. To do it globally for a DataContext, you can do something like this:
public override void SubmitChanges(System.Data.Linq.ConflictMode failureMode) {
try {
base.SubmitChanges(failureMode);
}
catch (Exception e) {
throw new ValidationException(null, e);
}
}
And to do it with more granularity, you can use one of the partial methods on the DataContext. e.g.
partial void DeleteCategory(Category instance) {
try {
ExecuteDynamicDelete(instance);
}
catch (Exception e) {
throw new ValidationException(null, e);
}
}
A few notes about this:
- By passing null as the text, it uses the original exception’s text. You very well may want to use a custom error message instead
- Instead of doing it ‘blindly’, you may want to look at the database exception and selectively decide to wrap it or not. If you don’t want to wrap it, just use the ‘throw;’ statement to rethrow it unchanged.
- There is a small issue in the default templates that you need to fix if you want to handle DB exceptions happening during a Delete: in both list.aspx and details.aspx, you’ll find CausesValidation="false" . You need to either get rid of it or set it to true (which is the default).
But now, let’s try to do the same thing with Entity Framework. Unfortunately, ObjectContext doesn’t have as many useful hooks as Linq To Sql’s DataContext (this will change in the next version), so the techniques above are not available.
However, there is a fairly easy workaround that can be used, which involves using a custom derived DynamicValidator control. Here are the steps to do this (full sample attached at the end of this post).
First, let’s create the derived DynamicValidator, as follows. I’ll let the comments speak for themselves:
/// <summary>
/// By default, Dynamic Data doesn't blindly display all exceptions in the page,
/// as some database exceptions may contain sensitive info. Instead, it only displays
/// ValidationExceptions.
/// However, in some cases you need to display other exceptions as well. This code
/// shows how to achieve this.
/// </summary>
public class MyDynamicValidator : DynamicValidator {
protected override void ValidateException(Exception exception) {
// If it's not already an exception that DynamicValidator looks at
if (!(exception is IDynamicValidatorException) && !(exception is ValidationException)) {
// Find the most inner exception
while (exception.InnerException != null) {
exception = exception.InnerException;
}
// Wrap it in a ValidationException so the base code doesn't ignore it
if (ExceptionShouldBeDisplayedInPage(exception)) {
exception = new ValidationException(null, exception);
}
}
// Call the base on the (possibly) modified exception
base.ValidateException(exception);
}
private bool ExceptionShouldBeDisplayedInPage(Exception e) {
// This is where you may want to add logic that looks at the exception and
// decides whether it should indeed be shown in the page
return true;
}
}
Then you need to make all the pages use it. The simplest way to do it is via a little know but powerful feature: tag remapping. Here is what you need to have in web.config:
<pages>
<tagMapping>
<add tagType="System.Web.DynamicData.DynamicValidator" mappedTagType="MyDynamicValidator"/>
</tagMapping>
</pages>
And then you also need to do the same as the 3rd bullet point above: get rid of CausesValidation="false" in the pages.
And that’s all! You should now see the error messages directly in the page.
DynamicDataEntityDbErrorHandling.zip
Comments
Anonymous
December 11, 2008
PingBack from http://www.alvinashcraft.com/2008/12/12/dew-drop-december-12-2008/Anonymous
December 12, 2008
(Sniff, Sniff) Beautiful! Just beautiful! This is the final link in the chain for me to use Dynamic Data in all my future projects. I was playing with it to try to get it to do exactly this and I just missed those partial methods. I've already switched back to an older technology and I can't switch back again, but rest assured my next project will be in DD. Thanks a lot David.Anonymous
February 18, 2009
Please post corrections/new submissions to the Dynamic Data Forum . Put FAQ Submission/Correction inAnonymous
September 26, 2010
Hi David, is there a similar method for Entity Framework please :) SteveAnonymous
December 03, 2011
Hi, David. When i am using this method on SQL Server 2000 i get full(correct error - which accordingly error that i get when for example delete row from Enterprice Manager) error from my MS SQL 2000 Server, but if i am using on SQL Server 20008 R2 i get not full and incorrect error(not the same as i get when i for example delete row over Server Managment Studio).Anonymous
December 03, 2011
The other words for example if i try to delete record, that take a part in a relationships, from my table then i get exception in my Dynamic Data site(EF): Object reference not set to an instance of an object! But if i do the same in Managment Studio then i get full correct exception: The DELETE statement conflicted with the REFERENCE constraint "R_97". The conflict occurred in database "IT-Audit", table "dbo.TeamViewerId", column 'PC_Id'. The statement has been terminated. Recently i migrate from SQL 2000 Server to SQL 2008 Server R2.Anonymous
December 08, 2011
Great, thank youAnonymous
September 26, 2012
Great post! Thank you!Anonymous
November 27, 2013
Great, thank you! Save my day with MyDynamicValidator!