FileResult是一个基于文件的ActionResult,利用FileResult我们可以很容易地将从某个物理文件的内容响应给客户端。ASP.NET MVC定义了三个具体的FileResult,分别是FileContentResultFilePathResultFileStreamResult。在这篇文章中我们将探讨三种具体的FileResult是如何将文件内容对请求进行响应的。

一、FileResult

如下面的代码片断所示,FileResult具有一个表示媒体类型的只读属性ContentType,该属性在构造函数中被初始化。当我们基于某个物理文件创建相应的FileResult对象的时候应该根据文件的类型指定媒体类型,比如说目标文件是一个.jpg图片,那么对应的媒体类型为“image/jpeg”,对于一个.pdf文件,则采用“application/pdf”。

public abstract class FileResult : ActionResult
{
    private string _fileDownloadName;
        
    protected FileResult(string contentType)
    {
        if (string.IsNullOrEmpty(contentType))
        {
            throw new ArgumentException(MvcResources.Common_NullOrEmpty, "contentType");
        }
        this.ContentType = contentType;
    }
        
    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        HttpResponseBase response = context.HttpContext.Response;
        response.ContentType = this.ContentType;
        if (!string.IsNullOrEmpty(this.FileDownloadName))
        {
            string headerValue = ContentDispositionUtil.GetHeaderValue(this.FileDownloadName);
            context.HttpContext.Response.AddHeader("Content-Disposition", headerValue);
        }
        this.WriteFile(response);
    }
        
    protected abstract void WriteFile(HttpResponseBase response);
        
    public string ContentType { get; private set; }
        
    public string FileDownloadName
    {
        get
        {
            return (this._fileDownloadName ?? string.Empty);
        }
        set
        {
            this._fileDownloadName = value;
        }
    }
        
    internal static class ContentDispositionUtil
    {
        private const string HexDigits = "0123456789ABCDEF";
            
        private static void AddByteToStringBuilder(byte b, StringBuilder builder)
        {
            builder.Append('%');
            int num = b;
            AddHexDigitToStringBuilder(num >> 4, builder);
            AddHexDigitToStringBuilder(num % 0x10, builder);
        }
            
        private static void AddHexDigitToStringBuilder(int digit, StringBuilder builder)
        {
            builder.Append("0123456789ABCDEF"[digit]);
        }
            
        private static string CreateRfc2231HeaderValue(string filename)
        {
            StringBuilder builder = new StringBuilder("attachment; filename*=UTF-8''");
            foreach (byte num in Encoding.UTF8.GetBytes(filename))
            {
                if (IsByteValidHeaderValueCharacter(num))
                {
                    builder.Append((char) num);
                }
                else
                {
                    AddByteToStringBuilder(num, builder);
                }
            }
            return builder.ToString();
        }
            
        public static string GetHeaderValue(string fileName)
        {
            foreach (char ch in fileName)
            {
                if (ch > '\x007f')
                {
                    return CreateRfc2231HeaderValue(fileName);
                }
            }
            ContentDisposition disposition = new ContentDisposition {
                FileName = fileName
            };
            return disposition.ToString();
        }
            
        private static bool IsByteValidHeaderValueCharacter(byte b)
        {
            if ((0x30 <= b) && (b <= 0x39))
            {
                return true;
            }
            if ((0x61 <= b) && (b <= 0x7a))
            {
                return true;
            }
            if ((0x41 <= b) && (b <= 90))
            {
                return true;
            }
            switch (b)
            {
                case 0x3a:
                case 0x5f:
                case 0x7e:
                case 0x24:
                case 0x26:
                case 0x21:
                case 0x2b:
                case 0x2d:
                case 0x2e:
                    return true;
            }
            return false;
        }
    }
}
View Code

相关文章: