filipw / Strathweb.CacheOutput

ASP.NET Web API CacheOutput - library to allow you to cache the output of ApiControllers
Other
882 stars 253 forks source link

The type IApiOutputCache does not have an accessible constructor. #89

Closed KingR1 closed 10 years ago

KingR1 commented 10 years ago

I install Strathweb.CacheOutput.WebApi2 using Package Manager Console. Try to run my WebAPI project - get error : "Attempt by security transparent method 'System.Web.Http.GlobalConfiguration.get_Configuration()' to access security critical type 'System.Web.Http.HttpConfiguration' failed."

So i made search for solution and stopped at this post http://www.dotnetspider.com/resources/45576-Attempt-by-security-transparent-method.aspx So i do following : Update-Package Microsoft.AspNet.WebApi -Pre.

Then i get problem with CacheOutput :

{"message":"An error has occurred.","exceptionMessage":"Resolution of the dependency failed, type = \"WebApi.OutputCache.Core.Cache.IApiOutputCache\", name = \"(none)\".\r\nException occurred while: while resolving.\r\nException is: InvalidOperationException - The type IApiOutputCache does not have an accessible constructor.\r\n-----------------------------------------------\r\nAt the time of the exception, the container was:\r\n\r\n Resolving WebApi.OutputCache.Core.Cache.IApiOutputCache,(none)\r\n","exceptionType":"Microsoft.Practices.Unity.ResolutionFailedException","stackTrace":" at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable1 resolverOverrides)\r\n at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, String name, IEnumerable1 resolverOverrides)\r\n at Microsoft.Practices.Unity.UnityContainer.Resolve(Type t, String name, ResolverOverride[] resolverOverrides)\r\n at Microsoft.Practices.Unity.UnityContainerExtensions.Resolve(IUnityContainer container, Type t, ResolverOverride[] overrides)\r\n at Microsoft.Practices.Unity.WebApi.UnityDependencyResolver.SharedDependencyScope.GetService(Type serviceType)\r\n at WebApi.OutputCache.V2.CacheOutputConfiguration.GetCacheOutputProvider(HttpRequestMessage request)\r\n at WebApi.OutputCache.V2.CacheOutputAttribute.EnsureCache(HttpConfiguration config, HttpRequestMessage req)\r\n at WebApi.OutputCache.V2.CacheOutputAttribute.OnActionExecuting(HttpActionContext actionContext)\r\n at WebApi.OutputCache.V2.CacheOutputAttribute.System.Web.Http.Filters.IActionFilter.ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func1 continuation)\r\n at System.Web.Http.Tracing.Tracers.ActionFilterTracer.<>cDisplayClass3.b0()\r\n at System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEndAsync[TResult](ITraceWriter traceWriter, HttpRequestMessage request, String category, TraceLevel level, String operatorName, String operationName, Action1 beginTrace, Func1 execute, Action2 endTrace, Action1 errorTrace)\r\n at System.Web.Http.Tracing.Tracers.ActionFilterTracer.System.Web.Http.Filters.IActionFilter.ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func1 continuation)\r\n at System.Web.Http.Controllers.ActionFilterResult.<>c__DisplayClassb.<>c__DisplayClassd.<InvokeActionWithActionFilters>b__9()\r\n at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at System.Web.Http.Controllers.ExceptionFilterResult.d0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Web.Http.Controllers.ExceptionFilterResult.d0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at System.Web.Http.Tracing.Tracers.HttpControllerTracer.<ExecuteAsyncCore>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at System.Web.Http.Tracing.ITraceWriterExtensions.d181.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.d1.MoveNext()","innerException":{"message":"An error has occurred.","exceptionMessage":"The type IApiOutputCache does not have an accessible constructor.","exceptionType":"System.InvalidOperationException","stackTrace":" at Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.ThrowForNullExistingObject(IBuilderContext context)\r\n at lambda_method(Closure , IBuilderContext )\r\n at Microsoft.Practices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>cDisplayClass1.b0(IBuilderContext context)\r\n at Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)\r\n at Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)\r\n at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)\r\n at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable1 resolverOverrides)"}}

Attribute, that i add to Web API method GET() is next : [CacheOutput(ClientTimeSpan = 50, ServerTimeSpan = 50)]

What can cause problem with CacheOutPut and how to resolve it?

filipw commented 10 years ago

it looks like you are using Unity. Did you register the Dependency Resolver for Unity? Do you have the code for that?

On 18 August 2014 15:37, KingR1 notifications@github.com wrote:

I install Strathweb.CacheOutput.WebApi2 using Package Manager Console. Try to run my WebAPI project - get error : "Attempt by security transparent method 'System.Web.Http.GlobalConfiguration.get_Configuration()' to access security critical type 'System.Web.Http.HttpConfiguration' failed."

So i made search for solution and stopped at this post http://www.dotnetspider.com/resources/45576-Attempt-by-security-transparent-method.aspx So i do following : Update-Package Microsoft.AspNet.WebApi -Pre.

Then i get problem with CacheOutput :

