Hi Guys,
I recently upgraded the my project to 3.5.2 but some old behaviors seem changed.
I am using the following code to register my services,
builder.RegisterType<MemoryCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").SingleInstance();
builder.RegisterType<PerRequestCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_per_request").InstancePerLifetimeScope();
builder.RegisterType<GenericAttributeService>().As<IGenericAttributeService>().InstancePerLifetimeScope();
Later on, the ICacheManager is resolved in the constructor.
public GenericAttributeService(ICacheManager cacheManager,
IRepository<GenericAttribute> genericAttributeRepository,
IEventPublisher eventPublisher)
{
this._cacheManager = cacheManager;
this._genericAttributeRepository = genericAttributeRepository;
this._eventPublisher = eventPublisher;
}
Before I upgraded the Autofac, the implementation of PerRequestCacheManager is resolved, but now MemoryCacheManager is resolved. So I have to change the code to following and then it works as expectation.
builder.RegisterType<MemoryCacheManager>().Named<ICacheManager>("nop_cache_static").SingleInstance();
builder.RegisterType<PerRequestCacheManager>().As<ICacheManager>().InstancePerLifetimeScope();
1. Anyone knows if the behavior that ‘last registered is resolved first’ is changed?
2. How can I debug the code of Autofac to understand the changes? Where to download the symbol files (*.pdb) and corresponding source code.
Thanks,
Sean
Thanks for your advice, Travis.
I will provide more detailed information in this thread later. Will try to debug first then see if I can figure out the reason.
Hi Travis,
I still didn’t find the cause, since symbols of v3.5.2 are not available on symbolsource yet.
https://www.symbolsource.org/Public/Metadata/NuGet/Project/Autofac
for resolving services, we use the following strategy in the MVC projects.
public ILifetimeScope Scope()
{
try
{
if (HttpContext.Current != null)
return AutofacDependencyResolver.Current.RequestLifetimeScope;
//when such lifetime scope is returned, you should be sure that it'll be disposed once used (e.g. in schedule tasks)
return Container.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
}
catch (Exception)
{
//we can get an exception here if RequestLifetimeScope is already disposed
//for example, requested in or after "Application_EndRequest" handler
//but note that usually it should never happen
//when such lifetime scope is returned, you should be sure that it'll be disposed once used (e.g. in schedule tasks)
return Container.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
}
}
Thanks,
Xiao-Lu
From: Xiaolu Liu [mailto:littl...@hotmail.com]
Sent: Friday, October 17, 2014 1:28 PM
To: 'Travis Illig'; aut...@googlegroups.com
Subject: RE: Default resolving behavior of multiple implementations (v3.5.2)
Thanks for your advice, Travis.
I will provide more detailed information in this thread later. Will try to debug first then see if I can figure out the reason.
From: Travis Illig [mailto:travis...@gmail.com]
Sent: Friday, October 17, 2014 12:55 PM
To: aut...@googlegroups.com
Cc: Xiao-Lu Liu (Inspur Worldwide Services Ltd)
Subject: Re: Default resolving behavior of multiple implementations (v3.5.2)
The last-in-wins behavior has not changed. It might be good to show how you're doing the resolve call. Something you'll want to be careful of is that "SingleInstance" and "InstancePerLifetimeScope" become effectively the same if you're resolving directly from the root container.
I can now resolve all symbols and code for 3.5.2. I guess something wrong or changed within the following method in ExternalRegistrySource.cs. The sequence of _implements member in ServiceRegistrationInfo is unexpectedly modified. It only happens when I registered an implementation was both KeyedService and TypedService.
/// <summary>
/// Retrieve registrations for an unregistered service, to be used
/// by the container.
/// </summary>
/// <param name="service">The service that was requested.</param>
/// <param name="registrationAccessor">A function that will return existing registrations for a service.</param>
/// <returns>Registrations providing the service.</returns>
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
var seenRegistrations = new HashSet<IComponentRegistration>();
var seenServices = new HashSet<Service>();
var lastRunServices = new List<Service> { service };
while (lastRunServices.Any())
{
var nextService = lastRunServices.First();
lastRunServices.Remove(nextService);
seenServices.Add(nextService);
foreach (var registration in _registry.RegistrationsFor(nextService).Where(r => !r.IsAdapting()))
{
if (seenRegistrations.Contains(registration))
continue;
seenRegistrations.Add(registration);
lastRunServices.AddRange(registration.Services.Where(s => !seenServices.Contains(s)));
var r = registration;
yield return RegistrationBuilder.ForDelegate(r.Activator.LimitType, (c, p) => c.ResolveComponent(r, p))
.Targeting(r)
.As(r.Services.ToArray())
.ExternallyOwned()
.CreateRegistration();
The last-in-wins behavior has not changed. It might be good to show how you're doing the resolve call. Something you'll want to be careful of is that "SingleInstance" and "InstancePerLifetimeScope" become effectively the same if you're resolving directly from the root container.