0

I've been searching for a few days not to try and find why this is happening.

My WCF service is .net 4.0. I'm using sevinzipsharp as a wrapper for the 7zip libraries.

I have tried a number of things on both the client and server sides and found that the actual methods being used for the compression are not the issue. The issue is definitely related to the streaming process, because while debugging i can rout the server to the original compressed file rather than the streamed file and the archive is unpacked fine.

My reason for using compression at this point in time is to transfer multiple files in a package to my WCF service with a single call. If you can help me to resolve the issue I'm having with my current method or have a completely different suggestion as to how I can get multiple files to the server in the same call I would be very appreciative.

IService Code:

<ServiceContract()>
Public Interface IService

  <OperationContract()>
  Function start_Archive_Job(ByVal file_stream As Stream) As Boolean

IService Implementation:

 Public Function start_Archive_Job(ByVal file_stream As Stream) As Boolean _
    Implements DDSArchiveService.IService.start_Archive_Job

    Dim f_zip As String = "C:\file_dest.7z"

    //' define a buffer and bytes read var
    Dim n As Integer
    Dim buf(1024) As Byte

    n = strm.Read(buf, 0, buf.Length)
    If n = 0 Then Throw New File_Upload_Exception()

    //' use a filestream to create the serverside file
    Using fs As New FileStream(f_zip, FileMode.Create, FileAccess.Write, FileShare.None)
        //' while the number of bytes read is not 0 and no exception occurrs continue to read from input and write to output
        While n > 0
            If Not n = buf.Length Then
                Dim nbuf(n) As Byte
                Array.Copy(buf, nbuf, n)
                fs.Write(nbuf, 0, nbuf.Length)
            Else
                fs.Write(buf, 0, buf.Length)
            End If

            Try
                n = strm.Read(buf, 0, buf.Length)
            Catch ex As Exception
                Exit While
            End Try
        End While
    End Using

    Dim decompressor As SevenZipExtractor
    Try
        //' check if 7zip is installed, if not look to the assemply location for the lib file
        Dim dllPath As String
        Dim sevenZ_reg As RegistryKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\7-zip")
        If Not sevenZ_reg Is Nothing Then
            dllPath = sevenZ_reg.GetValue("Path").ToString
        Else
            dllPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)
        End If

        SevenZipExtractor.SetLibraryPath(dllPath & "\7z.dll")
        decompressor = New SevenZipExtractor(f_zip.7z)

        decompressor.ExtractArchive(str_dsn_dir)
    Catch ex As Exception
        ' write to log
        Throw ex
    End Try

The decompressor.ExtractArchive(str_dsn_dir) call always seems to throw an exception that asks me if the file is encrypted and if the password is wrong, or tells me that the file may not have a signature that seven zip recognizes, so Tar was assumed.

The client code is:

Sub Main()

    Dim binding As New System.ServiceModel.BasicHttpBinding()
    binding.SendTimeout = New TimeSpan(0, 5, 0)

    Dim webService As New ServiceReference1.ServiceClient(binding, New System.ServiceModel.EndpointAddress("myuri"))

    Dim source As String = "C:\test_source"
    Dim output As String = "C:\Zipped.7z"
    Dim dllPath As String
    //' check if 7zip is installed, if not look to the assemply location for the lib file
    Dim sevenZ_reg As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\7-zip")
    If Not sevenZ_reg Is Nothing Then
        dllPath = sevenZ_reg.GetValue("Path").ToString
    Else
        dllPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)
    End If

    SevenZipExtractor.SetLibraryPath(dllPath & "\7z.dll")
    Dim compressor As New SevenZipCompressor
    compressor.ArchiveFormat = OutArchiveFormat.SevenZip
    compressor.CompressionMode = CompressionMode.Create
    compressor.CompressionMethod = CompressionMethod.Default
    compressor.TempFolderPath = System.IO.Path.GetTempPath()
    compressor.CompressDirectory(source, output)

    Dim fs As New System.IO.FileStream(output, IO.FileMode.Open, IO.FileAccess.Read)

     Try
        webService.start_Archive_Job(fs)
        fs.Dispose()
    Catch ex As Exception
        fs.Dispose()
    End Try
 End Sub

Again, help with this current issue, or ideas on how to package multiple files for a single call to a WCF web service into 1 stream and have them come out clean on the other end are acceptable and very appreciated.

  • Cant you pass a byte[][] parameter to the WCF call using NetDataContractSerializer or a different formatter ?. I personally use ProtoBuf serialization in my WCF formatter where size is an issue (heres a standard comparison of sizes http://marcgravell.blogspot.co.uk/2009/09/protobuf-net-vs-netdatacontractserializ.html) alternatively this site shows the MTOM protocol with compression to transfer large files (http://nirajrules.wordpress.com/2009/08/03/mtom-vs-streaming-vs-compression-%E2%80%93-large-attachments-over-wcf/). I'm not sure this is what you are after, thus the Comment not Answer. – PhillipH May 30 '14 at 21:05
  • Phillip, thanks for your reply and suggestions. I've found the issue I was having with this code, and for now it will work since we are in a time crunch at the end of our sprint. I will be looking into your suggestions to see if perhaps this might suit our needs better in the long term. – SaltpeterBoom May 31 '14 at 01:22

1 Answers1

1

I have found the answer to why the posted code was not working. The code in my OP was so close to the many examples that I found across the web, that it wasn't until we started trouble shooting with plain text files that we found recreating the file on the server side was inserting ASCII null characters at the end of nearly every buffer.

I found according to this post Creating a byte array from a stream I found that the Stream.Read method may not always read the full length of the buffer, so changing the code from fs.Write(buf, 0, buf.Length) to fs.Write(buf, 0, n) seems to have fixed the issue I was having.

If this post didn't help you, keep digging. There's a lot of information on the web about WCF in general and using the streaming method in particular.

Community
  • 1
  • 1