Reputation: 29010
We're using Service Stack for a web service API. We wrote a "get file" routine to fetch files rather than letting IIS serve the files directly, because we need server-side authentication logic.
We return a file from RestServiceBase<Foo>.OnGet
by returning an IStreamWriter
, which is implemented like this:
public void WriteTo(Stream responseStream)
{
Stream filedata = File.OpenRead(_filepath);
filedata.CopyTo(responseStream);
}
The problem: This is about 50% to 100% slower than IIS serving the file directly.
Am I returning a file from Service Stack incorrectly? Is there something I can do to speed this up?
Alternatively, is there some way I can plug our authentication scheme (which we want to be total stateless, so no caching credentials on a server machine) into IIS so that IIS calls our server in some way to authenticate each request then serves the file itself?
Upvotes: 3
Views: 1131
Reputation: 11
There is a penalty in the context switch of the IIS I/O thread to a thread on the CLR thread pool, if you set the (asp config) MaxConcurrentRequestsPerCPU to 0 your CLR code you should be able to mitigate that (might have other ramifications though)
see http://blogs.msdn.com/b/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx
I don't know if windows allow for "zero copy":ing the file (never leaving the kernel mode and skipping buffer on socket to filehandle operation) But if that is supported IIS is definitely utilizing it (making it faster than CLR in user mode .. )
Upvotes: 0
Reputation: 143359
IIS would use native code for serving static files and likely employs some aggressive in-memory caching to achieve its performance.
As ServiceStack is a .NET library that code is writing directly to ASP.NET's response stream so its harder to get any faster at streaming a file in managed .NET code. You could further increase performance by loading the file into memory and writing raw bytes instead.
Which is why if you have to do it managed code you should give your best efforts at taking advantage of HTTP Caching which is what we do in our StaticFileHandler - i.e. what ServiceStack uses to serve its static content, e.g css/js/html pages.
Although ServiceStack's request pipeline is heavily optimized (i.e. doesn't add much overhead) you can still by-pass it by registering your own custom IHttpHandler
and handle the raw ASP.NET request yourself - this will be the fastest option in .NET code, e.g:
SetConfig(new EndpointHostConfig {
RawHttpHandlers = { MiniProfilerHandler.MatchesRequest },
});
This is what the built-in MiniProfiler uses to serve its static content. MatchesRequest just takes a IHttpRequest
to work out if it should handle the request (by returning a instance of IHttpHandler) or not (return null):
public static IHttpHandler MatchesRequest(IHttpRequest request)
{
var file = Path.GetFileNameWithoutExtension(request.PathInfo);
return file != null && file.StartsWith("ss-")
? new MiniProfilerHandler()
: null;
}
Other than that, the stand-alone version of ServiceStack (i.e. HttpListener host) should provide better raw thoughput than ASP.NET.
Upvotes: 2