WebRequest 实现数据的即时抛转
之前我们和另外一个系统进行数据交互的时候,采用的方式为:我们会把数据按照约定的格式存放在一个用于数据交互的数据表中,然后各自会有一个Job每隔几分钟到此Table中获取最新的数据(之所以采取此种交互方式,主要是两个系统分别在不同的网段,所以只能把数据先放在中间临时的大家都可以直接的DB中交互)。这种方式其实也可以很好的工作。但是会有一个问题:如果A系统的数据B系统马上要获取,由于job定时执行的缘故,此时不得不人工手动执行job,才能是数据立即抛转到B系统,也就是说在紧急情况下,此种做法还是会有一个时间延迟的问题存在。
今天要说的是:采用Http WebRequest的方式,实现了一个所谓的Dispatch Service的基于Http的简单数据转发服务。使得A系统如果有数据更新,就即时的把数据抛给B系统,抛转的数据格式可以是File,也可以是String,Xml等等。
基本架构说明:
说明:
1.从client端到Dispatch Server再到Target Client,都通过【msgid】串起来。如果Target 端想要Client端传递什么数据,只需协商一个MsgID,并在Dispatch Service端配置相关信息即可。
2.server端有一个关键的xml配置档案,id即为msgid,同时配置此msgid的数据要server的哪个Handler执行,并把执行结果抛砖到哪个地址去!
3.在server的xml配置档案中,也可以配置,client端传递的信息的处理方式:直接抛转;处理后再抛转;直接处理不做抛转。
4.相关的数据抛转都采用WebRequest的方式进行,接收放利用HttpHandler方式进行处理;
5.如果要在server端处理处理,可把执行处理的方法封装成Dll,而后在配置档案配置,待需要时动态呼叫执行。
先看下Server端的config档案的定义:
<DispatchServices>
<message id="TransferFTPFile" type="http" filetype="file" onlysend="Y">
<source from="http://myserver/DispatchService/FileHandler.ashx" to="http://localhost/ReceiveDataHandler/FileHandler.ashx" />
<dll id="" namespace="" typename="" methodname=""/>
<mailto>jiaxin606@163.com</mailto>
</message>
<message id="TransferStringTest" type="http" filetype="str" onlysend="Y">
<source from="http://myserver/DispatchService/StringHandler.ashx" to="http://localhost/ReceiveDataHandler/StringHandler.ashx" />
<dll id="" namespace="" typename="" methodname=""/>
<mailto>jiaxin606@163.com</mailto>
</message>
<message id="TransferXmlTest" type="http" filetype="xml" onlysend="Y">
<source from="http://myserver/DispatchService/XMLHandler.ashx" to="http://localhost/ReceiveDataHandler/XmlHandler.ashx" />
<dll id="" namespace="" typename="" methodname=""/>
<mailto>jiaxin606@163.com</mailto>
</message>
<message id="TransferXmlTest" type="dll" filetype="xml" onlysend="N">
<source from="http://myserver/DispatchService/XMLHandlerWithDll.ashx" to="http://localhost/ReceiveDataHandler/XmlHandler.ashx" />
<dll id="" namespace="" typename="" methodname=""/>
<mailto>jiaxin606@163.com</mailto>
</message>
</DispatchServices>
数据发起方 Client端:
{
string uri = "http://myserver/DispatchService/ServerUriHandler.ashx";
WebRequest request = WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.Headers.Add("filename", Convert.ToBase64String(Encoding.UTF8.GetBytes(fileName)));
request.Headers.Add("msgid", Convert.ToBase64String(Encoding.UTF8.GetBytes(msgid)));
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
WebResponse response = request.GetResponse();
dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
dataStream.Close();
reader.Close();
response.Close();
}
说明:Client发送msgid,Data[](不管是文件还是字串,全部转为byte[]),filename(如果是文件的话)给Server特定URI.
Server端:
{
/// <summary>
/// Summary description for $codebehindclassname$
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class FileHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
Stream stream = context.Request.InputStream;
if (stream == null || stream.Length <= 0)
{
context.Response.Write("没有获得有效的信息");
return;
}
string fileName = Encoding.UTF8.GetString(Convert.FromBase64String(context.Request.Headers["filename"]));
string msgid = Encoding.UTF8.GetString(Convert.FromBase64String(context.Request.Headers["msgid"]));
byte[] data = new byte[stream.Length];
stream.Read(data, 0, Convert.ToInt32(stream.Length));
string guid = Guid.NewGuid().ToString();
IFileHandler dal = new FileTransfer();
//本地存储
string responseCode = dal.ExecuteReveive(data, guid, fileName, msgid);
//返回执行结果
context.Response.Write(responseCode);
//异步转发
object[] obj = new object[] { data, guid };
Thread thread = new Thread(new ParameterizedThreadStart(dal.ExecuteSend));
thread.Start(obj);
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
说明:server端拿到数据后首先在server备份,备份成功后开始转发。可以看到在server端有几个不同的handler,分别处理不同的数据类型:file,string ,xml.
{
/// <summary>
/// 接收调用端传递过来的信息
/// </summary>
/// <param name="context">传递的信息</param>
/// <param name="guid">guid 要和ExecuteSend的guid一致</param>
/// <returns></returns>
string ExecuteReveive(byte[] data, string guid, string fileName,string msgid);
void ExecuteSend(object obj);
}
FileTransfer的处理:
{
public class FileTransfer : IFileHandler
{
/// <summary>
/// 接收调用端传递过来的信息
/// </summary>
/// <param name="context">传递的信息</param>
/// <param name="guid">guid 要和ExecuteSend的guid一致</param>
/// <returns></returns>
public string ExecuteReveive(byte[] data, string guid, string fileName, string msgid)
{
string filePath = string.Empty;
string returnInfo = "OK";
//本地存储
try
{
string base64Str = Encoding.UTF8.GetString(data);
byte[] origin = Convert.FromBase64String(base64Str);
//本地Log存储路径
string path = System.Configuration.ConfigurationManager.AppSettings["filepath"].ToString();
filePath = path + DateTime.Now.ToString("yyyyMMddHHmmss") + "_" + Path.GetFileName(fileName);
File.WriteAllBytes(filePath, origin);
}
catch (Exception ex)
{
Common.WriteLog("Source:" + ex.GetBaseException().Source + "--Message:" + ex.GetBaseException().Message +" Guid:"+guid);
Common.SendMail("本地存储失败--GUID:" + guid + "ErrorMsg:" + ex.Message,msgid);
returnInfo = "Error:" + ex.Message + "\r\n filepath" + filePath;
}
try
{
//备份本地存储
Common.WriteLogInfo(filePath, guid, FileType.file.ToString(), msgid);
}
catch (Exception ex)
{
Common.WriteLog("Source:" + ex.GetBaseException().Source + "--Message:" + ex.GetBaseException().Message+" Guid:"+guid);
Common.SendMail("备份文件本地存储的路径失败--GUID:" + guid + "ErrorMsg:" + ex.Message,msgid);
returnInfo = ex.Message;
}
GC.Collect();
return returnInfo;
}
/// <summary>
/// 执行转发
/// </summary>
/// <param name="obj">要转发的信息</param>
public void ExecuteSend(object obj)
{
object[] resultObj = obj as object[];
byte[] byteArray = resultObj[0] as byte[];
string guid = resultObj[1] as string;
string msgid=string.Empty;
try
{
Entity.BasicInfo info = Common.GetExecuteType(guid);
msgid = info.MsdID;
string type = info.Type;
string fullName = ConfigurationManager.AppSettings["Dll"] + "\\" + info.DllName;
if (type == "http")
{
if (info.OnlySend != "Y")
{
//dll 处理后,得到要转发的byteArray
object objInfo= Common.ExecuteDllMethod(fullName, info.TypeName, info.MethodName, new string[] { });
}
string uri = info.UriTo;
string fileName = info.FileName;
Common.BeginRequest(uri, byteArray, fileName, msgid);
}
else if (type == "dll" && info.UriTo=="")
{
//动态呼叫Dll中的方法,对数据进行本地处理,不做转发动作
Common.ExecuteDllMethod(fullName, info.TypeName, info.MethodName, new string[] { });
}
//更改flag
Common.UpdateFlagForSend(guid);
}
catch (Exception ex)
{
Common.SendMail("文件转发失败--GUID:\t" + guid + "ErrorMsg:" + ex.Message,msgid);
Common.WriteLog("Source:" + ex.GetBaseException().Source + "\t" + "Message:" + ex.GetBaseException().Message+" Guid:"+guid);
}
GC.Collect();
}
}
}
在Server端的备份信息这里依然采取的Xml方式进行:文件记录文件路径,字串直接写入xml.每笔记录用Guid进行标记。在要查看抛转的log信息时,可读取这些档案,如果需要在Server端对数据重新抛转,就可以利用这些Guid查找唯一。
Log_Info.xml
<log_info>
<message guid="wqsdjfsf0909sfsfs998" filetype="file" msgid="" hassend="Y">
<data>D:\</data>
</message>
</log_info>
这样,架起来的Service,只要经过简单的配置就可以实现从Client端到Target端的数据即时抛转。