1

I have a rather complex WebAPI2 project using Owin and Dependency Injection using Unity. I now do have a controller action that gets MultipartContent from the Request.Content that is then handed over to a service (created by DI) that temporarily stores this file to the hard drive of the server. This is needed because the service uses an external and native DLL that reads this file for some validation and conversion. So the external DLL additionally stores the converted file as well as the conversion result (as XML) in the same location. My service now reads the conversion result and returns that result. After that the temp files are deleted.

Problem now is that the Dispose() method of my own IDependencyResolver is called twice during that operation which actually destroys stuff so that the next request also fails. For example I do get errors that the controller cannot be created as it has no parameterless constructor or an ObjectDisposedException on System.Web.Http.HttpServer. After that the DI container is properly rebuild and everything works fine. And so on. So every second request fails.

So here is some code:

Owin Startup

[assembly: OwinStartup(typeof(MyNamespace.Startup))]
namespace myNamespace
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration httpConfiguration = new HttpConfiguration();
            httpConfiguration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
            app.UseCors(CorsOptions.AllowAll);

            IUnityContainer container = new UnityContainer();

            // setup dependency injection
            container.RegisterType<IFileConversionService, FileConversionService>();

            UnityConfig.RegisterControllers(container);

            // register routes
            WebApiConfig.Register(httpConfiguration);

            // setup dependency resolver
            httpConfiguration.DependencyResolver = new MyNamespace.UnityResolver(container);

            app.UseWebApi(httpConfiguration);
        }
    }
}

Well I don't think that there is anything special about that. As you can see I do not use the GlobalConfiguration.Configuration.DependencyResolver due to Owin.

My DependencyResolver:

public class UnityResolver : IDependencyResolver
{
    private IUnityContainer _container;
    private bool _disposed;

    public UnityResolver(IUnityContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }
       _container = container;
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return _container.Resolve(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return null;
        }
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        try
        {
            return _container.ResolveAll(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return new List<object>();
        }
    }

    public IDependencyScope BeginScope()
    {
        var child = _container.CreateChildContainer();
        return new UnityResolver(child);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
        {
            return;
        }

        if (disposing)
        {
            _container.Dispose();
        }

        _disposed = true;
    }
}

Again nothing special about this, as it was just copied from one of the many examples in the web.

Now the ControllerAction:

public async Task<IHttpActionResult> Upload()
{
    if (!Request.Content.IsMimeMultipartContent())
    {
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }

    MultipartMemoryStreamProvider provider = new MultipartMemoryStreamProvider();
    await Request.Content.ReadAsMultipartAsync(provider);

    IList<MyFile> uploadFiles = new List<MyFile>();
    foreach (var file in provider.Contents)
    {
        MyFile myFile = new MyFile
        {
            FileName = file.Headers.ContentDisposition.FileName.Trim('\"'),
            Data = await file.ReadAsByteArrayAsync()
        };

        uploadFiles.Add(myFile);
    }

    List<ConversionResult> result = new List<ConversionResult>();
    foreach(MyFile file in uploadFiles)
    {
        result.AddRange(_fileConversionService.ImportFile(file));
    }

    if (result!= null && result.Count() == uploadFiles.Count)
    {
        return Ok(importedParts);
    }

    return BadRequest("One or more files could not be imported.");
}

Now the service:

public IEnumerable<ConversionResult> ImportFile(MyFile myFile)
{
    lock (_lock)
    {
        IEnumerable<ConversionResult> conversionResult = new List<ConversionResult>();
        try
        {
            string inputFile = SaveFileTemporarily(myFile);
            string inputFileExtension = Path.GetExtension(inputFile);
            string logFile = inputFile.Replace(inputFileExtension, ".txt");

            // check if the file can be validated/converted by the DLL
            if (ValidateFileExtension(inputFileExtension))
            {
                // call external DLL that writes log file and converted file
                ConvertFile(inputFile, logFile, inputFileExtension);

                conversionResult = ParseLogFile(logFile);
                if (!conversionResult.Any())
                {
                    // no errors found
                    conversionResult.Add(ConversionResult.NoError);
                }
            }
            else
            {
                conversionResult.Add(ConversionResult.UnknownFileType);
            }
        }
        finally
        {
            Directory.Delete(GenerateTempSavePath(myFile), true);
        }

        return conversionResult;
    }
}

