开发者

WCF .NET 4 OutputCaching with Stream doesn't seem to work

I'm having problems with OutputCaching over a WCF REST service on .NET4-IIS7. My service has a custom Authorization scheme (by implementing ServiceAuthorizationManager), one which should take place on every request, and any caching must be done after the request is authorized. So far, this seems to work, only the caching part I can't see happening.

I have the following OperationContract:

[OperationContract]
[AspNetCacheProfile("PageZIP")]
[WebGet(UriTemplate = "pages/{page_id}")]
System.IO.Stream getPage(string page_id);

And the following web.config:

<system.web>
<compilation targetFramework="4.0" />
<customErrors mode="Off" />
<authentication mode="None" />
<caching>
    <outputCache enableOutputCache="true"/>
    <outputCacheSettings>
        <outputCacheProfiles>
            <add name="PageZIP" duration="7200" location="ServerAndClient"
                     varyByParam="page_id" />
        </outputCacheProfiles>
    </outputCacheSettings>
</caching>
</system.web>
    <system.serviceModel>
    <behaviors>
        <serviceBehaviors>
            <behavior>
                <serviceAuthorization serviceAuthorizationManagerType="api.Authorization, api" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <standardEndpoints>
        <webHttpEndpoint>
            <standardEndpoint transferMode="StreamedResponse" automaticFormatSelectionEnabled="false" defaultOutgoingResponseFormat="Json" />
        </webHttpEndpoint>
    </standardEndpoints></system.serviceModel>

I can see the new response headers filled with client-side cache information when I call the service, but caching at the server doesn't seem to work. My custom log shows that my api.Authorization class is (rightly) being called, but my getPage() method is also executing as normal, up to the point where my file is being .OpenRead() into a Stream and returned:

public System.IO.Stream getPage(string page_id) {
    File zip = FileMapper.getZip(pid);
    ctx.OutgoingResponse.Headers.Clear();开发者_Go百科
    ctx.OutgoingResponse.Headers.Add("Content-Disposition", "attachment; filename=" + page_id + ".zip");
    ctx.OutgoingResponse.Headers.Add("Content-Length", zip.size.ToString());
    ctx.OutgoingResponse.ContentType = "application/zip";

    Log.write("OpenRead", LogType.Info);
    return System.IO.File.OpenRead(zip.path);
}

If output is being cached, this method shouldn't be executed at all... I expect the Stream to be cached and be served directly, without queries to the database and disk reads. Every zipfile is about 1 MB in size. What am I missing or doing wrong?


After playing with settings for a while, the answer came out: OutputCache won't work if transferMode is streaming, even if you implement your own OutputCacheProvider. The reason behind this is that, in a streamed response scenario, you're telling WCF not to buffer your response in memory, and try to read it from wherever it is and send it down to transport level. OutputCache depends on the object being fully in-memory before it's returned, so that WCF can keep the reference to it and put that on cache.

It's up to you to see in your scenario if enabling streaming without output cache is faster than reading and keeping the object in-memory so you can output it directly.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