必须填写至少10个字的日志
nnhy authored at 2012-07-27 18:48:21
4.87 KiB
X
using System;
using System.IO;
using System.Web;
using System.Web.Caching;
using NewLife.Log;
using NewLife.Web;

namespace NewLife.CommonEntity.Web
{
    /// <summary>附件处理器</summary>
    public class AttachmentHttpHandler : IHttpHandler
    {
        #region IHttpHandler 成员
        bool IHttpHandler.IsReusable
        {
            get { return false; }
        }

        void IHttpHandler.ProcessRequest(HttpContext context)
        {
            OnProcess(context);
        }
        #endregion

        #region 属性
        /// <summary>文件编号</summary>
        public Int32 ID
        {
            get
            {
                String str = HttpContext.Current.Request["ID"];
                if (String.IsNullOrEmpty(str)) return 0;

                Int32 n = 0;
                if (!Int32.TryParse(str, out n)) n = 0;

                return n;
            }
        }
        #endregion

        #region 文件流
        /// <summary>获取文件数据流。这里可以实现小文件缓存进入内容以减少磁盘IO</summary>
        /// <param name="context"></param>
        /// <param name="attachment"></param>
        /// <returns></returns>
        protected virtual Stream GetStream(HttpContext context, IAttachment attachment)
        {
            if (attachment.Size > MaxFileSize) return new FileStream(attachment.FullFilePath, FileMode.Open, FileAccess.Read);

            var key = "NewLife.Attachment.Cache_" + attachment.ID;
            var stream = HttpRuntime.Cache[key] as Stream;
            if (stream != null) return stream;

            var fs = new FileStream(attachment.FullFilePath, FileMode.Open, FileAccess.Read);
            // 再次判断,防止记录的文件大小不正确而导致系统占用大量内存
            if (fs.Length > MaxFileSize) return fs;

            var buffer = new Byte[fs.Length];
            fs.Read(buffer, 0, buffer.Length);
            fs.Close();

            stream = new MemoryStream(buffer);
            HttpRuntime.Cache.Insert(key, stream, null, DateTime.Now.Add(CacheTime), Cache.NoSlidingExpiration);
            return stream;
        }

        /// <summary>小于指定大小才缓存文件</summary>
        protected virtual Int64 MaxFileSize { get { return 100 * 1024; } }

        /// <summary>小文件缓存时间,默认10分钟</summary>
        /// <returns></returns>
        protected virtual TimeSpan CacheTime { get { return new TimeSpan(0, 10, 0); } }
        #endregion

        #region 方法
        /// <summary>处理</summary>
        /// <param name="context"></param>
        protected virtual void OnProcess(HttpContext context)
        {
            var attachment = GetAttachment();

            if (attachment == null || !attachment.IsEnable || !File.Exists(attachment.FullFilePath))
            {
                OnNotFound(context);
                return;
            }

            // 增加统计
            attachment.Increment(null);

            var stream = GetStream(context, attachment);
            if (stream.CanSeek && stream.Position >= stream.Length) stream.Position = 0;
            try
            {
                OnResponse(context, attachment, stream, null);
            }
            catch (Exception ex)
            {
                XTrace.WriteException(ex);
            }
            finally
            {
                // 关闭文件流
                if (stream is FileStream) stream.Close();
            }
        }

        /// <summary>取得附件对象</summary>
        /// <returns></returns>
        protected virtual IAttachment GetAttachment()
        {
            if (ID > 0)
                return Attachment.FindByID(ID);
            else
                return null;
        }

        /// <summary>没找到附件</summary>
        /// <param name="context"></param>
        protected virtual void OnNotFound(HttpContext context)
        {
            HttpResponse Response = context.Response;

            Response.StatusCode = 400;
            //Response.Status = "文件未找到!";

        }

        /// <summary>响应</summary>
        /// <param name="context"></param>
        /// <param name="attachment"></param>
        /// <param name="stream"></param>
        /// <param name="dispositionMode"></param>
        protected virtual void OnResponse(HttpContext context, IAttachment attachment, Stream stream, String dispositionMode)
        {
            var wd = new WebDownload();
            wd.Stream = stream;
            wd.FileName = attachment.FileName;
            if (!String.IsNullOrEmpty(dispositionMode)) wd.Mode = WebDownload.ParseMode(dispositionMode);
            if (!String.IsNullOrEmpty(attachment.ContentType)) wd.ContentType = attachment.ContentType;
            wd.Render();
        }
        #endregion
    }
}