1

在独立模式下使用 ServiceStack,我在我的 Apphost 中为任意文件名定义了一个包罗万象的处理程序(它只会从数据目录中提供文件)。

它的核心方法是(fi是一个FileInfo成员变量,ExtensionContentType是一个Dictionary从扩展到MIME的类型):

public class StaticFileHandler : EndpointHandlerBase
{
    protected static readonly Dictionary<string, string> ExtensionContentType;

    protected FileInfo fi;

    static StaticFileHandler()
    {
        ExtensionContentType = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) 
        {
            { ".text", "text/plain" },
            { ".js", "text/javascript" },
            { ".css", "text/css" },
            { ".html", "text/html" },
            { ".htm", "text/html" },
            { ".png", "image/png" },
            { ".ico", "image/x-icon" },
            { ".gif", "image/gif" },
            { ".bmp", "image/bmp" },
            { ".jpg", "image/jpeg" }
        };
    }

    public string BaseDirectory { protected set; get; }
    public string Prefix { protected set; get; }

    public StaticFileHandler(string baseDirectory, string prefix)
    {
        BaseDirectory = baseDirectory;
        Prefix = prefix;
    }

    private StaticFileHandler(FileInfo fi)
    {
        this.fi = fi;
    }

    public static StaticFileHandler Factory(string baseDirectory, string prefix, string pathInfo)
    {
        if (!pathInfo.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase))
        {
            return null;
        }

        var fn = baseDirectory + "/" + pathInfo.After(prefix.Length);

        Console.Write("StaticFileHandler.Factory fn=" + fn);

        Console.WriteLine("AbsoluteUri={0}", pathInfo);

        var fi = new System.IO.FileInfo(fn);

        if (!fi.Exists)
        {
            return null;
        }

        return new StaticFileHandler(fi);
    }

    public override void ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes, string operationName)
    {
        using (var source = new System.IO.FileStream(fi.FullName, System.IO.FileMode.Open))
        {
            source.CopyTo(httpRes.OutputStream);
            //var bytes = source.ReadAllBytes();
            //httpRes.OutputStream.Write(bytes, 0, bytes.Length);
        }

        // timeStamp = fi.LastWriteTime;                        

        httpRes.AddHeader("Date", DateTime.Now.ToString("R"));
        httpRes.AddHeader("Content-Type", ExtensionContentType.Safeget(fi.Extension) ?? "text/plain");
        //httpRes.ContentType = ExtensionContentType.Safeget(fi.Extension, "text/plain");
    }

    public override object CreateRequest(IHttpRequest request, string operationName)
    {
        return null;
    }

    public override object GetResponse(IHttpRequest httpReq, IHttpResponse httpRes, object request)
    {
        return null;
    }
}

当我使用标记为方法 1 或方法 2 的行运行时,未设置实际的 HTTP Response-Type 标头。使用 IE9 开发人员工具进行调试显示根本没有设置响应类型。

从包罗万象的处理程序设置内容类型(和流内容)的正确方法是什么?

这不是标准服务,所以我不能只返回一个自定义的IHttpResponse,这似乎是服务的正常方法。

附加信息:日期标题也未设置...

4

1 回答 1

2

我认为问题在于这条线source.CopyTo(httpRes.OutputStream);

如果您执行类似的操作,则应填充标题

public override void ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes, string operationName)
{
    var bytes = File.ReadAllBytes(fi.FullName);                   
    httpRes.AddHeader("Date", DateTime.Now.ToString("R"));
    httpRes.AddHeader("Content-Type", "text/plain");
    httpRes.AddHeader("TestHeader", "SomeValue");
    httpRes.OutputStream.Write(bytes, 0, bytes.Length);
}

用于测试答案的简单控制台应用程序

初始化 ServiceStack AppHost 并在控制台中运行它:

class Program
{
    static void Main(string[] args)
    {
        var appHost = new AppHost();
        appHost.Init();
        appHost.Start("http://*:1337/");
        System.Console.WriteLine("Listening on http://localhost:1337/ ...");
        System.Console.ReadLine();
        System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
    }
}

一些虚拟服务......对于这个答案来说并不是必需的:

[Route("/Hello/{Name}")]
public class Hello
{
    public string Name { get; set; }
}

public class HelloService : Service
{
    public string Any(Hello request)
    {
        return request.Name;
    }
}

配置 AppHost 并将“被测代码”添加到 CatchAllHanders:

public class AppHost : AppHostHttpListenerBase
{
    public AppHost() : base("Test Console", typeof(AppHost).Assembly) { }

    public override void Configure(Funq.Container container)
    {
        CatchAllHandlers.Add(StaticFileHandler.Factory);
    }

}

修改了“被测代码”——主要需要到达 ProcessRequest() 并返回一个文件:

public class StaticFileHandler : EndpointHandlerBase
{
    protected static readonly Dictionary<string, string> ExtensionContentType;

    protected FileInfo fi;

    static StaticFileHandler()
    {
        ExtensionContentType = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) 
    {
        { ".text", "text/plain" },
        { ".js", "text/javascript" },
        { ".css", "text/css" },
        { ".html", "text/html" },
        { ".htm", "text/html" },
        { ".png", "image/png" },
        { ".ico", "image/x-icon" },
        { ".gif", "image/gif" },
        { ".bmp", "image/bmp" },
        { ".jpg", "image/jpeg" }
    };
    }

    public string BaseDirectory { protected set; get; }
    public string Prefix { protected set; get; }

    public StaticFileHandler(string baseDirectory, string prefix)
    {
        BaseDirectory = baseDirectory;
        Prefix = prefix;
    }

    private StaticFileHandler(FileInfo fi)
    {
        this.fi = fi;
    }

    public static StaticFileHandler Factory(string baseDirectory, string prefix, string pathInfo)
    {
        return new StaticFileHandler(new FileInfo(@"C:\Test.xml"));
    }

    public override void ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes, string operationName)
    {
        var bytes = File.ReadAllBytes(fi.FullName);

        httpRes.AddHeader("Date", DateTime.Now.ToString("R"));
        httpRes.AddHeader("Content-Type", "text/plain");
        httpRes.AddHeader("Test", "SetThis");

        httpRes.OutputStream.Write(bytes, 0, bytes.Length);
    }

    public override object CreateRequest(IHttpRequest request, string operationName)
    {
        return null;
    }

    public override object GetResponse(IHttpRequest httpReq, IHttpResponse httpRes, object request)
    {
        return null;
    }
}
于 2013-04-08T22:12:52.377 回答