Skip to content

Commit

Permalink
Better execution exceptions. still need to wrap resolvers, formatters…
Browse files Browse the repository at this point in the history
… and type converters
  • Loading branch information
jbogard committed Dec 11, 2011
1 parent cf9d9a7 commit 73e673c
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 73 deletions.
91 changes: 66 additions & 25 deletions src/AutoMapper/AutoMapperMappingException.cs
@@ -1,6 +1,9 @@
using System;
using System.Runtime.Serialization;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

namespace AutoMapper
{
#if !SILVERLIGHT
Expand Down Expand Up @@ -65,33 +68,71 @@ public override string Message
get
{
string message = null;
if (Context != null)
{
message = string.Format("Trying to map {0} to {1}.", Context.SourceType.FullName, Context.DestinationType.FullName);
TypeMap contextTypeMap = Context.GetContextTypeMap();
if (contextTypeMap != null)
{
message += string.Format("\nUsing mapping configuration for {0} to {1}", contextTypeMap.SourceType, contextTypeMap.DestinationType);
}
if (Context.TypeMap != null && Context.TypeMap != contextTypeMap)
{
message += string.Format("\nUsing property mapping configuration for {0} to {1}", Context.TypeMap.SourceType, Context.TypeMap.DestinationType);
}
if (Context.PropertyMap != null)
{
message += string.Format("\nDestination property: {0}", Context.PropertyMap.DestinationProperty.Name);
}
if (Context != null)
{
message = "\n\nMapping types:";
message += Environment.NewLine + string.Format("{0} -> {1}", Context.SourceType.Name, Context.DestinationType.Name);
message += Environment.NewLine + string.Format("{0} -> {1}", Context.SourceType.FullName, Context.DestinationType.FullName);

var destPath = GetDestPath(Context);
message += "\n\nDestination path:\n" + destPath;

message += "\n\nSource value:\n" + (Context.SourceValue ?? "(null)");

return message;
}
if (_message != null)
{
message = (message == null ? null : message + "\n") + _message;
}
if (base.Message != null)
{
message = (message == null ? null : message + "\n") + base.Message;
}
message = _message;
}

message = (message == null ? null : message + "\n") + base.Message;

return message;
}
}

private string GetDestPath(ResolutionContext context)
{
var allContexts = GetContexts(context).Reverse();

var builder = new StringBuilder(allContexts.First().DestinationType.Name);

foreach (var ctxt in allContexts)
{
if (!string.IsNullOrEmpty(ctxt.MemberName))
{
builder.Append(".");
builder.Append(ctxt.MemberName);
}
if (ctxt.ArrayIndex != null)
{
builder.AppendFormat("[{0}]", ctxt.ArrayIndex);
}
}
return builder.ToString();
}

private static IEnumerable<ResolutionContext> GetContexts(ResolutionContext context)
{
while (context.Parent != null)
{
yield return context;

context = context.Parent;
}
yield return context;
}

