C# IDependencyResolver在一个请求中处理了两次
我有一个相当复杂的C# IDependencyResolver在一个请求中处理了两次,c#,dependency-injection,unity-container,asp.net-web-api2,owin,C#,Dependency Injection,Unity Container,Asp.net Web Api2,Owin,我有一个相当复杂的WebAPI2项目,使用Owin和依赖注入,使用Unity。我现在确实有一个控制器操作,它从请求.Content中获取MultipartContent,然后将其移交给一个服务(由DI创建),该服务将该文件临时存储到服务器的硬盘上。这是必需的,因为服务使用外部和本机DLL来读取此文件以进行某些验证和转换。因此,外部DLL将转换后的文件和转换结果(作为XML)另外存储在同一位置。我的服务现在读取转换结果并返回该结果。然后删除临时文件 现在的问题是,我自己的idependencyso
WebAPI2
项目,使用Owin
和依赖注入,使用Unity
。我现在确实有一个控制器操作,它从请求.Content
中获取MultipartContent
,然后将其移交给一个服务(由DI创建),该服务将该文件临时存储到服务器的硬盘上。这是必需的,因为服务使用外部和本机DLL来读取此文件以进行某些验证和转换。因此,外部DLL将转换后的文件和转换结果(作为XML)另外存储在同一位置。我的服务现在读取转换结果并返回该结果。然后删除临时文件
现在的问题是,我自己的idependencysolver
方法在该操作期间被调用了两次,这实际上破坏了内容,因此下一个请求也失败了。例如,我确实收到了无法创建控制器的错误,因为它在System.Web.Http.HttpServer
上没有无参数构造函数或ObjectDisposedException
。之后,DI容器被正确地重建,一切正常。等等所以每秒钟的请求都会失败
下面是一些代码:
Owin启动
[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);
}
}
}
同样,这也没什么特别之处,因为它只是从网络上众多示例中的一个复制而来
现在控制器操作:
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.");
}
现在问题来了。当我使用
_tempFilePath = AppDomain.CurrentDomain.BaseDirectory + TempDirectory;
一切正常
我想这与卷影复制有关…Dispose()似乎不是线程安全的。还有为什么每次请求后都要拆下DI?通常我是为应用程序的生命周期构建DI的。@OndrejSvejdar拆掉DI并不是故意的。在
idependencysolver.BeginScope()
中创建了一个子容器,该子容器稍后将被释放,这似乎是正确的。在我上面的例子中,父容器也被处理掉了,这给我带来了所有的麻烦。问题是为什么要处理父容器,是谁造成的;当您点击Dispose()时,我可以请您分享调用堆栈上的内容吗?@OndrejSvejdar感谢您的努力!在这两种情况下,调用堆栈中的第一个元素都是[External code]
,然后是Dispose()
。所以这里没有什么启发。。。我很确定这是和创建/删除文件和文件夹有关的。这是否可能只发生在vs调试环境中?可能是因为vs中的浏览器链接。此工具本身会发出一些请求。请参见此处:()Dispose()内容似乎不是线程安全的。还有为什么每次请求后都要拆下DI?通常我是为应用程序的生命周期构建DI的。@OndrejSvejdar拆掉DI并不是故意的。在idependencysolver.BeginScope()
中创建了一个子容器,该子容器稍后将被释放,这似乎是正确的。在我上面的例子中,父容器也被处理掉了,这给我带来了所有的麻烦。问题是为什么要处理父容器,是谁造成的;当您点击Dispose()时,我可以请您分享调用堆栈上的内容吗?@OndrejSvejdar感谢您的努力!在这两种情况下,调用堆栈中的第一个元素都是[External code]
,然后是Dispose()
。所以这里没有什么启发。。。我很确定这是和创建/删除文件和文件夹有关的。这是否可能只发生在vs调试环境中?可能是因为vs中的浏览器链接。此工具本身会发出一些请求。请看这里:()
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;
}
}
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
_tempFilePath = Path.GetDirectoryName(path) + TempDirectory;
_tempFilePath = AppDomain.CurrentDomain.BaseDirectory + TempDirectory;