昨天遇到一个比较奇怪的需求,大致是需要在服务器上部署一个http服务,但是服务的具体功能不知道,以后在客服端实现。这里介绍一下系统背景,有一个系统运(部署在美国)行了很多年了,给系统产生了很多文件,现在需要把该系统的文件(依据数据库中的记录)来做相应的archive,做了后发现里面还有一些独立的文件(不与数据库记录相关),那么这时我们需要删除这些独立的文件,或者把它们remove到其他地方,需要得到这些文件的list。后来想了想以后会不会还有别的什么需求啊,所以就想做一个通用的HTTPhandler了。这里说明一下:production时在美国,Archive在香港;在我们大陆的系统权限放的都比较开,在美国那个权限管的非常紧,我们是没有权限直接操作Production上的文件,所以才需要用http 协议来做。这里的http server部署到US,而client 却部署到hk。

整个解决方案如图:

如何实现一个通用的IHttpHandler 万能的IHttpHandler HttpWebRequest文件上传

其中

WebApp项目部署到Production上(us)

ConsoleApp部署到archive上(hk)

HttpRequestLibrary 是一个对象序列化的通用类以及一个请求类的包装,WebApp和ConsoleApp都需要引用该dll

ProcessAction是在客户端实现的,但是在服务器端反序列化是必须有该文件,所以该dll将会从client 上传到Production上。

首先我们来看看服务器端的实现:

首先需要创建一个ProcessActionHandler.ashx来处理客户端的调用:

 public class ProcessActionHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            try
            {
                string inputstring = ReadInputStream();
                if (!string.IsNullOrEmpty(inputstring))
                {
                    HttpRequestInfo requestinfo = inputstring;
                    if (requestinfo.Process != null)
                    {
                        requestinfo.Process(requestinfo);
                    }
                }
                else
                {
                    //context.Response.StatusCode = 404;
                    context.Response.Write("input error message");
                }
            }
            catch (Exception ex)
            {
                context.Response.Write(ex.Message);
            }
        }
        private string ReadInputStream()
        {
            StringBuilder inputString = new StringBuilder();
            using (Stream sr = HttpContext.Current.Request.InputStream)
            {
                byte[] data = new byte[1024 * 100];
                int readCount = sr.Read(data, 0, data.Length);
                while (readCount > 0)
                {
                    string text = Encoding.UTF8.GetString(data, 0, readCount);
                    inputString.Append(text);
                    readCount = sr.Read(data, 0, data.Length);
                }
            }
            return inputString.ToString();
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }

这里的HttpRequestInfo类是客户端创建的,这里调用HttpRequestInfo的Process方法也是客户端实现的。如何才能获得客户端的实现了,我们需要把客户端实现的dll文件上传到服务器上。

所以需要创建一个UploadActionHandler.ashx来上传客户端的处理:

 public class UploadActionHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            string baseFilePath = context.Server.MapPath("Bin");
            if (context.Request.Files.Count > 0)
            {
                try
                {
                    HttpPostedFile file = context.Request.Files[0];
                    FileInfo fileInfo = new FileInfo(file.FileName);
                    if (fileInfo.Extension.Equals(".dll"))
                    {
                        string tempPath = tempPath = Path.Combine(baseFilePath, fileInfo.Name);
                        file.SaveAs(tempPath);
                        context.Response.Write("Success");
                    }
                    else
                    {
                        context.Response.Write("Failed:\r\n There only upload dll file");
                    }
                }
                catch (Exception ex)
                {
                    context.Response.Write("Failed:\r\n" + ex.Message);
                }
            }
            else
            {
                context.Response.Write("Failed:\r\nThe  Request has not upload file");
            }
        }


        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }

那么对象时如何序列化和反序列化,以及HttpRequestInfo的定义是什么样的了,这就要参考我们的HttpRequestLibrary项目了。

