Can Unity Be Made to Not Throw Synchronizationlockexception All the Time

Can Unity be made to not throw SynchronizationLockException all the time?

I'm sure there's a lot of ways code could call SynchronizedLifetimeManager, or a descendant like ContainerControlledLifetimeManager, but there were two scenarios in particular that were causing me problems.

The first was my own fault - I was using constructor injection to supply a reference to the container, and in that constructor I was also adding the new instance of the class to the container for future use. This backwards approach had the effect of changing the lifetime manager from Transient to ContainerControlled so that the object Unity called GetValue on was not the same object it called SetValue on. The lesson learned is don't do anything during build-up that could change an object's lifetime manager.

The second scenario was that every time RegisterInstance is called, UnityDefaultBehaviorExtension calls SetValue without calling GetValue first. Luckily, Unity is extensible enough that, with enough bloody-mindedness, you can work around the problem.

Start with a new behavior extension like this:

/// <summary>
/// Replaces <see cref="UnityDefaultBehaviorExtension"/> to eliminate
/// <see cref="SynchronizationLockException"/> exceptions that would otherwise occur
/// when using <c>RegisterInstance</c>.
/// </summary>
public class UnitySafeBehaviorExtension : UnityDefaultBehaviorExtension
{
/// <summary>
/// Adds this extension's behavior to the container.
/// </summary>
protected override void Initialize()
{
Context.RegisteringInstance += PreRegisteringInstance;

base.Initialize();
}

/// <summary>
/// Handles the <see cref="ExtensionContext.RegisteringInstance"/> event by
/// ensuring that, if the lifetime manager is a
/// <see cref="SynchronizedLifetimeManager"/> that its
/// <see cref="SynchronizedLifetimeManager.GetValue"/> method has been called.
/// </summary>
/// <param name="sender">The object responsible for raising the event.</param>
/// <param name="e">A <see cref="RegisterInstanceEventArgs"/> containing the
/// event's data.</param>
private void PreRegisteringInstance(object sender, RegisterInstanceEventArgs e)
{
if (e.LifetimeManager is SynchronizedLifetimeManager)
{
e.LifetimeManager.GetValue();
}
}
}

Then you need a way to replace the default behavior. Unity doesn't have a method to remove a specific extension, so you have to remove everything and put the other extensions back in again:

public static IUnityContainer InstallCoreExtensions(this IUnityContainer container)
{
container.RemoveAllExtensions();
container.AddExtension(new UnityClearBuildPlanStrategies());
container.AddExtension(new UnitySafeBehaviorExtension());

#pragma warning disable 612,618 // Marked as obsolete, but Unity still uses it internally.
container.AddExtension(new InjectedMembers());
#pragma warning restore 612,618

container.AddExtension(new UnityDefaultStrategiesExtension());

return container;
}

Notice that UnityClearBuildPlanStrategies? RemoveAllExtensions clears out all of the container's internal lists of policies and strategies except for one, so I had to use another extension to avoid inserting duplicates when I restored the default extensions:

/// <summary>
/// Implements a <see cref="UnityContainerExtension"/> that clears the list of
/// build plan strategies held by the container.
/// </summary>
public class UnityClearBuildPlanStrategies : UnityContainerExtension
{
protected override void Initialize()
{
Context.BuildPlanStrategies.Clear();
}
}

Now you can safely use RegisterInstance without fear of being driven to the brink of madness. Just to be sure, here's some tests:

[TestClass]
public class UnitySafeBehaviorExtensionTests : ITest
{
private IUnityContainer Container;
private List<Exception> FirstChanceExceptions;

[TestInitialize]
public void TestInitialize()
{
Container = new UnityContainer();
FirstChanceExceptions = new List<Exception>();
AppDomain.CurrentDomain.FirstChanceException += FirstChanceExceptionRaised;
}

[TestCleanup]
public void TestCleanup()
{
AppDomain.CurrentDomain.FirstChanceException -= FirstChanceExceptionRaised;
}

private void FirstChanceExceptionRaised(object sender, FirstChanceExceptionEventArgs e)
{
FirstChanceExceptions.Add(e.Exception);
}

/// <summary>
/// Tests that the default behavior of <c>UnityContainer</c> leads to a <c>SynchronizationLockException</c>
/// being throw on <c>RegisterInstance</c>.
/// </summary>
[TestMethod]
public void UnityDefaultBehaviorRaisesExceptionOnRegisterInstance()
{
Container.RegisterInstance<ITest>(this);

Assert.AreEqual(1, FirstChanceExceptions.Count);
Assert.IsInstanceOfType(FirstChanceExceptions[0], typeof(SynchronizationLockException));
}

/// <summary>
/// Tests that <c>UnitySafeBehaviorExtension</c> protects against <c>SynchronizationLockException</c>s being
/// thrown during calls to <c>RegisterInstance</c>.
/// </summary>
[TestMethod]
public void SafeBehaviorPreventsExceptionOnRegisterInstance()
{
Container.RemoveAllExtensions();
Container.AddExtension(new UnitySafeBehaviorExtension());
Container.AddExtension(new InjectedMembers());
Container.AddExtension(new UnityDefaultStrategiesExtension());

Container.RegisterInstance<ITest>(this);

Assert.AreEqual(0, FirstChanceExceptions.Count);
}
}

public interface ITest { }

SynchronizationLockException + Logging

I found a "solution".
Consider to this post there is an issue within the Unity part of the enterprise lib.
Since every component is build up using unity you will alsways get those exceptions. So the "solution" is to disable the breaking for SynchronizationLockException; this is done via the exception settings menu where you usually turn the breaking for handled exceptions on.

Unity 2.0. How to throw ResolutionFailedException

Actualy this exception is not supposed to be called by developer, anyway you can call it following way

    throw new ResolutionFailedException(
typeof (IConcreteService),
"IConcreteService",
null,
new BuilderContext(null, null, null, null, NamedTypeBuildKey.Make<IConcreteService>("nameOrNullIfResolvedNotNamedInstance"), null)
);

Prism 2 for Silverlight with Unity - 'System.Threading.SynchronizationLockException'

The way how to turn it off is next:

  • In VS IDE go to Debug\Exceptions menu (or press Ctrl+Alt+E)
  • Uncheck the Thrwon check box beside the "Common Language Runtime exceptions"

As for why it is happening, I guess you already got that :)

SynchronizationLockException using mutexes

You need to assign an value (new object();) to monitorKey on creation (since it's static and readonly).

After that, you must acquire the lock before waiting on it:

while (condition)
{
lock(monitorKey)
{
Monitor.Wait(monitorKey); // exception is thrown
}
}

Or you could reverse the order and have the lock surround the while to avoid unnecessary lock -> exit cycles.

Resolve instance using named registration does not throw Exception

I'm with you that this is unexpected behavior. I think the problem origins from the fact that you are trying to resolve an instance of a concrete class (in your case object). Looks like Unity will always try to resolve that instance. As long as it can do that it will ignore named mappings.

I experimented with a base class (ViewBase) which the container will also resolve unless you declare it abstract. Doing that raises the expected exception.

If you introduce an interface or abstract base class that should solve your problem.

You should open a bug ticket for Unity.



Related Topics



Leave a reply



Submit