U4-9109 - Automapper upgrade seems to break things

Created by Sebastiaan Janssen 24 Oct 2016, 12:30:09 Updated by Sebastiaan Janssen 27 Oct 2016, 16:39:41

Relates to: U4-8984

Need to investigate if we can fix with more assembly redirects or if we need to revert the upgrade.

Comments

Sebastiaan Janssen 24 Oct 2016, 12:30:35

See comments in http://issues.umbraco.org/issue/U4-8984


Jonathan Roberts 24 Oct 2016, 12:38:59

I hope you dont revert the upgrade as my client has just upgraded to 7.5.4. If you revert the upgrade is it possible to downgrade a site?


Jeroen Breuer 24 Oct 2016, 12:42:23

Bug from previous issue. During ApplicationStarting we call AutofacConfig.Init();. In there we do Mapper.Configuration.ConstructServicesUsing(container.Resolve);. This seems to cause the issue.

An error occured

Mapping types: Content -> UserBasic Umbraco.Core.Models.Content -> Umbraco.Web.Models.ContentEditing.UserBasic

Destination path: ContentItemDisplay.Owner.Owner

Source value: Umbraco.Core.Models.Content

EXCEPTION DETAILS

AutoMapper.AutoMapperMappingException:

Mapping types: Content -> UserBasic Umbraco.Core.Models.Content -> Umbraco.Web.Models.ContentEditing.UserBasic

Destination path: ContentItemDisplay.Owner.Owner

Source value: Umbraco.Core.Models.Content STACKTRACE

at Umbraco.Web.Editors.ContentController.GetById(Int32 id) at lambda_method(Closure , Object , Object[] ) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.b__9(Object instance, Object[] methodParameters) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Controllers.ApiControllerActionInvoker.d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.ActionFilterAttribute.d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Web.Http.Filters.ActionFilterAttribute.d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.ActionFilterAttribute.d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.ActionFilterAttribute.d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Web.Http.Filters.ActionFilterAttribute.d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.ActionFilterAttribute.d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.ActionFilterAttribute.d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Web.Http.Filters.ActionFilterAttribute.d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.ActionFilterAttribute.d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.ActionFilterAttribute.d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Web.Http.Filters.ActionFilterAttribute.d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.ActionFilterAttribute.d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.ActionFilterAttribute.d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Web.Http.Filters.ActionFilterAttribute.d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.ActionFilterAttribute.d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.ActionFilterAttribute.d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Web.Http.Filters.ActionFilterAttribute.d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.ActionFilterAttribute.d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Controllers.ActionFilterResult.d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.AuthorizationFilterAttribute.d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.AuthorizationFilterAttribute.d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Filters.AuthorizationFilterAttribute.d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext() INNER EXCEPTION

Autofac.Core.Registration.ComponentNotRegisteredException: The requested service 'Umbraco.Web.Models.Mapping.OwnerResolver1[[Umbraco.Core.Models.IContent, Umbraco.Core, Version=1.0.6136.27241, Culture=neutral, PublicKeyToken=null]]' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency. at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable1 parameters) at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType) at AutoMapper.MappingExpression2.<>c__DisplayClass3a1.b__39(ResolutionContext context) in c:\dev\AutoMapper\src\AutoMapper\Internal\MappingExpression.cs:line 554 at AutoMapper.DeferredInstantiatedResolver.Resolve(ResolutionResult source) in c:\dev\AutoMapper\src\AutoMapper\Internal\DeferredInstantiatedResolver.cs:line 16 at System.Linq.Enumerable.Aggregate[TSource,TAccumulate](IEnumerable1 source, TAccumulate seed, Func3 func) at AutoMapper.Mappers.TypeMapObjectMapperRegistry.PropertyMapMappingStrategy.MapPropertyValue(ResolutionContext context, IMappingEngineRunner mapper, Object mappedObject, PropertyMap propertyMap) in c:\dev\AutoMapper\src\AutoMapper\Mappers\TypeMapObjectMapperRegistry.cs:line 116


Jonathan Roberts 24 Oct 2016, 12:47:17

This fixed the issue for me:

  <dependentAssembly>
    <assemblyIdentity name="AutoMapper" publicKeyToken="be96cd2c38ef1005" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-3.3.1.0" newVersion="3.3.1.0" />
  </dependentAssembly>


Jeroen Breuer 24 Oct 2016, 13:30:47

Dave did a little research. Umbraco registers some mappers itself:

https://github.com/umbraco/Umbraco-CMS/blob/5397f2c53acbdeb0805e1fe39fda938f571d295a/src/Umbraco.Web/Models/Mapping/CreatorResolver.cs

https://github.com/umbraco/Umbraco-CMS/blob/5397f2c53acbdeb0805e1fe39fda938f571d295a/src/Umbraco.Web/Models/Mapping/OwnerResolver.cs

https://github.com/umbraco/Umbraco-CMS/blob/5397f2c53acbdeb0805e1fe39fda938f571d295a/src/Umbraco.Core/Models/Mapping/MapperConfiguration.cs

https://github.com/umbraco/Umbraco-CMS/blob/5397f2c53acbdeb0805e1fe39fda938f571d295a/src/Umbraco.Core/CoreBootManager.cs#L127

Somehow if we do Mapper.Configuration.ConstructServicesUsing(container.Resolve); afterwards that doesn't work anymore. It did work on Umbraco 7.4.3 with Automapper 3.0.

I hope this can be fixed soon. We upgraded to Umbraco 7.5.4 and now need to wait for a fix before we can release it.


Jeroen Breuer 24 Oct 2016, 14:33:43

