IDependencyResolver在一个请求中处理了两次

时间:2015-09-04 12:33:26

标签: c# dependency-injection unity-container asp.net-web-api2 owin

我有一个使用WebAPI2的相当复杂的Owin项目和使用Unity的依赖注入。我现在有一个控制器操作从MultipartContent获取Request.Content,然后移交给服务(由DI创建),该服务将此文件临时存储到服务器的硬盘驱动器。这是必需的,因为该服务使用外部和本机DLL来读取此文件以进行某些验证和转换。因此,外部DLL还将转换后的文件以及转换结果(作为XML)存储在同一位置。我的服务现在读取转换结果并返回该结果。之后,临时文件将被删除。

现在的问题是我自己Dispose()的{​​{1}}方法在该操作期间被调用两次,这实际上会破坏东西,以便下一个请求也失败。例如,我确实得到了无法创建控制器的错误,因为它没有无参数构造函数或IDependencyResolver上的ObjectDisposedException。之后DI容器正确重建,一切正常。等等。所以每一个请求都会失败。

所以这里有一些代码:

Owin Startup

System.Web.Http.HttpServer

嗯,我不认为这有什么特别之处。如您所见,由于[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); } } } ,我不使用GlobalConfiguration.Configuration.DependencyResolver

我的DependencyResolver:

Owin

这一点没有什么特别之处,因为它只是从网络上的众多例子之一中复制而来。

现在是ControllerAction:

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;
    }
}

现在的服务:

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.");
}

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; } } 中,文件存储到某个文件夹,实际上是bin文件夹的子文件夹;例如SaveFileTemporarily()Directory.CreateDirectory(savePath);

通过调试我发现我总是在File.WriteAllBytes(fullPath, data);函数中断两次,这与任何其他控制器操作不同。通过评论服务方法IDependencyResolver.Dispose()中的内容,我发现这必须对文件操作做些什么。所以当我从服务类中完全删除ImportFile()命名空间时,我没有得到那种行为,一切似乎都没问题。

我现在真的迷失了,因为我现在已经好几天都在追捕这个虫子了。有谁知道问题是什么?

更新

在网站上使用API​​时,我经常(但并非总是)会收到此错误:System.IO这导致No 'Access-Control-Allow-Origin' header is present on the requested resource.也在Owin Startup(CORs)中配置

这一切暗示整个Owin应用程序或多或少随机丢弃/崩溃。在那些错误之后,再次调用Owin Startup方法,这不应该发生。何时调用Owin Startup?

在Visual Studio中激活所有异常时(DEBUG - &gt; Exceptions),我什么都得不到......

更新和解决方案: 好吧,我不知道为什么,但问题解决了。在服务类的app.UseCors(CorsOptions.AllowAll);方法中,调用ImportFile()。此方法使用我在类的构造函数中搜索的路径:

SaveFileTemporarily()

现在问题就在于此。当我使用

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

一切正常。

我想它必须要做阴影复制......

0 个答案:

没有答案