之前我们和另外一个系统进行数据交互的时候,采用的方式为:我们会把数据按照约定的格式存放在一个用于数据交互的数据表中,然后各自会有一个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档案的定义:
代码
<?
xml version="1.0" encoding="utf-8"
?>
<
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
>
[email protected]
</
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
>
[email protected]
</
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
>
[email protected]
</
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
>
[email protected]
</
mailto
>
</
message
>
</
DispatchServices
>
数据发起方 Client端:
代码
private
void
Send(
string
fileName,
string
msgid,
byte
[] byteArray)
{
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端:
代码
namespace
DispatchService
{
///
<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.
代码
public
interface
IFileHandler
{
///
<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的处理:
代码
namespace
DispatchService.DispatchLib
{
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
<?
xml version="1.0" encoding="utf-8"
?>
<
log_info
>
<
message
guid
="wqsdjfsf0909sfsfs998"
filetype
="file"
msgid
=""
hassend
="Y"
>
<
data
>
D:\
</
data
>
</
message
>
</
log_info
>
这样,架起来的Service,只要经过简单的配置就可以实现从Client端到Target端的数据即时抛转。