In SaveFileTemporarily() the file is stored to some folder, actually a sub folder of the bin folder; e.g. Directory.CreateDirectory(savePath); and File.WriteAllBytes(fullPath, data);

By debugging that I found out that I always break twice in the IDependencyResolver.Dispose() function which is not the case for any other controller action. By commenting stuff in the service method ImportFile() I found out that this has to do something with the file operations. So when I completely remove the System.IO namespace from the service class I do not get that behavior and everything seems to be fine.

I'm really lost at this now as I hunt this bug for several days now. Does anyone have an idea what the problem is?

UPDATE:

When using the API from a website I also often (but not always) get this error: No 'Access-Control-Allow-Origin' header is present on the requested resource. This leads to CORs which is also configured in the Owin Startup (app.UseCors(CorsOptions.AllowAll);).

This all hints to a more or less random disposal/crash of the whole Owin app. After those errors the Owin Startup method is called again which should not happen. When does the Owin Startup is being called?

When activating all Exceptions in Visual Studio (DEBUG -> Exceptions) I don't get anything...

UPDATE AND SOLUTION: Well I don't really know why, but the problem is solved. In the ImportFile() method of the service class is a call to SaveFileTemporarily(). This method uses a path that I searched in the constructor of the class:

string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
_tempFilePath = Path.GetDirectoryName(path) + TempDirectory;

Now here is the problem. When I use

_tempFilePath = AppDomain.CurrentDomain.BaseDirectory + TempDirectory;

everything works fine.

I guess it has to do something with the shadow-copying...

Simon Linder
  • 3,378
  • 4
  • 32
  • 49
  • The Dispose() stuff doesn't seem to be thread-safe. Also why you're tearing down DI after every request ? Usually I'm building DI for the life of application. – Ondrej Svejdar Sep 04 '15 at 13:42
  • @OndrejSvejdar Tearing down the DI is not intended. In the `IDependencyResolver.BeginScope()` a child container is created that is disposed later which seems to be correct. In my case above the parent container is disposed also which causes all my trouble. Question is why is the parent container disposed and who causes this. – Simon Linder Sep 04 '15 at 13:50
  • I'm having hard time to simulate this; can I ask you to share what is on the call stack when you hit the Dispose() ? – Ondrej Svejdar Sep 04 '15 at 14:59
  • @OndrejSvejdar Thanks for your effort! In both cases the first element in the call stack is `[External code]` then comes the `Dispose()`. So nothing enlightening here... I'm pretty sure that this is something with the creating/deleting files and folders. – Simon Linder Sep 04 '15 at 15:07
  • Is it possible that this only happens in your vs debug environment? Possible because of browser link in vs. This tool does make some requests on it's own. See here: (http://stackoverflow.com/questions/28820346/why-is-owin-middleware-created-a-second-time-after-the-httprequest-ended) – Ric .Net Sep 04 '15 at 18:04
  • @Ric.Net It is not browser related as this error also occurs using Fiddler. – Simon Linder Sep 04 '15 at 23:46
  • Could you try using the [UnityHierarchicalDependencyResolver](https://unity.codeplex.com/SourceControl/latest#source/Unity.WebApi/Src/UnityHierarchicalDependencyResolver.cs) from the [Unity.AspNet.WebApi](http://www.nuget.org/packages/Unity.AspNet.WebApi/) NuGet package? – TylerOhlsen Sep 07 '15 at 02:29
  • @TylerOhlsen I just tried that but it seems to be quite the same as my approach. Nevertheless the behavior is the same. – Simon Linder Sep 07 '15 at 07:32

0 Answers0