Wcf 如何将大文件从MS Word加载项(VBA)传输到Web服务器? 概述
我有一个用VBA(Visual Basic for Applications)编写的Microsoft Word加载项,它将文档及其所有相关内容(嵌入式媒体)压缩到zip存档中。创建zip存档后,它将文件转换为字节数组,并将其发布到ASMXWeb服务。这主要是有效的 问题 我遇到的主要问题是将大型文件传输到网站。我可以成功上传一个40MB左右的文件,但不是140MB(超时/一般故障) 第二个问题是,如果zip归档文件太大,则在VBScript Word加载项中构建字节数组可能会因客户端计算机内存不足而失败 潜在解决方案 我正在考虑以下选项,并期待任何一个选项或任何其他建议的反馈 选择一 在客户端(MS Word VBA)上打开一个文件流,一次读取一个“块”,并传输到ASMX web服务,后者将“块”组装到服务器上的文件中 这样做的好处是不会向应用程序添加任何其他依赖项或组件,我只会修改现有的功能。(依赖关系越少越好,因为此解决方案应适用于各种服务器环境,并且相对容易设置。) 问题:Wcf 如何将大文件从MS Word加载项(VBA)传输到Web服务器? 概述,wcf,vba,asmx,large-files,data-transfer,Wcf,Vba,Asmx,Large Files,Data Transfer,我有一个用VBA(Visual Basic for Applications)编写的Microsoft Word加载项,它将文档及其所有相关内容(嵌入式媒体)压缩到zip存档中。创建zip存档后,它将文件转换为字节数组,并将其发布到ASMXWeb服务。这主要是有效的 问题 我遇到的主要问题是将大型文件传输到网站。我可以成功上传一个40MB左右的文件,但不是140MB(超时/一般故障) 第二个问题是,如果zip归档文件太大,则在VBScript Word加载项中构建字节数组可能会因客户端计算机内存
- 是否有这样做的例子或任何推荐的技术(在VBA中的客户机上或在C#/VB.NET中的web服务中)
- WCF是否可靠地支持这种性质的大型文件传输?如果是,这涉及到什么?有什么资源或例子吗李>
- 您能从VBA调用WCF服务吗?有什么例子吗
至于VBA电话,我不是该领域的专家,因此我没有关于它的任何信息 我最终实现了原始问题中提到的选项一 我在VBA中“分块”文件,并将每个“分块”传输到web服务。我将解决方案的VBA部分基于以下代码:。但是,我没有复制到文件系统,而是将其发送到服务器 代码:VBA Land 下面是创建文件块的(fugly)VBA代码:
Function CopyFileByChunk(fileName As String, sSource As String) As Boolean
Dim FileSize As Long, OddSize As Long, SoFar As Long
Dim Buffer() As Byte, f1 As Integer, ChunkSize As Long
On Error GoTo CopyFileByChunk_Error
f1 = FreeFile: Open sSource For Binary Access Read As #f1
FileSize = LOF(f1)
If FileSize = 0 Then GoTo Exit_CopyFileByChunk ' -- done!
ChunkSize = 5505024 '5.25MB
OddSize = FileSize Mod ChunkSize
Dim index As Integer
index = 0
If OddSize Then
ReDim Buffer(1 To OddSize)
Get #f1, , Buffer
index = index + 1
SoFar = OddSize
If UploadFileViaWebService(Buffer, fileName, index, SoFar = FileSize) Then
g_frmProgress.lblProgress = "Percent uploaded: " & Format(SoFar / FileSize, "0.0%")
Debug.Print SoFar, Format(SoFar / FileSize, "0.0%")
DoEvents
Else
GoTo CopyFileByChunk_Error
End If
End If
If ChunkSize Then
ReDim Buffer(1 To ChunkSize)
Do While SoFar < FileSize
Get #f1, , Buffer
index = index + 1
SoFar = SoFar + ChunkSize
If UploadFileViaWebService(Buffer, fileName, index, SoFar = FileSize) Then
g_frmProgress.lblProgress = "Percent uploaded: " & Format(SoFar / FileSize, "0.0%")
Debug.Print SoFar, Format(SoFar / FileSize, "0.0%")
DoEvents
Else
GoTo CopyFileByChunk_Error
End If
Loop
End If
CopyFileByChunk = True
Exit_CopyFileByChunk:
Close #f1
Exit Function
CopyFileByChunk_Error:
CopyFileByChunk = False
Resume Exit_CopyFileByChunk
End Function
/// <summary>
/// Merges each file chunk into one complete zip archive.
/// </summary>
/// <param name="directoryPath">The full path to the directory.</param>
/// <param name="fileName">Name of the file.</param>
/// <param name="finalChunkIndex">The index of the last file chunk.</param>
private static void MergeFiles(string directoryPath, string fileName, int finalChunkIndex)
{
var fullNewFilePath = Path.Combine(directoryPath, fileName);
using (var newFileStream = File.Create(fullNewFilePath))
{
for (int i = 1; i <= finalChunkIndex; i++)
{
using (var chunkFileStream = new FileStream(AddIndexToFileName(fullNewFilePath, i), FileMode.Open))
{
var buffer = new byte[chunkFileStream.Length];
chunkFileStream.Read(buffer, 0, (int)chunkFileStream.Length);
newFileStream.Write(buffer, 0, (int)chunkFileStream.Length);
}
}
}
}
函数CopyFileByChunk(文件名为字符串,sSource为字符串)为布尔值
Dim FileSize为Long,OddSize为Long,SoFar为Long
Dim Buffer()作为字节,f1作为整数,ChunkSize作为长度
On错误转到CopyFileByChunk\u错误
f1=FreeFile:打开源进行二进制访问,读取为#f1
FileSize=LOF(f1)
如果FileSize=0,则转到退出\u CopyFileByChunk'--完成!
ChunkSize=5505024'5.25MB
OddSize=文件大小Mod ChunkSize
将索引设置为整数
索引=0
如果大小不一样的话
ReDim缓冲区(1到OddSize)
获取#f1,缓冲区
索引=索引+1
SoFar=奇数
如果通过WebService上传文件(缓冲区、文件名、索引、SoFar=FileSize),则
g_frmProgress.lblProgress=“上传百分比:”&格式(SoFar/FileSize,“0.0%”)
调试。打印SoFar,格式(SoFar/FileSize,“0.0%”)
多芬特
其他的
转到CopyFileByChunk\u错误
如果结束
如果结束
如果是大的话
ReDim缓冲区(1到ChunkSize)
在当前<文件大小时执行
获取#f1,缓冲区
索引=索引+1
SoFar=SoFar+ChunkSize
如果通过WebService上传文件(缓冲区、文件名、索引、SoFar=FileSize),则
g_frmProgress.lblProgress=“上传百分比:”&格式(SoFar/FileSize,“0.0%”)
调试。打印SoFar,格式(SoFar/FileSize,“0.0%”)
多芬特
其他的
转到CopyFileByChunk\u错误
如果结束
环
如果结束
CopyFileByChunk=True
退出\u CopyFileByChunk:
关闭#f1
退出功能
CopyFileByChunk\u错误:
CopyFileByChunk=False
恢复退出\u CopyFileByChunk
端函数
以下是将块上载到服务器的引用VBA方法:
Public Function UploadFileViaWebService(dataChunk() As Byte, fileName As String, index As Integer, lastChunk As Boolean) As Boolean
On Error GoTo ErrHand
Dim blnResult As Boolean
blnResult = False
'mdlConvert.SetProgressInfo "Connecting to the web server:" & vbNewLine & _
DQUOT & server_title() & DQUOT
If InternetAttemptConnect(0) = 0 Then
On Error Resume Next
Dim strSoapAction As String
Dim strXml As String
strXml = "<?xml version=""1.0"" encoding=""utf-8""?>" & _
"<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">" & _
"<soap:Body>" & _
"<UploadZipFile xmlns=""http://something.com/"">" & _
"<zipBytes></zipBytes>" & _
"<index>" & index & "</index>" & _
"<isLastChunk>" & IIf(lastChunk, 1, 0) & "</isLastChunk>" & _
"</UploadZipFile>" & _
"</soap:Body>" & _
"</soap:Envelope>"
Dim objXmlhttp As Object
Dim objDom As Object
Set objXmlhttp = New MSXML2.xmlhttp
' Load XML
Set objDom = CreateObject("MSXML2.DOMDocument")
objDom.LoadXML strXml
'insert data chunk into XML doc
objDom.SelectSingleNode("//zipBytes").dataType = "bin.base64"
objDom.SelectSingleNode("//zipBytes").nodeTypedValue = dataChunk
' Open the webservice
objXmlhttp.Open "POST", webServiceUrl, False
' Create headings
strSoapAction = "http://something.com/UploadZipFile"
objXmlhttp.setRequestHeader "Content-Type", "text/xml; charset=utf-8"
objXmlhttp.setRequestHeader "SOAPAction", strSoapAction
' Send XML command
objXmlhttp.send objDom.XML
' Get all response text from webservice
Dim strRet
strRet = objXmlhttp.responseText
' Close object
Set objXmlhttp = Nothing
Set objDom = Nothing
'get the error if any
Set objDom = CreateObject("MSXML2.DOMDocument")
objDom.LoadXML strRet
Dim isSoapResponse As Boolean
isSoapResponse = Not (objDom.SelectSingleNode("//soap:Envelope") Is Nothing)
Dim error As String
If Not isSoapResponse Then
error = "Woops"
Else
error = objDom.SelectSingleNode("//soap:Envelope/soap:Body/soap:Fault/faultstring").text
End If
If error <> "" Then
ShowServerError error, True
blnResult = False
Else
Err.Clear 'clear the error caused in the XPath query above
blnResult = True
End If
'close dom object
Set objDom = Nothing
Else
GetErrorInfo "UploadFileViaWebService:InternetCheckConnection"
End If
ErrHand:
If Err.Number <> 0 Then
ShowError Err, "UploadFileViaWebService"
blnResult = False
End If
UploadFileViaWebService = blnResult
End Function
Public函数UploadFileViaWebService(dataChunk()作为字节,fileName作为字符串,index作为整数,lastChunk作为布尔值)作为布尔值
在错误上走错
Dim blnResult为布尔值
blnResult=False
“mdlConvert.SetProgressInfo”连接到web服务器:”&vbNewLine&_
DQUOT&server_title()&DQUOT
如果InternetAttemptConnect(0)=0,则
出错时继续下一步
作为字符串的Dim strSoapAction
将strXml设置为字符串
strXml=”“&_
"" & _
"" & _
"" & _
"" & _
索引(&index&)_
&IIf(lastChunk,1,0)&&_
"" & _
"" & _
""
Dim objXmlhttp作为对象
作为对象的Dim objDom
设置objXmlhttp=New MSXML2.xmlhttp
'加载XML
设置objDom=CreateObject(“MSXML2.DOMDocument”)
objDom.LoadXML strXml
'将数据块插入XML文档
objDom.SelectSingleNode(//zipBytes”).dataType=“bin.base64”
objDom.SelectSingleNode(“//zipBytes”).nodeTypedValue=dataChunk
'打开Web服务
objXmlhttp.Open“POST”,webServiceUrl,False
'创建标题
strSoapAction=”http://something.com/UploadZipFile"
objXmlhttp.setRequestHeader
/// <summary>
/// Writes the contents of the given <paramref name="stream"/> into a file at <paramref name="newFilePath"/>.
/// </summary>
/// <param name="stream">The stream to write to the given file</param>
/// <param name="newFilePath">The full path to the new file which should contain the contents of the <paramref name="stream"/></param>
public static void WriteStreamToFile(Stream stream, string newFilePath)
{
using (FileStream fs = File.OpenWrite(newFilePath))
{
const int BlockSize = 1024;
var buffer = new byte[BlockSize];
int numBytes;
while ((numBytes = stream.Read(buffer, 0, BlockSize)) > 0)
{
fs.Write(buffer, 0, numBytes);
}
}
}
/// <summary>
/// Merges each file chunk into one complete zip archive.
/// </summary>
/// <param name="directoryPath">The full path to the directory.</param>
/// <param name="fileName">Name of the file.</param>
/// <param name="finalChunkIndex">The index of the last file chunk.</param>
private static void MergeFiles(string directoryPath, string fileName, int finalChunkIndex)
{
var fullNewFilePath = Path.Combine(directoryPath, fileName);
using (var newFileStream = File.Create(fullNewFilePath))
{
for (int i = 1; i <= finalChunkIndex; i++)
{
using (var chunkFileStream = new FileStream(AddIndexToFileName(fullNewFilePath, i), FileMode.Open))
{
var buffer = new byte[chunkFileStream.Length];
chunkFileStream.Read(buffer, 0, (int)chunkFileStream.Length);
newFileStream.Write(buffer, 0, (int)chunkFileStream.Length);
}
}
}
}