public override string StackTrace
{
get
{
return string.Join(Environment.NewLine,
base.StackTrace
.Split(new[] {Environment.NewLine}, StringSplitOptions.None)
.Where(str => !str.TrimStart().StartsWith("at AutoMapper.")));
}
}
}
}
6 changes: 5 additions & 1 deletion src/AutoMapper/Mappers/DataReaderMapper.cs
Expand Up @@ -161,7 +161,11 @@ private static void MapPropertyValues(ResolutionContext context, IMappingEngineR
if (propertyMap.CanBeSet)
propertyMap.DestinationProperty.SetValue(mappedObject, propertyValueToAssign);
}
catch (Exception ex)
catch (AutoMapperMappingException)
{
throw;
}
catch (Exception ex)
{
throw new AutoMapperMappingException(newContext, ex);
}
Expand Down
12 changes: 10 additions & 2 deletions src/AutoMapper/Mappers/TypeMapObjectMapperRegistry.cs
Expand Up @@ -95,8 +95,12 @@ private void MapPropertyValue(ResolutionContext context, IMappingEngineRunner ma
try
{
result = propertyMap.ResolveValue(context);
}
catch (Exception ex)
}
catch (AutoMapperMappingException)
{
throw;
}
catch (Exception ex)
{
var errorContext = CreateErrorContext(context, propertyMap, destinationValue);
throw new AutoMapperMappingException(errorContext, ex);
Expand Down Expand Up @@ -128,6 +132,10 @@ private void MapPropertyValue(ResolutionContext context, IMappingEngineRunner ma

AssignValue(propertyMap, mappedObject, propertyValueToAssign);
}
catch (AutoMapperMappingException)
{
throw;
}
catch (Exception ex)
{
throw new AutoMapperMappingException(newContext, ex);
Expand Down
6 changes: 5 additions & 1 deletion src/AutoMapper/MappingEngine.cs
Expand Up @@ -307,7 +307,11 @@ object IMappingEngineRunner.Map(ResolutionContext context)

return mapperToUse.Map(context, this);
}
catch (Exception ex)
catch (AutoMapperMappingException)
{
throw;
}
catch (Exception ex)
{
throw new AutoMapperMappingException(context, ex);
}
Expand Down
193 changes: 149 additions & 44 deletions src/UnitTests/MappingExceptions.cs
Expand Up @@ -6,48 +6,153 @@ namespace AutoMapper.UnitTests
{
namespace MappingExceptions
{
public class When_encountering_a_member_mapping_problem_during_mapping : NonValidatingSpecBase
{
public class Source
{
public string Value { get; set; }
}

public class Dest
{
public int Value { get; set;}
}

protected override void Establish_context()
{
Mapper.CreateMap<Source, Dest>();
}

[Test]
public void Should_provide_a_contextual_exception()
{
var source = new Source {Value = "adsf"};
typeof(AutoMapperMappingException).ShouldBeThrownBy(() => Mapper.Map<Source, Dest>(source));
}

[Test]
public void Should_have_contextual_mapping_information()
{
var source = new Source { Value = "adsf" };
AutoMapperMappingException thrown = null;
try
{
Mapper.Map<Source, Dest>(source);
}
catch (AutoMapperMappingException ex)
{
thrown = ex;
}
thrown.ShouldNotBeNull();
thrown.InnerException.ShouldNotBeNull();
thrown.InnerException.ShouldBeType<AutoMapperMappingException>();
((AutoMapperMappingException) thrown.InnerException).Context.PropertyMap.ShouldNotBeNull();
}
}
}
public class When_encountering_a_member_mapping_problem_during_mapping : NonValidatingSpecBase
{
public class Source
{
public string Value { get; set; }
}

public class Dest
{
public int Value { get; set; }
}

protected override void Establish_context()
{
Mapper.CreateMap<Source, Dest>();
}

[Test]
public void Should_provide_a_contextual_exception()
{
var source = new Source { Value = "adsf" };
typeof(AutoMapperMappingException).ShouldBeThrownBy(() => Mapper.Map<Source, Dest>(source));
}

[Test]
public void Should_have_contextual_mapping_information()
{
var source = new Source { Value = "adsf" };
AutoMapperMappingException thrown = null;
try
{
Mapper.Map<Source, Dest>(source);
}
catch (AutoMapperMappingException ex)
{
thrown = ex;
}
thrown.ShouldNotBeNull();
}
}

[Explicit]
public class When_encountering_a_complex_deep_error : NonValidatingSpecBase
{
public class Source
{
public SubSource Sub { get; set; }
}

public class SubSource
{
public SubSubSource OtherSub { get; set; }
}

public class SubSubSource
{
public SubSubSubSource[] Values { get; set; }
}

public class SubSubSubSource
{
public int Foo { get; set; }
}

public class Dest
{
public SubDest Sub { get; set; }
}

public class SubDest
{
public SubSubDest OtherSub { get; set; }
}

public class SubSubDest
{
public SubSubSubDest[] Values { get; set; }
}

public class SubSubSubDest
{
public int Foo { get; set; }
}

protected override void Establish_context()
{
Mapper.CreateMap<Source, Dest>();
Mapper.CreateMap<SubSource, SubDest>();
Mapper.CreateMap<SubSubSource, SubSubDest>();
Mapper.CreateMap<SubSubSubSource, SubSubSubDest>()
.ForMember(dest => dest.Foo, opt => opt.ResolveUsing<MyCoolResolver>());
}

public class MyCoolResolver : ValueResolver<SubSubSubSource, int>
{
private static int Count = 0;

protected override int ResolveCore(SubSubSubSource source)
{
Count++;
if (Count > 3)
throw new Exception("Oh noes");
return Count;
}
}

[Test]
public void Should_provide_a_contextual_exception()
{
var source = new Source
{
Sub = new SubSource
{
OtherSub = new SubSubSource
{
Values = new[]
{
new SubSubSubSource
{
Foo = 5,
},
new SubSubSubSource
{
Foo = 5,
},
new SubSubSubSource
{
Foo = 5,
},
new SubSubSubSource
{
Foo = 5,
},
new SubSubSubSource
{
Foo = 5,
},
new SubSubSubSource
{
Foo = 5,
},
},
}
}
};
Mapper.Map<Source, Dest>(source);
}
}
}
}

0 comments on commit 73e673c

Please sign in to comment.