Specified method is not supported

Coordinator
Oct 22, 2008 at 12:55 AM

The following is the message from yenyit:

Hi.  I'm doing some experiments with your DotNetZip component using an ASP.Net (2.x) page, and I'm getting an exception (Specified method is not supported) on the "zip.Save();" line.  The following is the source code of the test page:

<%@ Page Language="C#" Debug="true" %>
<%@ Import Namespace="System.Text" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="Ionic.Utils.Zip" %>
<%@ Import Namespace="System.Collections.Generic" %>
<script language="C#" runat="server">
public void Page_Load (Object sender, EventArgs e)
{
 Response.Clear();
 String ReadmeText= "This is a zip file dynamically generated at " + System.DateTime.Now.ToString("G");
 Response.ContentType = "application/zip";
 Response.AddHeader("content-disposition", "filename=test.zip");
 
 using (ZipFile zip = new ZipFile(Response.OutputStream)) {
   zip.AddFileFromString("Readme.txt", "", ReadmeText);
   zip.Save();
 }

 Response.End();
}
</script>


Could you please let me know what I've done wrong?  Thanks.
Coordinator
Oct 22, 2008 at 12:58 AM
Edited Oct 22, 2008 at 1:04 AM
I suspect that the breaking line is the one that calls ZipFile.AddFileFromString() and not ZipFile.Save().   

There was a breaking change in DotNetZip in v1.6.   Originally the name of the method for adding content from a string was called "AddStringAsFile". I shipped some early DLLs with that method in it.   Later I thought this was misleading and non-intuitive.  I changed the method name to AddFileFromString(). 

Is it possible that you have an older DLL for DotNetZip in the ASP.NET bin directory?   or in the GAC?

If your ASP.NET page is running against an older DLL, it would exhibit this problem.

Oct 22, 2008 at 9:50 PM
Thanks for your reply.  I am quite certain that the page is not using an older version of the DotNetZip DLL.  If I change the "zip.AddFileFromString" line from the source code above to:

zip.AddStringAsFile("Readme.txt", "", ReadmeText);

then I'll get a compiler error : 'Ionic.Utils.Zip.ZipFile' does not contain a definition for 'AddStringAsFile'

Also, if I change the "zip.AddFileFromString" line from the source code above to:

zip.AddFile("c:\\inetpub\\testing\\www2\\test.txt");

then I'll get the "Specified method is not supported" exception on the "zip.Save();" line again as before.
Oct 23, 2008 at 1:44 AM
Edited Oct 23, 2008 at 1:49 AM
I am having the same issue with the 1.6 release.

I just tried using the 1.5 dll and it works.

From the debug output the error looks to be in a call to HttpResponseStream.get_Position()
Coordinator
Oct 24, 2008 at 1:29 AM
Edited Oct 24, 2008 at 1:37 AM

Ah, thank you, that helps.

Yes, this looks like a bug in the ZipFile.Save() method.  I have reproduced it here. Sorry about that.   My unit tests do not include an ASP.NET runtime test.

Let me look into fixing it.

Coordinator
Oct 24, 2008 at 2:09 AM
This is fixed in change set 25482.  I also updated the binaries on the v1.6 release tab.  Thanks for reporting this.
May 1, 2009 at 7:26 PM
Edited May 4, 2009 at 1:57 PM
I'm getting the same error with version 1.7.  I'm using a WCF web service method GetFileStream which returns a Stream object because the machine the web service is on is a DMZ.  Here is the code I'm using.  It crashes on the bold line.

                Response.Clear();
                Response.ContentType = "application/zip";
                Response.AddHeader("content-disposition", "filename=Reports.zip");
                using (ZipFile zip = new ZipFile())
                {
                    foreach (string filepath in files_to_zip)
                    {
                        FileInfo file = new FileInfo(filepath);
                        Stream stream = mgsOps.GetFileStream(filepath);
                        zip.AddFileStream(file.Name, "", stream);
                    }
                    zip.Save(Response.OutputStream);
                }
                Response.End();

