Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Running WinZip Process on WebServer

Status
Not open for further replies.

Meleagant

Programmer
Aug 31, 2001
166
US
All,

Having a little trouble zipping files together on the server in preparation for download. The user is presented with a web tree containing items for download. The user selects the reports they want and then I get to zip then up on the server and download the file. This all started when users were trying to download 20-30 reports and the limitations of adding items to the header. For example: Response.AddHeader("Content-Disposition", "attachment; filename=""" & filename & """"); can only download one file, I have to pop open a new window for each file!

So here is the code which runs fine from my localhost (eval version of winzip installed). But not when running from the web serser (Full verison of winzip installed)

I thought by calling winzip32.exe from the server side code would open winzip on the server. Could I be running into a permissions issue?

Code:
    Protected Sub wibZip_Click(ByVal sender As Object, ByVal e As Infragistics.WebUI.WebDataInput.ButtonEventArgs) Handles wibZip.Click

        lblErrorText.Text = ""

        Dim igNode As Infragistics.WebUI.UltraWebNavigator.Node
        Dim fileName As String = ""
        Dim filePath As String = ""
        Dim fullPath As String = ""
        Dim fileText As String = ""

        Dim UserId As String = Session.Item("UserId").ToString.Trim
        Dim outFileName As String = String.Format("{0}_{1}", UserId, Date.Now.ToString("yyyyMMddHHmmss"))
        Dim fileArray As New ArrayList

        If uwtRepository.CheckedNodes.Count = 0 Then
            lblErrorText.Text = "Please select at least one file"
            Exit Sub
        End If

        For Each igNode In uwtRepository.CheckedNodes
            If Not String.IsNullOrEmpty(igNode.Tag) Then
                fullPath = igNode.Tag.ToString
                fileName = fullPath.Substring(fullPath.LastIndexOf("\") + 1)
                filePath = fullPath.Substring(0, fullPath.LastIndexOf("\"))

                If File.Exists(String.Format("\\XXX.X.X.XX\M\dir\{0}", fullPath)) Then
                    fileText &= String.Format("\\XXX.X.X.XX\M\dir\{0}{1}", fullPath, vbCrLf)
                End If
            End If
        Next

        File.AppendAllText(String.Format("c:\{0}.txt", outFileName), fileText)

        'winzip32 [-min] action [options] filename[.zip] files 
        Dim startInfo As System.Diagnostics.ProcessStartInfo
        Dim pStart As New System.Diagnostics.Process

        startInfo = New System.Diagnostics.ProcessStartInfo("\\WebServer\c$\Program Files\WinZip\WinZip32.Exe")
        startInfo.Arguments = String.Format("-a -p -ex {0}.zip @{0}.txt", String.Format("c:\{0}", outFileName))

        startInfo.WindowStyle = Diagnostics.ProcessWindowStyle.Maximized
        'pStart.PriorityClass = Diagnostics.ProcessPriorityClass.High

        pStart.StartInfo = startInfo
        pStart.Start()

    End Sub

* Sine scientia ars nihil est
* Respondeat superior
 
how is it "not running"?
is it failing silently (no exception)?
if so do you have an exception handling in place which would swallow the exception?
if not, or if your logging the exception what does the type/message/stack trace say?

the first place I would start is the permissions issue to winzip. I would think iis/asp.net would prevent this access by default due to security risks.

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
Sorry when I said failed, I meant that the page just hangs. No errors, nothing sent to the application error handler in the global.asax page. I haven't had the patience to see what happens if I didn't close the browser window. Probably would just go to "Page can not be displayed."


* Sine scientia ars nihil est
* Respondeat superior
 
you need to let if fail before abandoning the thread. there is another problem I see with your code. [tt]c:\{0}.txt[/tt] will not work on the server. the files should be created within the virtual directory. otherwise IIS cannot access it without modified permissions.

1st you need to make sure the zipping process is executing on the server.
create a simple console app to zip 2 or 3 small files. copy the executable to the server and run it. if that works it's a permissions issue.

I would refactor the code as well so its easier to read and seperates the concerns.
Code:
protected void wibZip_Click(object sender, eventargs e)
{
   List<string> files= new List<string>();
   foreach(Node node in uwtRepository.CheckedNodes)
   {
      if(string.IsNullOrEmpty(node.Tag))
         continue;
     files.Add(node.Tag);
   }
   new FileCompiler(Server.MapPath("~/Zip")).Compile(files);
}
Code:
public class FileCompiler
{
   string baseDirectory;

   FileCompiler(string baseDirectory)
   {
      this.baseDirectory = baseDirectory;
   }
   public void Compile(IEnumerable<string> files)
   {
      string filesToZipFileName = null;
      try
      {
         filesToZipFileName = GenerateZipTextDocumentFor(files);
         Compress(filesToZipFileName);
      }
      finally
      {
         if(string.IsNullOrEmpty(filesToZipFileName))
            return;
         if(File.Exists(filesToZipFileName);
            File.Delete(filesToZipFileName);
      }
   }

   private string GenerateZipTextDocumentFor(IEnumerable<string> files)
   {
       StringBuilder builder = new StringBuilder();
       foreach(string file in files)
       {
            builder.AppendLine(file);
       }
       string file = Path.Combine(baseDirectory, Guid.NewGuid().ToString() + ".txt");

       using(StreamWriter writer = new FileStreamWriter(file))
       {
          file.Write(builder.ToString());
       }
       return file;
   }

   private void Compress(string file)
   {
       ProcessStartInfo stater = new ProcessStartInfo(("C:\Program Files\WinZip\WinZip32.Exe");
       startInfo.Arguments = String.Format("-a -p -ex {0}.zip @{1}", Path.GetFileName(file), file);

       Process process = new Process(startInfo);
       process.Start();
       process.WaitForExit(); //not sure if name is correct
   }
}
for example

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
Let the page run through lunch and it just sat there, white screen with the status bar at the bottom stuck half way.

Thanks for the suggestions on refactoring the code to separate what could/is going wrong.

Also thanks for taking the time to translate the whole thing into C#. If your development day is anything like mine a spare 10 minutes is really at a premium.


* Sine scientia ars nihil est
* Respondeat superior
 
the worst kind of problem. something went wrong and nothing to show for it:) how about the event logs on the server?
The next step; log the different processes as they occur. If you are using a logging library, log messages at different points in the code. and see when it "stops" logging. if you're not using a logging library use this.
Code:
public class Log
{
   private const string logFile = "...\log.txt";
   public static Info(string message)
   {
      using(StreamWriter writer = CreateLogFile())
         writer.WriteLine(string.Format("{0:F} | {1}", DateTime.Now, message));
   }

   private StreamWriter CreateLogFile()
   {
       if(!File.Exists(logFile))
           return File.CreateText(logFile);
       return new FileStream(logFile);
   }
}
run the page for a minute and then close. view the log file and see where it stopped.

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
I have a logging class that I use, basically a ton of overloaded WriteToLog functions that will write out exceptions, log strings, or anything else that I need.

When I put those in place it seemed that my code hung up on the "If File.Exist(FilePathName)" check before I add files to the text file that I pass along to WinZip.

Interestingly (or Aggravatingly) enough, when I try to run the WinZip command line from a cmd prompt on the Web Server, WinZip will open but not create the archive. It just sort of hangs, like it can't find the files to add (these files are on a completely different server.)

I've already copied the files local to the web server, adjusted the text file that lists the files to archive, and everything works fine!

I don't know if I have a network problem, I can try to replace the IP path to the files with a UNC path or even a mapped drive.

* Sine scientia ars nihil est
* Respondeat superior
 
the web server needs to be configured to allow the permissions to extend to the file server. with Windows AD this is done through delegation.

i would not use the if(file.exists) to determine if you should append a line break. this is:
1. creating unecessary reads to the IO (a relatively slow process comparitvily speaking)
2. not seperating the concerns of the workflow.

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
the web server needs to be configured to allow the permissions to extend to the file server. with Windows AD this is done through delegation.

Huh? Windows Active Directory? I'm not sure how the networking boyz have things set up, but I'm pretty sure there is no windows active directory. I think out domain controller is a Win98 box.

* Sine scientia ars nihil est
* Respondeat superior
 
yes, Windows Active Directory. Win98 is an OS, not a server OS, so Win98 cannot be a DC. However you will need to work with the net admins to figure out how to pass the credientials from IIS to the remote file server.

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
I've so far figured out that I am dealing with some type of permissions issue. I found this article the other day: [URL unfurl="true"]http://codebetter.com/blogs/brendan.tompkins/archive/2004/05/13/13484.aspx[/url]

The article really helped a lot. I was actually able to see the errors produced by WinZip and there were two of them. One error dealt with WinZip's inability to find the files to archive (on another server) and this was the error:
Warning: no files were found for this pattern that match your selection criteria: \\FileServer\ASPFTP\280\A\ABC_INDEX_WITH_PER_UNIT_20080714_86215_39.PDF

Which I thought was odd since \\FileServer\AspFtp is a virtual directory in IIS. Then when I moved the files local to the web server and still tried to create the Zip Archive on the File server, I got a message from WinZip that \\FileServer\Z\AspFtp was full or it was read only or something to that effect.

Now as for Security/Permissions -- The exe that is called by the web page is run under the IUSR_WebServer account right? And that is a local account on the Web Server right? So how the 'hec do I give that user permissions to go across the network? Do I need to use impersonation when I run the exe? (I've already tried it with no luck, I keep on getting an exception that says the user is not found or the password is bad.)

Jason you suggested Delegation, can you elaborate a little for me? Or is there something else that I am missing?


* Sine scientia ars nihil est
* Respondeat superior
 
ok, 1st i know there are better descriptions out there then what I am about to write, so please be patient. I'm not a security expert by any means, but this is my understanding of how the security works.

by default IIS uses anonymous authentication. users are only allowed to access resources within the virtual directory. from the IIS pipeline nothing else exists. this is the pipeline your application is traversing.

the 1st step is to replicate your local credentials to IIS. This is done using Windows authentication and Impersonation. configure this in the web.config. You will also need to disable anynomous access in IIS and enable Windows Integrated Authentication for the virtual directory.

now you also want to access files on a remote server. As it stands now your credentials will not traverse the wire from IIS to the remote server. To continue passing your credentials you need delegations. which simply means. IIS is access the remote machine as if it was you.

here's a metaphor. Manager A needs a document from Manger B. Manager A sends his assitant to Manger B to get the document. the assistant cannot just request the document. She is acting as Manager A when requesting the report.
Not the greatest, but hopefully it's not more confusing:)

This is where AD manages the relationships between entities within the domain. AD keeps a list of all the computers on the network. open AD and select the IIS computer. open the properties and click the delegation tab. mark off the options you need and the authentication pass through from the client to the remote server.

now this still requires that the end user has permission to the files on the remote server. if they don't they still cannot access the report.

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
Just found out from the Network Admin that we have a WinNT domain. I asked him if we had any sort of active directory and was told no. I'm going to try to find info on delegation and WinNT to see if what you are describing above can be done or if I am S.O.L.

Thanks for your help, it wasn't that confusing at all. [smile]

* Sine scientia ars nihil est
* Respondeat superior
 
ok WINNT makes more sense then WIN98. I haven't worked directly with that technology. try forum55.

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top