namespace HttpRequestLibrary
{

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Runtime.Remoting.Messaging;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Runtime.Serialization.Formatters.Soap;
    using System.Text;
    using System.Web;

    public enum FormatterType
    {
        /// <summary>
        /// SOAP消息格式编码
        /// </summary>
        Soap,

        /// <summary>
        /// 二进制消息格式编码
        /// </summary>
        Binary
    }

    public static class SerializationHelper
    {
        private const FormatterType DefaultFormatterType = FormatterType.Binary;

        /// <summary>
        /// 按照串行化的编码要求,生成对应的编码器。
        /// </summary>
        /// <param name="formatterType"></param>
        /// <returns></returns>
        private static IRemotingFormatter GetFormatter(FormatterType formatterType)
        {
            switch (formatterType)
            {
                case FormatterType.Binary: return new BinaryFormatter();
                case FormatterType.Soap: return new SoapFormatter();
            }
            throw new NotSupportedException();
        }

        /// <summary>
        /// 把对象序列化转换为字符串
        /// </summary>
        /// <param name="graph">可串行化对象实例</param>
        /// <param name="formatterType">消息格式编码类型(Soap或Binary型)</param>
        /// <returns>串行化转化结果</returns>
        /// <remarks>调用BinaryFormatter或SoapFormatter的Serialize方法实现主要转换过程。
        /// </remarks>    
        public static string SerializeObjectToString(object graph, FormatterType formatterType)
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                IRemotingFormatter formatter = GetFormatter(formatterType);
                formatter.Serialize(memoryStream, graph);
                Byte[] arrGraph = memoryStream.ToArray();
                return Convert.ToBase64String(arrGraph);
            }
        }
        public static string SerializeObjectToString(object graph)
        {
            return SerializeObjectToString(graph, DefaultFormatterType);
        }

        /// <summary>
        /// 把已序列化为字符串类型的对象反序列化为指定的类型
        /// </summary>
        /// <param name="serializedGraph">已序列化为字符串类型的对象</param>
        /// <param name="formatterType">消息格式编码类型(Soap或Binary型)</param>
        /// <typeparam name="T">对象转换后的类型</typeparam>
        /// <returns>串行化转化结果</returns>
        /// <remarks>调用BinaryFormatter或SoapFormatter的Deserialize方法实现主要转换过程。
        /// </remarks>
        public static T DeserializeStringToObject<T>(string graph, FormatterType formatterType)
        {
            Byte[] arrGraph = Convert.FromBase64String(graph);
            using (MemoryStream memoryStream = new MemoryStream(arrGraph))
            {
                IRemotingFormatter formatter = GetFormatter(formatterType);
                return (T)formatter.Deserialize(memoryStream);
            }
        }

        public static T DeserializeStringToObject<T>(string graph)
        {
            return DeserializeStringToObject<T>(graph, DefaultFormatterType);
        }
    }

    [Serializable]
    public class HttpRequestInfo
    {
        public HttpRequestInfo()
        {
            ContentData = new byte[0];
            CommData = new Dictionary<string, string>();
        }
        public byte[] ContentData { set; get; }
        public Action<HttpRequestInfo> Process { set; get; }
        public Dictionary<string, string> CommData { set; get; }

        public override string ToString()
        {
            string graph = SerializationHelper.SerializeObjectToString(this);
            return graph;
        }
        public static implicit operator HttpRequestInfo(string contentString)
        {
            return SerializationHelper.DeserializeStringToObject<HttpRequestInfo>(contentString);
        }
    }
}
View Code

相关文章:

  • 2021-12-26
  • 2022-12-23
  • 2021-12-10
  • 2021-07-18
  • 2022-02-20
  • 2021-08-03
  • 2021-09-22
  • 2021-07-14
猜你喜欢
  • 2022-12-23
  • 2021-10-08
  • 2021-06-22
  • 2022-03-02
  • 2021-04-19
  • 2021-09-05
相关资源
相似解决方案