It's worth noting that before I moved the web service to the DMZ machine and could access files directly from the network, the bold line above worked successfully although I was creating the zip file a little differently.
Coordinator
May 4, 2009 at 4:56 PM
Mike, do you get a stacktrace?
can you post it?
May 4, 2009 at 5:24 PM
Hi Cheeso,

Thanks for the reply.  Here is the stack trace:

"   at System.ServiceModel.Dispatcher.StreamFormatter.MessageBodyStream.get_Length()\r\n   at Ionic.Zip.ZipEntry.FigureCompressionMethodForWriting(Int32 cycle)\r\n   at Ionic.Zip.ZipEntry.WriteHeader(Stream s, Int32 cycle)\r\n   at Ionic.Zip.ZipEntry.Write(Stream outstream)\r\n   at Ionic.Zip.ZipFile.Save()\r\n   at Ionic.Zip.ZipFile.Save(Stream outputStream)\r\n   at Reports.Download_click(Object sender, EventArgs e) in c:\\Inetpub\\wwwroot\\MGS2\\Reports.aspx.cs:line 300"
May 7, 2009 at 9:16 PM
Is there a possibility that the problem is in the zip.AddFileStream(file.Name, "", stream) line of code?  Could it be incorrectly creating the zip file causing it to be corrupt or something and the zip.Save(Response.OutuptStream) line has a problem with it?
Coordinator
May 7, 2009 at 9:44 PM
Edited Jan 10, 2010 at 3:56 PM

Hmmm,
Based on what I am seeing, the problem is that while trying to create the zip file and save it to Response.OutputStream,  DotNetZip is getting an error while reading the Length property on the passed-in stream (which is, I guess, the result of the GetFileStream() ) call. 

I still cannot tell what the error is.  Thanks for the stack trace; can you also provide the exact exception?  It could be a null pointer exception, or a method not supported exception, etc.  It's essential to know.

Can you help me better understand what you are doing in the code?  Here is my guess: In the context of an ASP.NET page, you are calling out to a remote web service using WCF.   The response from WCF contains one or more attachments?   And you are then using GetFileStream() to get the files associated to those attachments. 

Are you certain that the stream in question returned from GetFileStream() is non-null? 

I think your instinct that the problem might be with AddFileFromStream() is correct.  IF there is a problem with the stream, it will fail during the call to Save(), which is when the ZipFile (or bytestream) is created.
If the stream you pass in to AddFileFromStream() is null, the exception will happen upon Save(). 
And if there are other problems with the Stream, for example if it does not support the Length property, it will also fail only upon Save().  

Addendum: In v1.9, the ZipFile.AddFileFromString() method was renamed to ZipFile.AddEntry()

May 7, 2009 at 10:02 PM
Thanks for the response, Cheeso.  Your continued support of your product is truly appreciated.

It is a System.NotSupportedException: "Specified method is not supported."

It seems to get the stream successfully from the WCF service method.  When I check the Stream object, it is not null although some of the properties have a exceptions eg. Length    'stream.Length' threw an exception of type 'System.NotSupportedException'    long {System.NotSupportedException}.  When I check the Count property of the ZipFile object after I call the AddFileStream method, it does in fact increment. 

It seems then that the issue is how I'm creating the Stream object.  This is out of the scope of DotNetZip, but I'm wondering if you can tell me if there is anything wrong with the method I'm using:

        public Stream GetFileStream(string filepath)
        {
            return File.OpenRead(filepath);
        }

Coordinator
May 8, 2009 at 1:07 AM

Geez, I don't know what to tell you. 

I thought that GetFileStream() was a method on one of the WCF support classes, but your reply seems to indicate that GetFileStream() is something you wrote.  And furthermore it is very simple.

What do you mean "it seems to get the stream successfully from the WCF service method" ?    I don't see where WCF is used at all.   I think I still don't understand what you are doing.

Are you using ASP.NET and WCF in the same app?  Or are you saying that there are two separate apps, and in the first one, using WCF, you can successfully use DotNetZip, but in the second app, using ASP.NET, then you cannot successfully use DotNetZip. ????   I am guessing here.