{"message":"An error has occurred.","exceptionMessage":"Resolution of the dependency failed, type = \"WebApi.OutputCache.Core.Cache.IApiOutputCache\", name = \"(none)\".\r\nException occurred while: while resolving.\r\nException is: InvalidOperationException - The type IApiOutputCache does not have an accessible constructor.\r\n-----------------------------------------------\r\nAt the time of the exception, the container was:\r\n\r\n Resolving WebApi.OutputCache.Core.Cache.IApiOutputCache,(none)\r\n","exceptionType":"Microsoft.Practices.Unity.ResolutionFailedException","stackTrace":" at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable1 resolverOverrides)\r\n at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, String name, IEnumerable1 resolverOverrides)\r\n at Microsoft.Practices.Unity.UnityContainer.Resolve(Type t, String name, ResolverOverride[] resolverOverrides)\r\n at Microsoft.Practices .Unity.UnityContainerExtensions.Resolve(IUnityContainer container, Type t, ResolverOverride[] overrides)\r\n at Microsoft.Practices.Unity.WebApi.UnityDependencyResolver.SharedDependencyScope.GetService(Type serviceType)\r\n at WebApi.OutputCache.V2.CacheOutputConfiguration.GetCacheOutputProvider(HttpRequestMessage request)\r\n at WebApi.OutputCache.V2.CacheOutputAttribute.EnsureCache(HttpConfiguration config, HttpRequestMessage req)\r\n at WebApi.OutputCache.V2.CacheOutputAttribute.OnActionExecuting(HttpActionContext actionContext)\r\n at WebApi.OutputCache.V2.CacheOutputAttribute.System.Web.Http.Filters.IActionFilter.ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func1 continuation)\r\n at System.Web.Http.Tracing.Tracers.ActionFilterTracer.<>cDisplayClass3.b0()\r\n at System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEndAsync TResult\r\n at System.Web.Http.Tracing.Tracers.ActionFilterTracer.System.Web.Http.Filters.IActionFilter.ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func1 continuation)\r\n at System.Web.Http.Controllers.ActionFilterResult.<>cDisplayClassb.<>cDisplayClassd.b9()\r\n at System.Web.Http.Controllers.ActionFilterResult.d2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetRe sult()\r\n at System.Web.Http.Controllers.ExceptionFilterResult.d0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Web.Http.Controllers.ExceptionFilterResult.d0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at System.Web.Http.Tracing.Tracers.HttpControllerTracer.d5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNoti fication(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at System.Web.Http.Tracing.ITraceWriterExtensions.d181.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()","innerException":{"message":"An error has occurred.","exceptionMessage":"The type IApiOutputCache does not have an accessible constructor.","exceptionType":"System.InvalidOperationException","stackTrace":" at Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.ThrowForNullExistingObject(IBuilderContext context)\r\n at lambda_method(Closure , IBuilderContext )\r\n at Microsoft.Pract ices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>cDisplayClass1.b0(IBuilderContext context)\r\n at Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)\r\n at Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)\r\n at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)\r\n at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable1 resolverOverrides)"}}

Attribute, that i add to Web API method GET() is next : [CacheOutput(ClientTimeSpan = 50, ServerTimeSpan = 50)]

What can cause problem with CacheOutPut and how to resolve it?

— Reply to this email directly or view it on GitHub https://github.com/filipw/AspNetWebApi-OutputCache/issues/89.

KingR1 commented 10 years ago

Hi, Filip. Yes, I use Unity and yes, I register it.

filipw commented 10 years ago

looks like your Unity adapter is throwing an exception when it shouldn't. Here you can find a proper implementation of Unity resolver http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver

The caching library will try to grab IApiOutputCache using the following precedence:

If you can't change the behavior unity resolver, you can always register IApiOutputCache in the HttpConfiguration:

httpConfiguration.CacheOutputConfiguration().RegisterCacheOutputProvider(() => new MemoryCacheDefault());
filipw commented 10 years ago

If you read the Unity article, there is even a highlighted note there :)

    If the GetService method cannot resolve a type, it should return null. If the GetServices method cannot resolve a type, it should return an empty collection object. Don't throw exceptions for unknown types.

which is what your Unity resolver seems to be doing now

KingR1 commented 10 years ago

If you can't change the behavior unity resolver, you can always register IApiOutputCache in the HttpConfiguration: httpConfiguration.CacheOutputConfiguration().RegisterCacheOutputProvider(() => new MemoryCacheDefault());

This also doesn't help me after I tried to make some changes in implementation of Unity resolver (firstly i user [Dependency] attribute, now - constructors for repositories)

filipw commented 10 years ago

please provide a repro project, I can have a look then

KingR1 commented 10 years ago

If it's allright - please get prototype of my project from here https://drive.google.com/file/d/0B60DXolm0D0GUWxxZG9ZUl9IeDQ/edit?usp=sharing (Connection String is some fake, working link /api/v1/holidays )

filipw commented 10 years ago

the unity dependency resolver you are using is botched because it doesn't handle errors properly (!). Use the one from the article I linked to http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver

public class UnityResolver : IDependencyResolver
{
    protected IUnityContainer container;

    public UnityResolver(IUnityContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }
        this.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()
    {
        container.Dispose();
    }
}

It works I tested it.

Alternatively add the following two lines in your web api configuration (not 1 like I said before :)

        config.CacheOutputConfiguration().RegisterCacheOutputProvider(() => new MemoryCacheDefault());
        config.CacheOutputConfiguration().RegisterDefaultCacheKeyGeneratorProvider(() => new DefaultCacheKeyGenerator());

This also works, even without changing the Unity resolver.

filipw commented 10 years ago

and thanks for providing the repro project - it helped a lot

KingR1 commented 10 years ago

Filip, Thanks! Problem is resolved!!! :+1: