3
votes

I'm using Unity 2.0 in my project where I'm reading a lot of files at the same time inside Parallel.ForEach block of code:

Parallel.ForEach(files, currentFile =>
{
    using(IMsBuildProjectLoader msBuildProject = Container.Resolve<IMsBuildProjectLoader>(new ParameterOverride("projectFileName", currentFile)))
    {
        // file processing
    }
}

Resolve(new ParameterOverride("projectFileName", currentFile) function sometimes throw ResolutionFailedException:

ResolutionFailedException: Resolution of the dependency failed, 
type = "Porthus.Build.Common.Interfaces.IMsBuildProjectLoader", name = "(none)". 
Exception occurred while: Calling constructor XXX.Build.Common.Types.MsBuildProjectLoader(System.String projectFileName). 
Exception is: ArgumentException - Item has already been added. Key in dictionary: 'xxx'  Key being added: 'xxx'

This is when the same file is loaded at the same time - Resolve function is creating two IMsBuildProjectLoader instances with the same parameter at the same time. It cannot be solved by files.Distinct() filter. Above code is only a code example to explain my problem.

The question is: How to implement thread safe UnityContainer.Resolve function? Is it possible to do it using some Unity extension class?

IMsBuildProjectLoader:

public interface IMsBuildProjectLoader : IDisposable
{
}

MsBuildProjectLoader:

public class MsBuildProjectLoader : Project, IMsBuildProjectLoader
{
    public MsBuildProjectLoader(string projectFileName)
        : base()
    {
        // Load the contents of the specified project file.
        Load(projectFileName);
    }
}

MsBuildProjectLoader is registered this way:

container.RegisterType<IMsBuildProjectLoader, MsBuildProjectLoader>();
1
This doesn't answer your question directly, but I think you might be doing it wrong. Your class should be injected with an IMsBuildProjectLoader, and in your loop, you should call a method on the IMsBuildProjectLoader that takes the file name as a parameter. The thread safety should then be baked into your implementation of the IMsBuildProjectLoader. My $0.02. - BFree
Yes, that's another option. Thanks - Ludwo

1 Answers

0
votes

Resolve is actually thread safe (or so say the guys at Microsoft P&P). What is probably not thread safe is the implementation of MsBuildProjectLoader, or more specifically it's constructor. You would probably stumble the same issue by simply creating new instances of MsBuildProjectLoader using new in the same asynchronous manner

You didn't include the implementation of Load, but according to the exception I would assume it manipulates a shared or static dictionary in a not thread-safe manner. If this is the case, you should make that dictionary thread safe (for example by replacing it with a ConcurrentDictionary).