最近用ActionFilter给REST Api加入本地缓存功能,在OnActionExecutedAsync重写中,需要将缓存对象的内容以byte[]的形式存入缓存,并缓存Etag、ContentType信息。
而在该方法中以
var content = await responseContent.ReadAsByteArrayAsync().ConfigureAwait(false);
获取byte[]形式的响应内容时,提示Cannot access a closed Stream.即认为响应流已关闭,但其实上下文中并未显示关闭Stream对象或以using操作流对象。
为了验证,同样的代码在一个新建的web api2项目中使用,则能够正常获取响应内容,查了很久未果。。。。
以下是上下文代码:
1 public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken) 2 { 3 if (actionExecutedContext.ActionContext.Response == null 4 || !actionExecutedContext.ActionContext.Response.IsSuccessStatusCode) 5 return; 6 if (!IsCachingAllowed(actionExecutedContext.ActionContext)) 7 return; 8 var cacheTime = CacheTimeQuery.Execute(DateTime.Now); 9 if (cacheTime.AbsoluteExpiration > DateTime.Now) 10 { 11 var httpConfig = actionExecutedContext.Request.GetConfiguration(); 12 var config = httpConfig.RestCacheConfiguration(); 13 var cacheKeyGenerator = config.GetCacheKeyGenerator(CacheKeyGenerator); 14 var responseMediaType = actionExecutedContext.Request.Properties[CurrentRequestMediaType] as MediaTypeHeaderValue 15 ?? GetExpectedMediaType(httpConfig, actionExecutedContext.ActionContext); 16 var cachekey = cacheKeyGenerator.MakeCacheKey(actionExecutedContext.ActionContext, responseMediaType); 17 if (!string.IsNullOrWhiteSpace(cachekey) && !(_restCache.Contains(cachekey))) 18 { 19 SetEtag(actionExecutedContext.Response, CreateEtag(actionExecutedContext, cachekey, cacheTime)); 20 var responseContent = actionExecutedContext.Response.Content; 21 if (responseContent != null) 22 { 23 var baseKey = config.MakeBaseCachekey(actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerType.FullName, actionExecutedContext.ActionContext.ActionDescriptor.ActionName); 24 var contentType = responseContent.Headers.ContentType; 25 string etag = actionExecutedContext.Response.Headers.ETag.Tag; 26 try 27 { 28 var content = await responseContent.ReadAsByteArrayAsync().ConfigureAwait(false); 29 responseContent.Headers.Remove("Content-Length"); 30 _restCache.Add(baseKey, string.Empty, cacheTime.AbsoluteExpiration); 31 _restCache.Add(cachekey, content, cacheTime.AbsoluteExpiration, baseKey); 32 _restCache.Add(cachekey + Constants.ContentTypeKey, 33 contentType, 34 cacheTime.AbsoluteExpiration, baseKey); 35 _restCache.Add(cachekey + Constants.EtagKey, 36 etag, 37 cacheTime.AbsoluteExpiration, baseKey); 38 } 39 catch (Exception exp) 40 { 41 //捕捉到Cannot access a closed Stream. 42 throw; 43 } 44 } 45 } 46 } 47 ApplyCacheHeaders(actionExecutedContext.ActionContext.Response, cacheTime); 48 }