It might be better to downgrade to AutoMapper back to 3.0 for now. Since this issue was introduced in a patch release Umbraco Cloud (UaaS) already upgraded all websites to this version which means some live website could be broken right now. I don't think this is something which should be done in a patch release. Originally the AutoMapper upgrade was even postponed until Umbraco 8: http://issues.umbraco.org/issue/U4-6923


Sebastiaan Janssen 24 Oct 2016, 16:19:43

FYI: All live sites on UaaS are working just fine, which is why this is surprising. Will look into it tomorrow.


Dave Woestenborghs 24 Oct 2016, 17:54:29

@sebastiaan I installed Archetype on my upgraded Uaas trial (live environment). Archetype is not working in the backend.

Edit: looking through the Kudu console I also don't see the assemblybinding defined in the web.config


Sebastiaan Janssen 24 Oct 2016, 18:14:01

@dave what happens when you add the assembly redirect?


Dave Woestenborghs 24 Oct 2016, 18:17:58

That fixes it. But shouldn't that be handled by the upgrade. But in one of our projects we see also issues with automapper in combination with Autofac


Sebastiaan Janssen 24 Oct 2016, 18:21:41

If it's on UaaS then yes, we are fixing a few sites that didn't get the config updated. I'm investigating the autofac issue tomorrow.


Dave Woestenborghs 24 Oct 2016, 18:29:01

Okay.. Why is this upgrade done in a patch release. I consider this as a breaking change. I know we had the same issue in one of the 7.3 beta's and there it was rolled back because of the breaking changes.


Jeroen Breuer 25 Oct 2016, 07:04:12

I am also still wondering why this was done in a patch release. I've upgraded several websites from Umbraco 7.4.3 to 7.5.3 and the upgrade went flawless. I've done 1 upgrade from 7.4.3 to 7.5.4 and instead I've wasted many precious hours on AutoMapper issues. I think I'm just going to rollback the database and branch to Umbraco 7.4.3 and will only upgrade to 7.5.3 because I no longer trust Umbraco 7.5.4 and that's too bad because it had some nice bugfixes.


Sebastiaan Janssen 25 Oct 2016, 09:03:29

As for why we upgraded; We've been wanting to do this upgrade for a while: there's hundreds of bug fixes and performance improvements between the old 3.0.0 and the newer 3.3.1 version. However, it always seemed impossible until we stumbled upon a way to resolve this dependency in code - see https://github.com/umbraco/Umbraco-CMS/pull/1483/files#diff-915962d064524ee323d0884cbc9b9ab1R52

To re-iterate: we've first tested this upgrade first on about 10 sites that we knew were using Automapper (apart from Umbraco using it internally, but actually code built against the Automapper assemblies), including Our and our Training materials, then we upgraded a few hundred sites on our UaaS test environment, then on all sites currently running UaaS and we found that we missed updating the web.config for some sites, so we're currently adding the assembly redirect for those sites we missed. From NuGet/Our download we also see 1500 other sites have either downloaded or upgraded their site to 7.5.4. So until you raised this issue we were pretty confident that it didn't break anything. :-)

Of course super annoying and unfortunate that the two of you ran into this issue! Which is why we're investigating and trying to figure it out, which we could use a little help with: @dawoe @jbreuer any chance you can send a solution that's failing over? Doesn't have to be a "real" site, maybe you have a demo site that's not working any more either? I am trying to reproduce this but I'm not sure how yet.

That said, I'm pretty confident we can find a workaround for the problem, we're working on it.


Dave Woestenborghs 25 Oct 2016, 09:12:09

@sebastiaan I think some issue can occur when doing a nuget update and you choose not to overwrite your web.config ? Is possible that the assemblybinding doens't get updated then ?

I haven't got time to look in to the autofac issue. I only happens when you use depedency injection on Automapper typeconverters and valueresolvers. Will see if I can have a quick solution ready to replicate.

Dave


Sebastiaan Janssen 25 Oct 2016, 10:07:23

@dawoe No there's a config transform that adds the assembly redirect which should always run even if you don't overwrite files.


Dave Woestenborghs 25 Oct 2016, 11:53:08

Hi Sebastiaan,

I found our issue.

We had this in our Autofac setup to be able to use DI in automapper ValueResolvers and ITypeConverters.

// Create container var container = builder.Build();

        // Setup AutoMapper to use DI
        Mapper.Configuration.ConstructServicesUsing(container.Resolve);

        // Setup MVC dependency resolver to user Autofac
        var resolver = new AutofacWebApiDependencyResolver(container);
        GlobalConfiguration.Configuration.DependencyResolver = resolver;
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

To get it working with the new version of automapper we needed to change this line to : Mapper.Configuration.ConstructServicesUsing(container.ResolveOptional);

Now backend and front end work again.

Dave


Jeroen Breuer 27 Oct 2016, 11:10:31

Another issue which is probably related to AutoMapper: https://our.umbraco.org/forum/using-umbraco-and-getting-started/80936-trees-not-working-after-upgrade-to-754


Sebastiaan Janssen 27 Oct 2016, 16:38:07

Alright, we've been able to find the error regarding Umbraco.Core.Models.Content -Umbraco.Web.Models.ContentEditing.UserBasic and it's been resolved in this commit: https://github.com/umbraco/Umbraco-CMS/commit/ba0ef3676d4b6c27046d7ed4906f471070966dca

So you could go back to using container.Resolve if necessary.


Sebastiaan Janssen 27 Oct 2016, 16:39:41

If there's any other errors besides the compile error in "Note2" in U4-8984 then please create a new issue for it!


Priority: Normal

Type: Bug

State: Fixed

Assignee:

Difficulty: Normal

Category:

Backwards Compatible: True

Fix Submitted:

Affected versions: 7.5.4

Due in version: 7.5.5

Sprint: Sprint 45

Story Points: 1

Cycle: