ServiceStack:在Handler中设置响应类型?

时间:2013-04-08 15:57:35

标签: c# servicestack

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

其核心方法是(fiFileInfo成员变量,ExtensionContentTypeDictionary从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响应类型标头。使用IE9开发人员工具进行调试表明根本没有设置响应类型。

从catch-all处理程序设置内容类型(和流内容)的正确方法是什么?

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

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

1 个答案:

答案 0 :(得分: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;
    }
}