If I were debugging this I would check, wthin GetFileStream(), that I can read the file and get the Length and so on.  Try to separate it from any DotNetZip issues. 

I don't see anything wrong with your method.  Could there be a permissions/security issue?   Also, for a stream returned in that way, you need to be sure to Dispose() it when you finish using it. 

Taking one step back, I don't understand why you would use GetFileStream() and AddFileFromStream.  If GetFileStream just opens the file, why not just call ZipFile.AddFile() passing the name of the file - it seems simpler.

 

 

May 8, 2009 at 2:19 PM

I have a WCF web service on one machine and a website that uses the WCF service on another machine.  The WCF accomplishes all of the "business" processing and just passes results required to load the page back to the website (on another machine).  I was originally using the following code - which works - to create the zip file:

                Response.Clear();
                Response.ContentType = "application/zip";
                Response.AddHeader("content-disposition", "filename=Reports.zip");
                using (ZipFile zip = new ZipFile())
                {
                    foreach (string filepath in files_to_zip)
                    {
                        FileInfo myFile = new FileInfo(filepath);
                        zip.AddFile(myFile.FullName, "");
                    }
                    zip.Save(Response.OutputStream);
                }
                Response.End();

This was in the testing/creation phase of the website, however.  It is ultimately going to be moved to another machine which is in a DMZ and does not have access to the network location where the files that I need to zip are located.  This is where the web service comes in.  I'm now trying to use the web service to pass a stream of data from the file to be zipped rather than the location of the file to be zipped so the website doesn't need direct access to the file.  This is why I'm trying now using AddFileStream() rather than AddFile().

 

I've altered my GetFileStream() method on the web service to be the following to help debugging:

        public Stream GetFileStream(string filepath)
        {
            Stream stream = File.OpenRead(filepath);
            return stream;
        }

When I step through it  in debug, stream.Length is defined when I try a file.  The value is of type long and has a value of 424448. 

This is what I meant when I said "it seems to get the stream successfully from the WCF service method".  However, when I step further to see what the value of the Length property of the Stream object is on the website that I got back from the web service, there is an exception for the Length property.

As another test, I decided to move the GetFileStream() to my web site just to rule out the web service being the issue.  To my amazement, when the Stream object was passed back from the GetFileStream() method, now on the same aspx page, to the zip for loop, it did have a valid Length property value.  As I continued to step through this time, the exception below occurred at the Response.End() line;

{Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.}    System.Exception {System.Threading.ThreadAbortException}

"   at System.Threading.Thread.AbortInternal()\r\n   at System.Threading.Thread.Abort(Object stateInfo)\r\n   at System.Web.HttpResponse.End()\r\n   at Reports.Download_click(Object sender, EventArgs e) in c:\\Inetpub\\wwwroot\\MGS2\\Reports.aspx.cs:line 303"

HOWEVER, a prompt to save/open the zip file appeared and the zip file did contain the expected files!  The exception didn't stop the program so if you're not debugging, the program functions normally, correctly zipping the files.

Thoughts?????????

Coordinator
May 8, 2009 at 3:03 PM

OK, things are clearer now.

As for the ThreadAbortException, I think that can occur when you have a debug session that exceeds the timeout value for the HTTP protocol.  If you are working in your debugger for a long time, the HTTP session can end, so Response.End() will fail, even though the response really did get all sent out.  So I wouldn't worry about that.

On the NotSupportedException when trying to read the Length property - I see that MessageBodyStream (which is the type you get back from WCF) does not support Seek nor Length.  

Thinking about it, DotNetZip should work with a non-seekable stream as input. It tries to get the length of the stream, but it shouldn't fail if that is not possible.  So I think this is a bug in DotNetZip.  If you don't mind I'd like to prepare a fix and ask you to test it.

 

 

 

Coordinator
May 8, 2009 at 3:05 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Coordinator
May 8, 2009 at 3:43 PM

To get the fix, I'd like you to try out either v1.8.3.1, or v1.7.2.18.